summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp42
-rw-r--r--Android.bp38
-rw-r--r--FF_LEADS_OWNERS10
-rw-r--r--apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java4
-rw-r--r--apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java19
-rw-r--r--apct-tests/perftests/windowmanager/Android.bp2
-rw-r--r--apex/jobscheduler/service/aconfig/alarm.aconfig10
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java87
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java20
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java12
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java53
-rw-r--r--api/ApiDocs.bp1
-rw-r--r--boot/boot-image-profile-extra.txt23
-rw-r--r--cmds/idmap2/idmap2/CreateMultiple.cpp6
-rw-r--r--cmds/interrupter/Android.bp20
-rw-r--r--cmds/interrupter/interrupter.c53
-rw-r--r--cmds/interrupter/interrupter.h79
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java3
-rw-r--r--core/api/current.txt525
-rw-r--r--core/api/lint-baseline.txt11
-rw-r--r--core/api/module-lib-current.txt30
-rw-r--r--core/api/system-current.txt649
-rw-r--r--core/api/test-current.txt55
-rw-r--r--core/api/test-lint-baseline.txt8
-rw-r--r--core/java/Android.bp44
-rw-r--r--core/java/android/accounts/AccountManager.java20
-rw-r--r--core/java/android/adaptiveauth/OWNERS2
-rw-r--r--core/java/android/animation/AnimatorSet.java8
-rw-r--r--core/java/android/animation/ValueAnimator.java10
-rw-r--r--core/java/android/app/Activity.java29
-rw-r--r--core/java/android/app/ActivityManager.java99
-rw-r--r--core/java/android/app/ActivityManagerInternal.java27
-rw-r--r--core/java/android/app/ActivityThread.java12
-rw-r--r--core/java/android/app/AppOpsManager.java229
-rw-r--r--core/java/android/app/ApplicationPackageManager.java43
-rw-r--r--core/java/android/app/BroadcastStickyCache.java269
-rw-r--r--core/java/android/app/ContextImpl.java17
-rw-r--r--core/java/android/app/ForegroundServiceTypePolicy.java45
-rw-r--r--core/java/android/app/IActivityClientController.aidl4
-rw-r--r--core/java/android/app/IActivityManager.aidl5
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl4
-rw-r--r--core/java/android/app/INotificationManager.aidl4
-rw-r--r--core/java/android/app/ITaskStackListener.aidl5
-rw-r--r--core/java/android/app/KeyguardManager.java96
-rw-r--r--core/java/android/app/LoadedApk.java5
-rw-r--r--core/java/android/app/LoaderManager.java89
-rw-r--r--core/java/android/app/Notification.java122
-rw-r--r--core/java/android/app/NotificationManager.java29
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java90
-rw-r--r--core/java/android/app/ResourcesManager.java127
-rw-r--r--core/java/android/app/SystemServiceRegistry.java55
-rw-r--r--core/java/android/app/TEST_MAPPING4
-rw-r--r--core/java/android/app/TaskInfo.java16
-rw-r--r--core/java/android/app/TaskStackListener.java4
-rw-r--r--core/java/android/app/ZenBypassingApp.java98
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java369
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl9
-rw-r--r--core/java/android/app/admin/flags/flags.aconfig20
-rw-r--r--core/java/android/app/background_install_control_manager.aconfig7
-rw-r--r--core/java/android/app/backup/BackupTransport.java33
-rw-r--r--core/java/android/app/jank/FrameOverrunHistogram.java2
-rw-r--r--core/java/android/app/jank/JankDataProcessor.java86
-rw-r--r--core/java/android/app/jank/JankTracker.java7
-rw-r--r--core/java/android/app/jank/StateTracker.java6
-rw-r--r--core/java/android/app/keyguard.aconfig10
-rw-r--r--core/java/android/app/notification.aconfig21
-rw-r--r--core/java/android/app/ondeviceintelligence/InferenceInfo.java47
-rw-r--r--core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java7
-rw-r--r--core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig7
-rw-r--r--core/java/android/app/performance.aconfig7
-rw-r--r--core/java/android/app/supervision/SupervisionManagerInternal.java (renamed from services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java)11
-rw-r--r--core/java/android/app/trust/ITrustManager.aidl5
-rw-r--r--core/java/android/app/trust/TrustManager.java31
-rw-r--r--core/java/android/app/wearable/WearableSensingManager.java40
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java97
-rw-r--r--core/java/android/appwidget/flags.aconfig22
-rw-r--r--core/java/android/companion/virtual/IVirtualDevice.aidl5
-rw-r--r--core/java/android/companion/virtual/flags.aconfig11
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig8
-rw-r--r--core/java/android/content/BroadcastReceiver.java2
-rw-r--r--core/java/android/content/Context.java30
-rw-r--r--core/java/android/content/ContextWrapper.java1
-rw-r--r--core/java/android/content/Intent.java17
-rw-r--r--core/java/android/content/om/OverlayManager.java5
-rw-r--r--core/java/android/content/om/OverlayManagerTransaction.java15
-rw-r--r--core/java/android/content/pm/ActivityInfo.java17
-rw-r--r--core/java/android/content/pm/IPackageInstaller.aidl6
-rw-r--r--core/java/android/content/pm/PackageInstaller.java162
-rw-r--r--core/java/android/content/pm/PackageManager.java103
-rw-r--r--core/java/android/content/pm/ServiceInfo.java10
-rw-r--r--core/java/android/content/pm/SharedLibraryInfo.java43
-rw-r--r--core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl19
-rw-r--r--core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java100
-rw-r--r--core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java83
-rw-r--r--core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl41
-rw-r--r--core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl37
-rw-r--r--core/java/android/content/pm/flags.aconfig20
-rw-r--r--core/java/android/content/pm/multiuser.aconfig11
-rw-r--r--core/java/android/content/pm/parsing/ApkLite.java21
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java17
-rw-r--r--core/java/android/content/pm/parsing/PackageLite.java17
-rw-r--r--core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl32
-rw-r--r--core/java/android/content/pm/verify/pkg/VerificationSession.java311
-rw-r--r--core/java/android/content/pm/verify/pkg/VerificationStatus.java166
-rw-r--r--core/java/android/content/pm/verify/pkg/VerifierService.java113
-rw-r--r--core/java/android/content/res/ApkAssets.java33
-rw-r--r--core/java/android/content/res/AssetManager.java32
-rw-r--r--core/java/android/content/res/ResourcesImpl.java22
-rw-r--r--core/java/android/content/res/flags.aconfig9
-rw-r--r--core/java/android/content/res/loader/ResourcesProvider.java2
-rw-r--r--core/java/android/credentials/flags.aconfig10
-rw-r--r--core/java/android/hardware/DisplayLuts.java288
-rw-r--r--core/java/android/hardware/LutProperties.java34
-rw-r--r--core/java/android/hardware/OverlayProperties.java7
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java62
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java55
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java30
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java156
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java32
-rw-r--r--core/java/android/hardware/camera2/CameraSharedCaptureSession.java180
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java14
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java173
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java14
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionUtils.java37
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java26
-rw-r--r--core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java16
-rw-r--r--core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java242
-rw-r--r--core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java12
-rw-r--r--core/java/android/hardware/camera2/params/OutputConfiguration.java74
-rw-r--r--core/java/android/hardware/camera2/params/SessionConfiguration.java14
-rw-r--r--core/java/android/hardware/camera2/params/SharedSessionConfiguration.java312
-rw-r--r--core/java/android/hardware/contexthub/HubDiscoveryInfo.java73
-rw-r--r--core/java/android/hardware/contexthub/HubEndpoint.java559
-rw-r--r--core/java/android/hardware/contexthub/HubEndpointInfo.aidl (renamed from core/java/android/content/pm/verify/pkg/VerificationStatus.aidl)4
-rw-r--r--core/java/android/hardware/contexthub/HubEndpointInfo.java330
-rw-r--r--core/java/android/hardware/contexthub/HubEndpointSession.java170
-rw-r--r--core/java/android/hardware/contexthub/HubEndpointSessionResult.java79
-rw-r--r--core/java/android/hardware/contexthub/HubMessage.aidl22
-rw-r--r--core/java/android/hardware/contexthub/HubMessage.java289
-rw-r--r--core/java/android/hardware/contexthub/HubServiceInfo.aidl22
-rw-r--r--core/java/android/hardware/contexthub/HubServiceInfo.java230
-rw-r--r--core/java/android/hardware/contexthub/IContextHubEndpoint.aidl90
-rw-r--r--core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl61
-rw-r--r--core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java82
-rw-r--r--core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java45
-rw-r--r--core/java/android/hardware/contexthub/OWNERS2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java77
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java54
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java29
-rw-r--r--core/java/android/hardware/display/DisplayTopology.java147
-rw-r--r--core/java/android/hardware/flags/flags.aconfig (renamed from core/java/android/hardware/flags/overlayproperties_flags.aconfig)9
-rw-r--r--core/java/android/hardware/input/AidlInputGestureData.aidl3
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl2
-rw-r--r--core/java/android/hardware/input/InputManager.java17
-rw-r--r--core/java/android/hardware/input/InputSettings.java11
-rw-r--r--core/java/android/hardware/input/KeyGestureEvent.java29
-rw-r--r--core/java/android/hardware/input/KeyGlyphMap.java8
-rw-r--r--core/java/android/hardware/input/input_framework.aconfig24
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java140
-rw-r--r--core/java/android/hardware/location/ContextHubTransaction.java75
-rw-r--r--core/java/android/hardware/location/IContextHubService.aidl25
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java17
-rw-r--r--core/java/android/inputmethodservice/IInputMethodSessionWrapper.java43
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java96
-rw-r--r--core/java/android/inputmethodservice/NavigationBarController.java28
-rw-r--r--core/java/android/net/ConnectivityFrameworkInitializerBaklava.java (renamed from core/java/android/net/vcn/VcnFrameworkInitializer.java)18
-rw-r--r--core/java/android/net/vcn/VcnGatewayConnectionConfig.java19
-rw-r--r--core/java/android/net/vcn/VcnTransportInfo.java100
-rw-r--r--core/java/android/net/vcn/flags.aconfig12
-rw-r--r--core/java/android/os/BinderProxy.java34
-rw-r--r--core/java/android/os/Build.java22
-rw-r--r--core/java/android/os/Bundle.java13
-rw-r--r--core/java/android/os/CombinedMessageQueue/MessageQueue.java41
-rw-r--r--core/java/android/os/CpuHeadroomParams.java91
-rw-r--r--core/java/android/os/CpuHeadroomParamsInternal.aidl31
-rw-r--r--core/java/android/os/GpuHeadroomParams.java91
-rw-r--r--core/java/android/os/GpuHeadroomParamsInternal.aidl28
-rw-r--r--core/java/android/os/IBinder.java39
-rw-r--r--core/java/android/os/IHintManager.aidl16
-rw-r--r--core/java/android/os/OWNERS8
-rw-r--r--core/java/android/os/Parcel.java1
-rw-r--r--core/java/android/os/PerformanceHintManager.java5
-rw-r--r--core/java/android/os/PowerManager.java10
-rw-r--r--core/java/android/os/PowerManagerInternal.java12
-rw-r--r--core/java/android/os/RemoteCallbackList.java48
-rw-r--r--core/java/android/os/SessionCreationConfig.aidl39
-rw-r--r--core/java/android/os/UserManager.java29
-rw-r--r--core/java/android/os/VibrationEffect.java383
-rw-r--r--core/java/android/os/Vibrator.java84
-rw-r--r--core/java/android/os/VibratorInfo.java2
-rw-r--r--core/java/android/os/flags.aconfig53
-rw-r--r--core/java/android/os/health/SystemHealthManager.java111
-rw-r--r--core/java/android/os/vibrator/BasicPwleSegment.java222
-rw-r--r--core/java/android/os/vibrator/PrimitiveSegment.java52
-rw-r--r--core/java/android/os/vibrator/PwlePoint.java8
-rw-r--r--core/java/android/os/vibrator/PwleSegment.java8
-rw-r--r--core/java/android/os/vibrator/VibrationEffectSegment.java8
-rw-r--r--core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java197
-rw-r--r--core/java/android/permission/flags.aconfig47
-rw-r--r--core/java/android/provider/ContactsContract.java2
-rw-r--r--core/java/android/provider/Settings.java110
-rw-r--r--core/java/android/security/advancedprotection/AdvancedProtectionManager.java184
-rw-r--r--core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl4
-rw-r--r--core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java237
-rw-r--r--core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl21
-rw-r--r--core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java82
-rw-r--r--core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl21
-rw-r--r--core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java82
-rw-r--r--core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl32
-rw-r--r--core/java/android/security/authenticationpolicy/OWNERS1
-rw-r--r--core/java/android/security/flags.aconfig8
-rw-r--r--core/java/android/security/forensic/ForensicEvent.java92
-rw-r--r--core/java/android/security/forensic/IForensicService.aidl32
-rw-r--r--core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl (renamed from core/java/android/security/forensic/IBackupTransport.aidl)23
-rw-r--r--core/java/android/security/intrusiondetection/IIntrusionDetectionService.aidl35
-rw-r--r--core/java/android/security/intrusiondetection/IIntrusionDetectionServiceCommandCallback.aidl (renamed from core/java/android/security/forensic/IForensicServiceCommandCallback.aidl)8
-rw-r--r--core/java/android/security/intrusiondetection/IIntrusionDetectionServiceStateCallback.aidl (renamed from core/java/android/security/forensic/IForensicServiceStateCallback.aidl)9
-rw-r--r--core/java/android/security/intrusiondetection/IntrusionDetectionEvent.aidl (renamed from packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockAnimation.kt)7
-rw-r--r--core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java218
-rw-r--r--core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java145
-rw-r--r--core/java/android/security/intrusiondetection/IntrusionDetectionManager.java278
-rw-r--r--core/java/android/security/intrusiondetection/OWNERS (renamed from core/java/android/security/forensic/OWNERS)0
-rw-r--r--core/java/android/security/responsible_apis_flags.aconfig22
-rw-r--r--core/java/android/service/autofill/FillEventHistory.java51
-rw-r--r--core/java/android/service/autofill/FillRequest.java12
-rw-r--r--core/java/android/service/carrier/CarrierMessagingService.java450
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl6
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java10
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java29
-rw-r--r--core/java/android/service/notification/SystemZenRules.java11
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java2
-rw-r--r--core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl2
-rw-r--r--core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl2
-rw-r--r--core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java18
-rw-r--r--core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java32
-rw-r--r--core/java/android/service/quickaccesswallet/QuickAccessWalletService.java42
-rw-r--r--core/java/android/service/quickaccesswallet/flags.aconfig9
-rw-r--r--core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java22
-rw-r--r--core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java147
-rw-r--r--core/java/android/service/settings/preferences/SettingsPreferenceValue.java24
-rw-r--r--core/java/android/service/wearable/WearableSensingService.java17
-rw-r--r--core/java/android/telephony/PhoneStateListener.java9
-rw-r--r--core/java/android/telephony/SubscriptionPlan.java71
-rw-r--r--core/java/android/telephony/TelephonyCallback.java83
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java43
-rw-r--r--core/java/android/text/ClientFlags.java29
-rw-r--r--core/java/android/text/Html.java2
-rw-r--r--core/java/android/text/TextFlags.java81
-rw-r--r--core/java/android/text/TextUtils.java9
-rw-r--r--core/java/android/text/style/NoWritingToolsSpan.java87
-rw-r--r--core/java/android/text/style/TtsSpan.java10
-rw-r--r--core/java/android/util/ArrayMap.java1
-rw-r--r--core/java/android/util/ArraySet.java1
-rw-r--r--core/java/android/view/AttachedSurfaceControl.java24
-rw-r--r--core/java/android/view/Choreographer.java157
-rw-r--r--core/java/android/view/Display.java48
-rw-r--r--core/java/android/view/DisplayEventReceiver.java7
-rw-r--r--core/java/android/view/DisplayInfo.java31
-rw-r--r--core/java/android/view/FrameMetrics.java19
-rw-r--r--core/java/android/view/HapticScrollFeedbackProvider.java28
-rw-r--r--core/java/android/view/IWindowSession.aidl10
-rw-r--r--core/java/android/view/InputWindowHandle.java9
-rw-r--r--core/java/android/view/ScaleGestureDetector.java10
-rw-r--r--core/java/android/view/SurfaceControl.java330
-rw-r--r--core/java/android/view/SurfaceControlActivePicture.java58
-rw-r--r--core/java/android/view/SurfaceControlActivePictureListener.java69
-rw-r--r--core/java/android/view/SurfaceView.java7
-rw-r--r--core/java/android/view/View.java26
-rw-r--r--core/java/android/view/ViewRootImpl.java72
-rw-r--r--core/java/android/view/ViewStructure.java16
-rw-r--r--core/java/android/view/Window.java6
-rw-r--r--core/java/android/view/WindowManager.java14
-rw-r--r--core/java/android/view/WindowlessWindowManager.java5
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java16
-rw-r--r--core/java/android/view/accessibility/flags/accessibility_flags.aconfig10
-rw-r--r--core/java/android/view/autofill/AutofillId.java43
-rw-r--r--core/java/android/view/autofill/AutofillManager.java17
-rw-r--r--core/java/android/view/flags/scroll_feedback_flags.aconfig7
-rw-r--r--core/java/android/view/flags/view_flags.aconfig8
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java59
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java9
-rw-r--r--core/java/android/view/inputmethod/InputMethodSession.java18
-rw-r--r--core/java/android/view/inputmethod/flags.aconfig28
-rw-r--r--core/java/android/widget/Button.java46
-rw-r--r--core/java/android/widget/RemoteViews.java82
-rw-r--r--core/java/android/widget/TextView.java581
-rw-r--r--core/java/android/widget/flags/flags.aconfig10
-rw-r--r--core/java/android/window/BackProgressAnimator.java3
-rw-r--r--core/java/android/window/IBackAnimationHandoffHandler.aidl40
-rw-r--r--core/java/android/window/IOnBackInvokedCallback.aidl6
-rw-r--r--core/java/android/window/ImeOnBackInvokedDispatcher.java5
-rw-r--r--core/java/android/window/TransitionInfo.java10
-rw-r--r--core/java/android/window/WindowContainerTransaction.java4
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java5
-rw-r--r--core/java/android/window/WindowTokenClient.java8
-rw-r--r--core/java/android/window/WindowTokenClientController.java63
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig54
-rw-r--r--core/java/android/window/flags/window_surfaces.aconfig17
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig26
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl2
-rw-r--r--core/java/com/android/internal/app/procstats/AssociationState.java5
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessState.java4
-rw-r--r--core/java/com/android/internal/backup/IBackupTransport.aidl11
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfig.java3
-rw-r--r--core/java/com/android/internal/content/om/OverlayManagerImpl.java20
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java14
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java34
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java12
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java126
-rw-r--r--core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl21
-rw-r--r--core/java/com/android/internal/protolog/LegacyProtoLogImpl.java8
-rw-r--r--core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java112
-rw-r--r--core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java33
-rw-r--r--core/java/com/android/internal/protolog/ProtoLog.java80
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java28
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java35
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogDataSource.java103
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogImpl.java54
-rw-r--r--core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java10
-rw-r--r--core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java4
-rw-r--r--core/java/com/android/internal/telephony/IPhoneStateListener.aidl4
-rw-r--r--core/java/com/android/internal/telephony/ITelephonyRegistry.aidl5
-rw-r--r--core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java55
-rw-r--r--core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java15
-rw-r--r--core/java/com/android/internal/vibrator/persistence/XmlConstants.java53
-rw-r--r--core/java/com/android/internal/widget/NotificationProgressBar.java149
-rw-r--r--core/java/com/android/internal/widget/NotificationProgressDrawable.java259
-rw-r--r--core/java/com/android/internal/widget/NotificationRowIconView.java84
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java87
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/Operation.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/Operations.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/PaintContext.java16
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/Platform.java17
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java183
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java48
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java75
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java32
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java42
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java7
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java17
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java51
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/Header.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java22
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java18
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java21
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java52
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java106
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java7
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java44
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java7
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java7
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java36
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java7
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java32
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java71
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java32
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java22
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java27
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java120
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java21
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java227
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java105
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java61
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java16
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java20
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java73
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java20
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java16
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicSpline.java203
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/SpringStopEngine.java188
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java1
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java116
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java18
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java88
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java17
-rw-r--r--core/java/com/android/server/pm/pkg/AndroidPackage.java22
-rw-r--r--core/jni/Android.bp3
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_content_res_ApkAssets.cpp4
-rw-r--r--core/jni/android_hardware_OverlayProperties.cpp2
-rw-r--r--core/jni/android_media_AudioRecord.cpp26
-rw-r--r--core/jni/android_media_AudioSystem.cpp12
-rw-r--r--core/jni/android_media_AudioTrack.cpp22
-rw-r--r--core/jni/android_media_DeviceCallback.cpp15
-rw-r--r--core/jni/android_media_DeviceCallback.h3
-rw-r--r--core/jni/android_os_PerformanceHintManager.cpp9
-rw-r--r--core/jni/android_text_Hyphenator.cpp27
-rw-r--r--core/jni/android_util_Process.cpp3
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp12
-rw-r--r--core/jni/android_view_SurfaceControl.cpp184
-rw-r--r--core/jni/android_view_SurfaceControlActivePictureListener.cpp191
-rw-r--r--core/jni/com_android_internal_content_FileSystemUtils.cpp19
-rw-r--r--core/jni/com_android_internal_content_FileSystemUtils.h10
-rw-r--r--core/jni/platform/host/HostRuntime.cpp2
-rw-r--r--core/proto/android/providers/settings/secure.proto8
-rw-r--r--core/proto/android/providers/settings/system.proto1
-rw-r--r--core/res/Android.bp3
-rw-r--r--core/res/AndroidManifest.xml229
-rw-r--r--core/res/res/drawable-watch-v36/btn_background_material_filled.xml2
-rw-r--r--core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml2
-rw-r--r--core/res/res/drawable/notification_progress.xml6
-rw-r--r--core/res/res/layout-sw600dp/preference_list_content_single.xml1
-rw-r--r--core/res/res/layout/list_content_simple.xml1
-rw-r--r--core/res/res/layout/notification_2025_reply_container.xml79
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_base.xml195
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_base.xml86
-rw-r--r--core/res/res/layout/notification_2025_template_header.xml111
-rw-r--r--core/res/res/layout/notification_2025_template_heads_up_base.xml66
-rw-r--r--core/res/res/layout/notification_2025_template_text.xml28
-rw-r--r--core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml4
-rw-r--r--core/res/res/layout/preference_list_content.xml1
-rw-r--r--core/res/res/layout/preference_list_content_material.xml1
-rw-r--r--core/res/res/layout/preference_list_content_single.xml1
-rw-r--r--core/res/res/layout/preference_list_fragment.xml1
-rw-r--r--core/res/res/layout/preference_list_fragment_material.xml1
-rw-r--r--core/res/res/values-af/strings.xml78
-rw-r--r--core/res/res/values-am/strings.xml78
-rw-r--r--core/res/res/values-ar/strings.xml6
-rw-r--r--core/res/res/values-as/strings.xml6
-rw-r--r--core/res/res/values-az/strings.xml78
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml6
-rw-r--r--core/res/res/values-be/strings.xml6
-rw-r--r--core/res/res/values-bg/strings.xml78
-rw-r--r--core/res/res/values-bn/strings.xml6
-rw-r--r--core/res/res/values-bs/strings.xml6
-rw-r--r--core/res/res/values-ca/strings.xml78
-rw-r--r--core/res/res/values-cs/strings.xml78
-rw-r--r--core/res/res/values-da/strings.xml78
-rw-r--r--core/res/res/values-de/strings.xml78
-rw-r--r--core/res/res/values-el/strings.xml78
-rw-r--r--core/res/res/values-en-rAU/strings.xml6
-rw-r--r--core/res/res/values-en-rGB/strings.xml6
-rw-r--r--core/res/res/values-en-rIN/strings.xml6
-rw-r--r--core/res/res/values-es-rUS/strings.xml6
-rw-r--r--core/res/res/values-es/strings.xml80
-rw-r--r--core/res/res/values-et/strings.xml78
-rw-r--r--core/res/res/values-eu/strings.xml78
-rw-r--r--core/res/res/values-fa/strings.xml80
-rw-r--r--core/res/res/values-fi/strings.xml78
-rw-r--r--core/res/res/values-fr-rCA/strings.xml6
-rw-r--r--core/res/res/values-fr/strings.xml78
-rw-r--r--core/res/res/values-gl/strings.xml78
-rw-r--r--core/res/res/values-gu/strings.xml78
-rw-r--r--core/res/res/values-hi/strings.xml8
-rw-r--r--core/res/res/values-hr/strings.xml6
-rw-r--r--core/res/res/values-hu/strings.xml78
-rw-r--r--core/res/res/values-hy/strings.xml78
-rw-r--r--core/res/res/values-in/strings.xml82
-rw-r--r--core/res/res/values-is/strings.xml6
-rw-r--r--core/res/res/values-it/strings.xml78
-rw-r--r--core/res/res/values-iw/strings.xml8
-rw-r--r--core/res/res/values-ja/strings.xml6
-rw-r--r--core/res/res/values-ka/strings.xml6
-rw-r--r--core/res/res/values-kk/strings.xml80
-rw-r--r--core/res/res/values-km/strings.xml6
-rw-r--r--core/res/res/values-kn/strings.xml18
-rw-r--r--core/res/res/values-ko/strings.xml8
-rw-r--r--core/res/res/values-ky/strings.xml80
-rw-r--r--core/res/res/values-lo/strings.xml6
-rw-r--r--core/res/res/values-lt/strings.xml6
-rw-r--r--core/res/res/values-lv/strings.xml78
-rw-r--r--core/res/res/values-mk/strings.xml82
-rw-r--r--core/res/res/values-ml/strings.xml6
-rw-r--r--core/res/res/values-mn/strings.xml80
-rw-r--r--core/res/res/values-mr/strings.xml6
-rw-r--r--core/res/res/values-ms/strings.xml6
-rw-r--r--core/res/res/values-my/strings.xml8
-rw-r--r--core/res/res/values-nb/strings.xml78
-rw-r--r--core/res/res/values-ne/strings.xml14
-rw-r--r--core/res/res/values-night/colors_dynamic.xml103
-rw-r--r--core/res/res/values-nl/strings.xml6
-rw-r--r--core/res/res/values-or/strings.xml80
-rw-r--r--core/res/res/values-pa/strings.xml6
-rw-r--r--core/res/res/values-pl/strings.xml6
-rw-r--r--core/res/res/values-pt-rBR/strings.xml8
-rw-r--r--core/res/res/values-pt-rPT/strings.xml6
-rw-r--r--core/res/res/values-pt/strings.xml8
-rw-r--r--core/res/res/values-ro/strings.xml14
-rw-r--r--core/res/res/values-ru/strings.xml14
-rw-r--r--core/res/res/values-si/strings.xml80
-rw-r--r--core/res/res/values-sk/strings.xml78
-rw-r--r--core/res/res/values-sl/strings.xml6
-rw-r--r--core/res/res/values-sq/strings.xml80
-rw-r--r--core/res/res/values-sr/strings.xml6
-rw-r--r--core/res/res/values-sv/strings.xml6
-rw-r--r--core/res/res/values-sw/strings.xml78
-rw-r--r--core/res/res/values-ta/strings.xml78
-rw-r--r--core/res/res/values-te/strings.xml86
-rw-r--r--core/res/res/values-th/strings.xml6
-rw-r--r--core/res/res/values-tl/strings.xml6
-rw-r--r--core/res/res/values-tr/strings.xml78
-rw-r--r--core/res/res/values-uk/strings.xml78
-rw-r--r--core/res/res/values-ur/strings.xml8
-rw-r--r--core/res/res/values-uz/strings.xml6
-rw-r--r--core/res/res/values-vi/strings.xml78
-rw-r--r--core/res/res/values-watch-v36/config.xml3
-rw-r--r--core/res/res/values-watch-v36/styles_material.xml4
-rw-r--r--core/res/res/values-watch/themes_device_defaults.xml6
-rw-r--r--core/res/res/values-zh-rCN/strings.xml8
-rw-r--r--core/res/res/values-zh-rHK/strings.xml78
-rw-r--r--core/res/res/values-zh-rTW/strings.xml78
-rw-r--r--core/res/res/values-zu/strings.xml78
-rw-r--r--core/res/res/values/attrs.xml322
-rw-r--r--core/res/res/values/attrs_manifest.xml15
-rw-r--r--core/res/res/values/colors.xml472
-rw-r--r--core/res/res/values/colors_dynamic.xml103
-rw-r--r--core/res/res/values/config.xml38
-rw-r--r--core/res/res/values/config_display.xml2
-rw-r--r--core/res/res/values/config_telephony.xml13
-rw-r--r--core/res/res/values/dimens.xml38
-rw-r--r--core/res/res/values/ids.xml3
-rw-r--r--core/res/res/values/public-staging.xml33
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/styles_device_defaults.xml1
-rw-r--r--core/res/res/values/symbols.xml265
-rw-r--r--core/res/res/values/themes_device_defaults.xml5868
-rw-r--r--core/res/res/xml/bookmarks.xml26
-rw-r--r--core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java21
-rw-r--r--core/tests/coretests/Android.bp1
-rw-r--r--core/tests/coretests/AndroidTest.xml2
-rw-r--r--core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java3
-rw-r--r--core/tests/coretests/src/android/app/NotificationTest.java17
-rw-r--r--core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java39
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityTestsBase.java9
-rw-r--r--core/tests/coretests/src/android/app/activity/LaunchpadActivity.java1
-rw-r--r--core/tests/coretests/src/android/appwidget/AppWidgetEventsTest.kt51
-rw-r--r--core/tests/coretests/src/android/appwidget/OWNERS1
-rw-r--r--core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java69
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java14
-rw-r--r--core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java194
-rw-r--r--core/tests/coretests/src/android/content/pm/verify/VerificationStatusTest.java72
-rw-r--r--core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java96
-rw-r--r--core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java89
-rw-r--r--core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt206
-rw-r--r--core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java4
-rw-r--r--core/tests/coretests/src/android/os/OWNERS3
-rw-r--r--core/tests/coretests/src/android/view/HapticScrollFeedbackProviderTest.java30
-rw-r--r--core/tests/coretests/src/android/view/RotaryScrollHapticsTest.java43
-rw-r--r--core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java16
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java3
-rw-r--r--core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java15
-rw-r--r--core/tests/systemproperties/src/android/os/SystemPropertiesTest.java7
-rw-r--r--core/tests/vibrator/src/android/os/VibrationEffectTest.java324
-rw-r--r--core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java82
-rw-r--r--core/xsd/permission.xsd16
-rw-r--r--core/xsd/schema/current.txt21
-rw-r--r--core/xsd/vibrator/vibration/schema/current.txt8
-rw-r--r--core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd9
-rw-r--r--core/xsd/vibrator/vibration/vibration.xsd9
-rw-r--r--data/etc/privapp-permissions-platform.xml14
-rw-r--r--data/sounds/Android.bp304
-rw-r--r--errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java2
-rw-r--r--graphics/java/android/graphics/BlendMode.java6
-rw-r--r--graphics/java/android/graphics/ComposeShader.java5
-rw-r--r--graphics/java/android/graphics/Paint.java36
-rw-r--r--graphics/java/android/graphics/PorterDuffXfermode.java3
-rw-r--r--graphics/java/android/graphics/RuntimeColorFilter.java23
-rw-r--r--graphics/java/android/graphics/RuntimeShader.java53
-rw-r--r--graphics/java/android/graphics/RuntimeXfermode.java331
-rw-r--r--graphics/java/android/graphics/Xfermode.java9
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java65
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java1
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java1
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java12
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java14
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java34
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt30
-rw-r--r--libs/WindowManager/Shell/Android.bp46
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt97
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt2
-rw-r--r--libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml2
-rw-r--r--libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml11
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values/styles.xml1
-rw-r--r--libs/WindowManager/Shell/shared/Android.bp78
-rw-r--r--libs/WindowManager/Shell/shared/AndroidManifest.xml (renamed from packages/BackupRestoreConfirmation/res/values/styles.xml)15
-rw-r--r--libs/WindowManager/Shell/shared/res/values/config.xml (renamed from packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml)14
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java25
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java20
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java99
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java88
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java148
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java289
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt184
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt82
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt150
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt106
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java189
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt142
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt97
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt452
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt174
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformComponents.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java93
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java227
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt235
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java1012
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt185
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java99
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java86
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt89
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt7
-rw-r--r--libs/WindowManager/Shell/tests/OWNERS1
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt50
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt50
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt67
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt51
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt48
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt42
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenUnlimitedApps.kt47
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt26
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MinimizeAutoPipAppWindowTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenUnlimitedAppsTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt72
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt3
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt74
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAutoPipAppWindow.kt72
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt28
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt73
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt2
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp38
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml85
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml97
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto71
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt76
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt83
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt86
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt86
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt76
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt83
-rw-r--r--libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt86
-rw-r--r--libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp1
-rw-r--r--libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java27
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt (renamed from core/java/android/content/pm/verify/pkg/IVerifierService.aidl)31
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java53
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java86
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt160
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt294
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt55
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt75
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt17
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt316
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt31
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt396
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt106
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt157
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt29
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java9
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java58
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java65
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java270
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt24
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java61
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java172
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt387
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java28
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java18
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java22
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt182
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt180
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt357
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt329
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java48
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt73
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt16
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/DeviceInfo.h1
-rw-r--r--libs/hwui/RenderNode.cpp2
-rw-r--r--libs/hwui/RenderProperties.h3
-rw-r--r--libs/hwui/SkiaCanvas.cpp19
-rw-r--r--libs/hwui/apex/jni_runtime.cpp2
-rw-r--r--libs/hwui/effects/GainmapRenderer.cpp15
-rw-r--r--libs/hwui/jni/ColorFilter.cpp18
-rw-r--r--libs/hwui/jni/Paint.cpp19
-rw-r--r--libs/hwui/jni/RuntimeEffectUtils.cpp2
-rw-r--r--libs/hwui/jni/RuntimeXfermode.cpp133
-rw-r--r--libs/hwui/jni/Shader.cpp81
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp5
-rw-r--r--libs/hwui/tests/unit/RenderPropertiesTests.cpp8
-rw-r--r--libs/input/SpriteIcon.cpp2
-rw-r--r--media/java/android/media/AudioDeviceInfo.java14
-rw-r--r--media/java/android/media/AudioDevicePort.java43
-rw-r--r--media/java/android/media/AudioPlaybackConfiguration.java98
-rw-r--r--media/java/android/media/AudioRecord.java42
-rw-r--r--media/java/android/media/AudioRouting.java23
-rw-r--r--media/java/android/media/AudioTrack.java50
-rw-r--r--media/java/android/media/HwAudioSource.java9
-rw-r--r--media/java/android/media/IAudioService.aidl5
-rw-r--r--media/java/android/media/ImageWriter.java6
-rw-r--r--media/java/android/media/MediaCas.java5
-rw-r--r--media/java/android/media/MediaCodec.java166
-rw-r--r--media/java/android/media/MediaCodecInfo.java140
-rw-r--r--media/java/android/media/MediaFormat.java34
-rw-r--r--media/java/android/media/MediaPlayer.java49
-rw-r--r--media/java/android/media/MediaRecorder.java44
-rw-r--r--media/java/android/media/PlayerBase.java36
-rw-r--r--media/java/android/media/SoundPool.java2
-rw-r--r--media/java/android/media/Spatializer.java26
-rw-r--r--media/java/android/media/flags/media_better_together.aconfig153
-rw-r--r--media/java/android/media/flags/projection.aconfig15
-rw-r--r--media/java/android/media/projection/IMediaProjection.aidl3
-rw-r--r--media/java/android/media/projection/IMediaProjectionManager.aidl17
-rw-r--r--media/java/android/media/projection/MediaProjection.java2
-rw-r--r--media/java/android/media/projection/MediaProjectionManager.java4
-rw-r--r--media/java/android/media/projection/StopReason.aidl36
-rw-r--r--media/java/android/media/quality/AmbientBacklightEvent.java25
-rw-r--r--media/java/android/media/quality/AmbientBacklightMetadata.java62
-rw-r--r--media/java/android/media/quality/AmbientBacklightSettings.java70
-rw-r--r--media/java/android/media/quality/IMediaQualityManager.aidl7
-rw-r--r--media/java/android/media/quality/ISoundProfileCallback.aidl9
-rw-r--r--media/java/android/media/quality/MediaQualityContract.java29
-rw-r--r--media/java/android/media/quality/MediaQualityManager.java249
-rw-r--r--media/java/android/media/quality/ParamCapability.java1
-rw-r--r--media/java/android/media/quality/PictureProfile.java43
-rw-r--r--media/java/android/media/quality/PictureProfileHandle.java38
-rw-r--r--media/java/android/media/quality/SoundProfile.java234
-rw-r--r--media/java/android/media/tv/TvInputServiceExtensionManager.java214
-rw-r--r--media/java/android/media/tv/ad/TvAdView.java32
-rw-r--r--media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl26
-rw-r--r--media/java/android/media/tv/extension/cam/ICamAppInfoListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/cam/ICamAppInfoService.aidl32
-rw-r--r--media/java/android/media/tv/extension/cam/ICamDrmInfoListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/cam/ICamHostControlAskReleaseReplyCallback.aidl24
-rw-r--r--media/java/android/media/tv/extension/cam/ICamHostControlInfoListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/cam/ICamHostControlService.aidl35
-rw-r--r--media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlag.aidl32
-rw-r--r--media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlagListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/cam/ICamInfoListener.aidl28
-rw-r--r--media/java/android/media/tv/extension/cam/ICamMonitoringService.aidl38
-rw-r--r--media/java/android/media/tv/extension/cam/ICamPinCapabilityListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/cam/ICamPinService.aidl35
-rw-r--r--media/java/android/media/tv/extension/cam/ICamPinStatusListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/cam/ICamProfileInterface.aidl29
-rw-r--r--media/java/android/media/tv/extension/cam/IContentControlService.aidl32
-rw-r--r--media/java/android/media/tv/extension/cam/IEnterMenuErrorCallback.aidl24
-rw-r--r--media/java/android/media/tv/extension/cam/IMmiInterface.aidl32
-rw-r--r--media/java/android/media/tv/extension/cam/IMmiSession.aidl31
-rw-r--r--media/java/android/media/tv/extension/cam/IMmiStatusCallback.aidl28
-rw-r--r--media/java/android/media/tv/extension/clienttoken/IClientToken.aidl24
-rw-r--r--media/java/android/media/tv/extension/event/IEventDownload.aidl29
-rw-r--r--media/java/android/media/tv/extension/event/IEventDownloadListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/event/IEventDownloadSession.aidl38
-rw-r--r--media/java/android/media/tv/extension/event/IEventMonitor.aidl43
-rw-r--r--media/java/android/media/tv/extension/event/IEventMonitorListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl41
-rw-r--r--media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl24
-rw-r--r--media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl24
-rw-r--r--media/java/android/media/tv/extension/pvr/IRecordedContents.aidl36
-rw-r--r--media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl27
-rw-r--r--media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl31
-rw-r--r--media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl32
-rw-r--r--media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/rating/IRatingInterface.aidl (renamed from packages/SystemUI/src/com/android/systemui/haptics/slider/SliderQuantization.kt)19
-rw-r--r--media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl31
-rw-r--r--media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl36
-rw-r--r--media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl25
-rw-r--r--media/java/android/media/tv/extension/scan/ILcnConflict.aidl35
-rw-r--r--media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl35
-rw-r--r--media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/scan/IOperatorDetection.aidl35
-rw-r--r--media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl27
-rw-r--r--media/java/android/media/tv/extension/scan/IRegionChannelList.aidl30
-rw-r--r--media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/scan/IScanInterface.aidl30
-rw-r--r--media/java/android/media/tv/extension/scan/IScanListener.aidl33
-rw-r--r--media/java/android/media/tv/extension/scan/IScanSatSearch.aidl26
-rw-r--r--media/java/android/media/tv/extension/scan/IScanSession.aidl75
-rw-r--r--media/java/android/media/tv/extension/scan/ITargetRegion.aidl36
-rw-r--r--media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/scan/ITkgsInfo.aidl28
-rw-r--r--media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl32
-rw-r--r--media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl31
-rw-r--r--media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl29
-rw-r--r--media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl29
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceList.aidl30
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl81
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl30
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl25
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl32
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl29
-rw-r--r--media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl31
-rw-r--r--media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl26
-rw-r--r--media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl36
-rw-r--r--media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl25
-rw-r--r--media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl36
-rw-r--r--media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl28
-rw-r--r--media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl24
-rw-r--r--media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl30
-rw-r--r--media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl35
-rw-r--r--media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl41
-rw-r--r--media/java/android/media/tv/extension/time/IBroadcastTime.aidl30
-rw-r--r--media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl27
-rw-r--r--media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl26
-rw-r--r--media/java/android/media/tv/extension/tune/IMuxTune.aidl26
-rw-r--r--media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl33
-rw-r--r--media/java/android/media/tv/flags/media_tv.aconfig34
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppView.java32
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendStatus.java16
-rw-r--r--media/java/android/media/tv/tuner/frontend/StandardExtension.java (renamed from media/java/android/media/tv/tuner/frontend/StandardExt.java)24
-rw-r--r--media/jni/Android.bp1
-rw-r--r--media/jni/android_media_MediaCodec.cpp147
-rw-r--r--media/jni/android_media_MediaCodec.h2
-rw-r--r--media/jni/android_media_MediaPlayer.cpp22
-rw-r--r--media/jni/android_media_MediaRecorder.cpp29
-rw-r--r--media/jni/android_media_tv_Tuner.cpp6
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java19
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java12
-rw-r--r--media/tests/projection/src/android/media/projection/FakeIMediaProjection.java2
-rw-r--r--native/android/dynamic_instrumentation_manager.cpp14
-rw-r--r--native/android/include_platform/android/dynamic_instrumentation_manager.h15
-rw-r--r--native/android/libandroid.map.txt17
-rw-r--r--native/android/performance_hint.cpp461
-rw-r--r--native/android/tests/performance_hint/PerformanceHintNativeTest.cpp128
-rw-r--r--native/graphics/jni/Android.bp2
-rw-r--r--nfc/api/current.txt14
-rw-r--r--nfc/api/system-current.txt85
-rw-r--r--nfc/java/android/nfc/INfcAdapter.aidl11
-rw-r--r--nfc/java/android/nfc/INfcCardEmulation.aidl4
-rw-r--r--nfc/java/android/nfc/INfcEventListener.aidl5
-rw-r--r--nfc/java/android/nfc/INfcOemExtensionCallback.aidl5
-rw-r--r--nfc/java/android/nfc/IT4tNdefNfcee.aidl33
-rw-r--r--nfc/java/android/nfc/NfcAdapter.java60
-rw-r--r--nfc/java/android/nfc/NfcOemExtension.java255
-rw-r--r--nfc/java/android/nfc/NfcRoutingTableEntry.java47
-rw-r--r--nfc/java/android/nfc/OemLogItems.java14
-rw-r--r--nfc/java/android/nfc/RoutingTableAidEntry.java4
-rw-r--r--nfc/java/android/nfc/RoutingTableProtocolEntry.java2
-rw-r--r--nfc/java/android/nfc/RoutingTableSystemCodeEntry.java6
-rw-r--r--nfc/java/android/nfc/RoutingTableTechnologyEntry.java15
-rw-r--r--nfc/java/android/nfc/T4tNdefNfcee.java258
-rw-r--r--nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl (renamed from core/java/android/security/forensic/ForensicEvent.aidl)6
-rw-r--r--nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java293
-rw-r--r--nfc/java/android/nfc/cardemulation/ApduServiceInfo.java29
-rw-r--r--nfc/java/android/nfc/cardemulation/CardEmulation.java336
-rw-r--r--nfc/java/android/nfc/flags.aconfig16
-rw-r--r--packages/BackupRestoreConfirmation/Android.bp1
-rw-r--r--packages/BackupRestoreConfirmation/AndroidManifest.xml1
-rw-r--r--packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml9
-rw-r--r--packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml11
-rw-r--r--packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java34
-rw-r--r--packages/CarrierDefaultApp/res/values-ar/strings.xml2
-rw-r--r--packages/CarrierDefaultApp/res/values-ur/strings.xml2
-rw-r--r--packages/CrashRecovery/framework/Android.bp1
-rw-r--r--packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java228
-rw-r--r--packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java14
-rw-r--r--packages/NeuralNetworks/OWNERS5
-rw-r--r--packages/PackageInstaller/res/values-cs/strings.xml2
-rw-r--r--packages/PrintSpooler/AndroidManifest.xml1
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java19
-rw-r--r--packages/SettingsLib/Android.bp4
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-af/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-am/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-as/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-az/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-be/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-da/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-de/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-el/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-en-rCA/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-es/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-et/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-hy/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-in/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-is/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-it/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ja/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-km/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-kn/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-mr/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-my/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-or/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-pa/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-pt-rPT/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-si/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-sl/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ta/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-te/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-th/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-tl/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-ur/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-uz/strings.xml25
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml27
-rw-r--r--packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml27
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml2
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml2
-rw-r--r--packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesObservable.kt45
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt30
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceCoordinate.kt45
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt148
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterCodecs.kt126
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterFlags.kt31
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt241
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt12
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt40
-rw-r--r--packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt2
-rw-r--r--packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt35
-rw-r--r--packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt5
-rw-r--r--packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt7
-rw-r--r--packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt7
-rw-r--r--packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt3
-rw-r--r--packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt66
-rw-r--r--packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml2
-rw-r--r--packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt9
-rw-r--r--packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt27
-rw-r--r--packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt12
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml6
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-te/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml4
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml6
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt14
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt33
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt17
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt62
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt66
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt93
-rw-r--r--packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml6
-rw-r--r--packages/SettingsLib/aconfig/settingslib.aconfig7
-rw-r--r--packages/SettingsLib/res/drawable/ic_bt_le_audio_sharing.xml79
-rw-r--r--packages/SettingsLib/res/drawable/ic_tv_box_internal_speaker.xml25
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml16
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml16
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml12
-rw-r--r--packages/SettingsLib/res/values/strings.xml19
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java20
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java29
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java27
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java86
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt2
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java30
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java36
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java33
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeDescriptionsTest.java60
-rw-r--r--packages/SettingsProvider/res/xml/bookmarks.xml3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java11
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java44
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/OWNERS3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java12
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java36
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java47
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java8
-rw-r--r--packages/Shell/Android.bp2
-rw-r--r--packages/Shell/AndroidManifest.xml29
-rw-r--r--packages/Shell/OWNERS1
-rw-r--r--packages/Shell/aconfig/Android.bp13
-rw-r--r--packages/Shell/aconfig/wear.aconfig9
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java14
-rw-r--r--packages/SystemUI/Android.bp97
-rw-r--r--packages/SystemUI/TEST_MAPPING6
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig58
-rw-r--r--packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java11
-rw-r--r--packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java22
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt553
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt126
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt22
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt24
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt25
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt7
-rw-r--r--packages/SystemUI/common/Android.bp4
-rw-r--r--packages/SystemUI/common/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt (renamed from packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt)0
-rw-r--r--packages/SystemUI/common/src/com/android/systemui/coroutines/Tracing.kt (renamed from packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt)0
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt6
-rw-r--r--packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt23
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt31
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt9
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt43
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt3
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt18
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt3
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt19
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt1
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt31
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt3
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToBouncerTransition.kt23
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt33
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToShadeTransition.kt23
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt20
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt20
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt30
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt5
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt5
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt19
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt69
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt25
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt47
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt93
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt94
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt6
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt23
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt36
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt10
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt10
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt72
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt95
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt27
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt12
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt76
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt9
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt66
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt289
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt17
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt13
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt16
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt16
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt9
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt15
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt106
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt34
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt14
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt33
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt3
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt37
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt81
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt115
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt8
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt57
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt121
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt11
-rw-r--r--packages/SystemUI/customization/res/values-land/dimens.xml (renamed from libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml)13
-rw-r--r--packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml2
-rw-r--r--packages/SystemUI/customization/res/values-sw600dp/dimens.xml1
-rw-r--r--packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml19
-rw-r--r--packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml19
-rw-r--r--packages/SystemUI/customization/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt4
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt252
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt29
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt51
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt40
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt33
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt21
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TypefaceCache.kt11
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt7
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt58
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt50
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/BatteryMeterDrawableTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/BootCompleteCacheTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/CameraAvailabilityListenerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/FakeCameraProtectionLoader.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/FakeCameraProtectionLoader.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManagerTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java59
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt23
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt50
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt219
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt75
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt62
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt28
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryTest.kt167
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorTest.kt138
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt11
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt35
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt181
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeMachineTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java)2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayRegistrantTest.kt165
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt295
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java49
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt222
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt23
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt65
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt319
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt286
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt99
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt151
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt43
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt120
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt33
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt23
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt63
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt103
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt23
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt28
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt24
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt37
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/power/PowerUITest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt50
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSSecurityFooterTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt110
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt116
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt44
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt63
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorTest.kt145
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt52
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt364
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionExecutorTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt)26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt156
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java64
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt71
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfoTest.java305
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt42
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt129
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt25
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt68
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt228
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt)116
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt28
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java74
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt280
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt36
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt70
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt68
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt62
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/util/TestableAlertDialogTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/util/TestableAlertDialogTest.kt)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt82
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java)4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java32
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorTest.kt92
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt24
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java9
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt25
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt37
-rw-r--r--packages/SystemUI/pods/Android.bp22
-rw-r--r--packages/SystemUI/pods/com/android/systemui/dagger/Android.bp34
-rw-r--r--packages/SystemUI/pods/com/android/systemui/dagger/SysUISingleton.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java)0
-rw-r--r--packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Application.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java)0
-rw-r--r--packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Background.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java)0
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/Android.bp38
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt (renamed from packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt)6
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp55
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt29
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt)13
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp46
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt23
-rw-r--r--packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt (renamed from packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt)9
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp40
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettings.java (renamed from packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java)0
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java (renamed from packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java)14
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettings.java (renamed from packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java)0
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java (renamed from packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java)14
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt (renamed from packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt)57
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxyExt.kt (renamed from packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt)0
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java (renamed from packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java)2
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettings.java (renamed from packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java)0
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java (renamed from packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java)14
-rw-r--r--packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt (renamed from packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt)58
-rw-r--r--packages/SystemUI/res-keyguard/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-eu/strings.xml2
-rw-r--r--packages/SystemUI/res-product/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml (renamed from packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml)7
-rw-r--r--packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml (renamed from packages/SystemUI/res/drawable/hearing_devices_preset_spinner_popup_background.xml)0
-rw-r--r--packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml (renamed from packages/SystemUI/res/drawable/volume_dialog_spacer.xml)17
-rw-r--r--packages/SystemUI/res/drawable/ic_check.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_widgets.xml26
-rw-r--r--packages/SystemUI/res/drawable/volume_background_top.xml1
-rw-r--r--packages/SystemUI/res/drawable/volume_background_top_legacy.xml2
-rw-r--r--packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml78
-rw-r--r--packages/SystemUI/res/layout/bluetooth_device_item.xml11
-rw-r--r--packages/SystemUI/res/layout/bluetooth_tile_dialog.xml26
-rw-r--r--packages/SystemUI/res/layout/bundle_notification_info.xml366
-rw-r--r--packages/SystemUI/res/layout/custom_trace_settings_dialog.xml12
-rw-r--r--packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml48
-rw-r--r--packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml45
-rw-r--r--packages/SystemUI/res/layout/hearing_devices_spinner_view.xml32
-rw-r--r--packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml117
-rw-r--r--packages/SystemUI/res/layout/hearing_tool_item.xml2
-rw-r--r--packages/SystemUI/res/layout/hybrid_conversation_notification.xml5
-rw-r--r--packages/SystemUI/res/layout/notification_2025_hybrid.xml42
-rw-r--r--packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml74
-rw-r--r--packages/SystemUI/res/layout/ongoing_activity_chip.xml5
-rw-r--r--packages/SystemUI/res/layout/record_issue_dialog.xml6
-rw-r--r--packages/SystemUI/res/layout/split_clock_view.xml54
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml16
-rw-r--r--packages/SystemUI/res/layout/volume_dialog.xml102
-rw-r--r--packages/SystemUI/res/layout/volume_dialog_legacy.xml4
-rw-r--r--packages/SystemUI/res/layout/volume_ringer_button.xml2
-rw-r--r--packages/SystemUI/res/layout/volume_ringer_drawer.xml61
-rw-r--r--packages/SystemUI/res/values-af/strings.xml39
-rw-r--r--packages/SystemUI/res/values-af/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-am/strings.xml39
-rw-r--r--packages/SystemUI/res/values-am/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml54
-rw-r--r--packages/SystemUI/res/values-ar/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-as/strings.xml39
-rw-r--r--packages/SystemUI/res/values-as/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-az/strings.xml39
-rw-r--r--packages/SystemUI/res/values-az/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml38
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-be/strings.xml36
-rw-r--r--packages/SystemUI/res/values-be/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml40
-rw-r--r--packages/SystemUI/res/values-bg/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml39
-rw-r--r--packages/SystemUI/res/values-bn/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml54
-rw-r--r--packages/SystemUI/res/values-bs/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml45
-rw-r--r--packages/SystemUI/res/values-ca/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml39
-rw-r--r--packages/SystemUI/res/values-cs/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-da/strings.xml41
-rw-r--r--packages/SystemUI/res/values-da/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-de/strings.xml41
-rw-r--r--packages/SystemUI/res/values-de/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-el/strings.xml36
-rw-r--r--packages/SystemUI/res/values-el/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml40
-rw-r--r--packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml40
-rw-r--r--packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml40
-rw-r--r--packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml42
-rw-r--r--packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-es/strings.xml43
-rw-r--r--packages/SystemUI/res/values-es/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-et/strings.xml47
-rw-r--r--packages/SystemUI/res/values-et/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml41
-rw-r--r--packages/SystemUI/res/values-eu/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml44
-rw-r--r--packages/SystemUI/res/values-fa/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml39
-rw-r--r--packages/SystemUI/res/values-fi/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml38
-rw-r--r--packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml45
-rw-r--r--packages/SystemUI/res/values-fr/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml41
-rw-r--r--packages/SystemUI/res/values-gl/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml40
-rw-r--r--packages/SystemUI/res/values-gu/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml61
-rw-r--r--packages/SystemUI/res/values-hi/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml46
-rw-r--r--packages/SystemUI/res/values-hr/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml41
-rw-r--r--packages/SystemUI/res/values-hu/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml42
-rw-r--r--packages/SystemUI/res/values-hy/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-in/strings.xml49
-rw-r--r--packages/SystemUI/res/values-in/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-is/strings.xml46
-rw-r--r--packages/SystemUI/res/values-is/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-it/strings.xml43
-rw-r--r--packages/SystemUI/res/values-it/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml47
-rw-r--r--packages/SystemUI/res/values-iw/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml48
-rw-r--r--packages/SystemUI/res/values-ja/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml36
-rw-r--r--packages/SystemUI/res/values-ka/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml39
-rw-r--r--packages/SystemUI/res/values-kk/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-km/strings.xml36
-rw-r--r--packages/SystemUI/res/values-km/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml52
-rw-r--r--packages/SystemUI/res/values-kn/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml43
-rw-r--r--packages/SystemUI/res/values-ko/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml53
-rw-r--r--packages/SystemUI/res/values-ky/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml1
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml36
-rw-r--r--packages/SystemUI/res/values-lo/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml36
-rw-r--r--packages/SystemUI/res/values-lt/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml39
-rw-r--r--packages/SystemUI/res/values-lv/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml39
-rw-r--r--packages/SystemUI/res/values-mk/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml39
-rw-r--r--packages/SystemUI/res/values-ml/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml39
-rw-r--r--packages/SystemUI/res/values-mn/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml36
-rw-r--r--packages/SystemUI/res/values-mr/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml44
-rw-r--r--packages/SystemUI/res/values-ms/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-my/strings.xml41
-rw-r--r--packages/SystemUI/res/values-my/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml39
-rw-r--r--packages/SystemUI/res/values-nb/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml44
-rw-r--r--packages/SystemUI/res/values-ne/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml36
-rw-r--r--packages/SystemUI/res/values-nl/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-or/strings.xml47
-rw-r--r--packages/SystemUI/res/values-or/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml41
-rw-r--r--packages/SystemUI/res/values-pa/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml40
-rw-r--r--packages/SystemUI/res/values-pl/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml47
-rw-r--r--packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml40
-rw-r--r--packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml47
-rw-r--r--packages/SystemUI/res/values-pt/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml39
-rw-r--r--packages/SystemUI/res/values-ro/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml47
-rw-r--r--packages/SystemUI/res/values-ru/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-si/strings.xml39
-rw-r--r--packages/SystemUI/res/values-si/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml57
-rw-r--r--packages/SystemUI/res/values-sk/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml46
-rw-r--r--packages/SystemUI/res/values-sl/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml41
-rw-r--r--packages/SystemUI/res/values-sq/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml38
-rw-r--r--packages/SystemUI/res/values-sr/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml39
-rw-r--r--packages/SystemUI/res/values-sv/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml45
-rw-r--r--packages/SystemUI/res/values-sw/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml3
-rw-r--r--packages/SystemUI/res/values-sw600dp-port/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp-land/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp-port/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml40
-rw-r--r--packages/SystemUI/res/values-ta/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-te/strings.xml52
-rw-r--r--packages/SystemUI/res/values-te/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-th/strings.xml38
-rw-r--r--packages/SystemUI/res/values-th/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml36
-rw-r--r--packages/SystemUI/res/values-tl/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml43
-rw-r--r--packages/SystemUI/res/values-tr/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml45
-rw-r--r--packages/SystemUI/res/values-uk/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml39
-rw-r--r--packages/SystemUI/res/values-ur/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml38
-rw-r--r--packages/SystemUI/res/values-uz/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml39
-rw-r--r--packages/SystemUI/res/values-vi/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml40
-rw-r--r--packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml39
-rw-r--r--packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml39
-rw-r--r--packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml39
-rw-r--r--packages/SystemUI/res/values-zu/tiles_states_strings.xml8
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml48
-rw-r--r--packages/SystemUI/res/values/strings.xml45
-rw-r--r--packages/SystemUI/res/values/styles.xml29
-rw-r--r--packages/SystemUI/res/xml/volume_dialog_constraint_set.xml15
-rw-r--r--packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml15
-rw-r--r--packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml49
-rw-r--r--packages/SystemUI/res/xml/volume_dialog_scene.xml27
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java13
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButton.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/development/data/repository/DevelopmentSettingRepository.kt79
-rw-r--r--packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/development/shared/model/BuildNumber.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/development/ui/compose/BuildNumber.kt81
-rw-r--r--packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java129
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt201
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shared/model/ShortcutCustomizationRequestResult.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt179
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt188
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt156
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CustomShortcutCategories.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/DefaultShortcutCategories.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/KeyCombination.kt (renamed from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt)6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt220
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt234
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt154
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt113
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java107
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl4
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.aidl3
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt167
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeLog.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt105
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt140
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt115
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt97
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/compose/BorderOnFocus.kt102
-rw-r--r--packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractor.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt126
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt109
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt)15
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt174
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/OWNERS2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipLogTags.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt)18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt422
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java772
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt152
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt119
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfo.java124
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java)38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java620
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitClockView.java145
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastUI.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt185
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractor.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/shared/model/SliderInputEvent.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt129
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt103
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt197
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderContentProviderTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt360
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt137
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt112
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt65
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt60
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt146
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java106
-rw-r--r--packages/SystemUI/tests/utils/src/android/content/ClipboardManagerKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt30
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryKosmos.kt25
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt35
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModelKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt15
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorKosmos.kt25
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToastKosmos.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt25
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt31
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt18
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt48
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java17
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt54
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepositoryKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorKosmo.kt33
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt61
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java6
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java66
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java67
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java15
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java4
-rw-r--r--ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java47
-rwxr-xr-xravenwood/scripts/run-ravenwood-tests.sh16
-rw-r--r--ravenwood/tests/bivalentinst/Android.bp7
-rw-r--r--ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java7
-rw-r--r--ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java9
-rw-r--r--ravenwood/tests/bivalenttest/Android.bp2
-rw-r--r--ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java10
-rw-r--r--ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt12
-rw-r--r--ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java9
-rw-r--r--ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java3
-rw-r--r--ravenwood/tests/runtime-test/Android.bp2
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp1
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt3697
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt3727
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt4896
-rwxr-xr-xravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py48
-rw-r--r--ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt2
-rw-r--r--services/accessibility/accessibility.aconfig10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java12
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java43
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java37
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java15
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java44
-rw-r--r--services/autofill/bugfixes.aconfig10
-rw-r--r--services/autofill/features.aconfig15
-rw-r--r--services/autofill/java/com/android/server/autofill/Helper.java60
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java5
-rw-r--r--services/backup/flags.aconfig9
-rw-r--r--services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java318
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java6
-rw-r--r--services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java3
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java170
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java2
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java27
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java5
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java23
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java27
-rw-r--r--services/backup/java/com/android/server/backup/transport/BackupTransportClient.java22
-rw-r--r--services/companion/java/com/android/server/companion/securechannel/SecureChannel.java4
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java9
-rw-r--r--services/core/java/com/android/server/BinaryTransparencyService.java64
-rw-r--r--services/core/java/com/android/server/SystemConfig.java19
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java102
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java20
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java25
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java81
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java142
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java54
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java4
-rw-r--r--services/core/java/com/android/server/am/AppStartInfoTracker.java25
-rw-r--r--services/core/java/com/android/server/am/BackupRecord.java5
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java23
-rw-r--r--services/core/java/com/android/server/am/BroadcastController.java36
-rw-r--r--services/core/java/com/android/server/am/BroadcastFilter.java29
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java30
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java4
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java225
-rw-r--r--services/core/java/com/android/server/am/OomAdjusterModernImpl.java5
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java3
-rw-r--r--services/core/java/com/android/server/am/ProcessServiceRecord.java12
-rw-r--r--services/core/java/com/android/server/am/ProcessStateController.java25
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java2
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig35
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java5
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java5
-rw-r--r--services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java3
-rw-r--r--services/core/java/com/android/server/audio/AudioServerPermissionProvider.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java31
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java61
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java19
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java20
-rw-r--r--services/core/java/com/android/server/biometrics/PreAuthInfo.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java15
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java9
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java2
-rw-r--r--services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java3
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java10
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java65
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java17
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java18
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java2
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java99
-rw-r--r--services/core/java/com/android/server/display/OWNERS2
-rw-r--r--services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java14
-rw-r--r--services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java15
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java2
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java58
-rw-r--r--services/core/java/com/android/server/display/color/TintController.java39
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java31
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig24
-rw-r--r--services/core/java/com/android/server/display/mode/SystemRequestObserver.java16
-rw-r--r--services/core/java/com/android/server/display/plugin/Plugin.java44
-rw-r--r--services/core/java/com/android/server/display/plugin/PluginManager.java141
-rw-r--r--services/core/java/com/android/server/display/plugin/PluginStorage.java134
-rw-r--r--services/core/java/com/android/server/display/plugin/PluginType.java48
-rw-r--r--services/core/java/com/android/server/display/plugin/PluginsProvider.java36
-rw-r--r--services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java10
-rw-r--r--services/core/java/com/android/server/input/AppLaunchShortcutManager.java57
-rw-r--r--services/core/java/com/android/server/input/InputGestureManager.java44
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java72
-rw-r--r--services/core/java/com/android/server/input/InputSettingsObserver.java9
-rw-r--r--services/core/java/com/android/server/input/InputShellCommand.java1
-rw-r--r--services/core/java/com/android/server/input/KeyGestureController.java5
-rw-r--r--services/core/java/com/android/server/input/KeyboardBacklightController.java10
-rw-r--r--services/core/java/com/android/server/input/NativeInputManagerService.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java43
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingModeController.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java2
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java1
-rw-r--r--services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java93
-rw-r--r--services/core/java/com/android/server/integrity/model/RuleMetadata.java41
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java7
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java93
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubService.java60
-rw-r--r--services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java130
-rw-r--r--services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java49
-rw-r--r--services/core/java/com/android/server/location/contexthub/OWNERS1
-rw-r--r--services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java20
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java199
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java191
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionStopController.java239
-rw-r--r--services/core/java/com/android/server/media/quality/MediaQualityDbHelper.java64
-rw-r--r--services/core/java/com/android/server/media/quality/MediaQualityService.java197
-rw-r--r--services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java99
-rw-r--r--services/core/java/com/android/server/notification/GroupHelper.java246
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java247
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java43
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java33
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/InferenceInfoStore.java12
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java35
-rw-r--r--services/core/java/com/android/server/pm/InstallDependencyHelper.java362
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java23
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java31
-rw-r--r--services/core/java/com/android/server/pm/OWNERS28
-rw-r--r--services/core/java/com/android/server/pm/PackageArchiver.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java93
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java302
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java106
-rw-r--r--services/core/java/com/android/server/pm/SharedLibrariesImpl.java5
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java8
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java14
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java11
-rw-r--r--services/core/java/com/android/server/pm/verify/pkg/VerificationStatusTracker.java91
-rw-r--r--services/core/java/com/android/server/pm/verify/pkg/VerifierController.java721
-rw-r--r--services/core/java/com/android/server/policy/DeviceStateProviderImpl.java5
-rw-r--r--services/core/java/com/android/server/policy/ModifierShortcutManager.java34
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java6
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java47
-rw-r--r--services/core/java/com/android/server/power/hint/Android.bp9
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java561
-rw-r--r--services/core/java/com/android/server/power/hint/adpf_flags.aconfig7
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java12
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java73
-rw-r--r--services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java (renamed from services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java)59
-rw-r--r--services/core/java/com/android/server/security/authenticationpolicy/OWNERS (renamed from services/core/java/com/android/server/security/adaptiveauthentication/OWNERS)0
-rw-r--r--services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java120
-rw-r--r--services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java55
-rw-r--r--services/core/java/com/android/server/security/forensic/ForensicService.java339
-rw-r--r--services/core/java/com/android/server/security/forensic/OWNERS1
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java (renamed from services/core/java/com/android/server/security/forensic/DataAggregator.java)30
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/DataSource.java (renamed from services/core/java/com/android/server/security/forensic/DataSource.java)2
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java (renamed from services/core/java/com/android/server/security/forensic/BackupTransportConnection.java)70
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java340
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/OWNERS1
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java (renamed from services/core/java/com/android/server/security/forensic/SecurityLogSource.java)55
-rw-r--r--services/core/java/com/android/server/stats/Android.bp7
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java65
-rw-r--r--services/core/java/com/android/server/stats/stats_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java49
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java96
-rw-r--r--services/core/java/com/android/server/utils/LazyJniRegistrar.java3
-rw-r--r--services/core/java/com/android/server/vibrator/AbstractVibratorStep.java8
-rw-r--r--services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java327
-rw-r--r--services/core/java/com/android/server/vibrator/DeviceAdapter.java9
-rw-r--r--services/core/java/com/android/server/vibrator/PrimitiveDelayAdapter.java116
-rw-r--r--services/core/java/com/android/server/vibrator/PrimitiveSegmentsValidator.java59
-rw-r--r--services/core/java/com/android/server/vibrator/PwleSegmentsValidator.java41
-rw-r--r--services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java2
-rw-r--r--services/core/java/com/android/server/vibrator/VendorVibrationSession.java104
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationSettings.java10
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationStepConductor.java11
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java249
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperDataParser.java8
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java12
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java174
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java73
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java27
-rw-r--r--services/core/java/com/android/server/wm/AppCompatCameraOverrides.java24
-rw-r--r--services/core/java/com/android/server/wm/AppCompatController.java10
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java46
-rw-r--r--services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java31
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java57
-rw-r--r--services/core/java/com/android/server/wm/DeferredDisplayUpdater.java1
-rw-r--r--services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java10
-rw-r--r--services/core/java/com/android/server/wm/Dimmer.java22
-rw-r--r--services/core/java/com/android/server/wm/DimmerAnimationHelper.java33
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java14
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java34
-rw-r--r--services/core/java/com/android/server/wm/EventLogTags.logtags13
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java10
-rw-r--r--services/core/java/com/android/server/wm/MirrorActiveUids.java47
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java32
-rw-r--r--services/core/java/com/android/server/wm/RefreshRatePolicy.java10
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java43
-rw-r--r--services/core/java/com/android/server/wm/SafeActivityOptions.java7
-rw-r--r--services/core/java/com/android/server/wm/Session.java15
-rw-r--r--services/core/java/com/android/server/wm/SnapshotPersistQueue.java15
-rw-r--r--services/core/java/com/android/server/wm/Task.java80
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java18
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java22
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java64
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java9
-rw-r--r--services/core/jni/Android.bp22
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp7
-rw-r--r--services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp6
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java21
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java896
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java13
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java30
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java41
-rw-r--r--services/java/com/android/server/SystemServer.java63
-rw-r--r--services/java/com/android/server/flags.aconfig8
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java16
-rw-r--r--services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java10
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java33
-rw-r--r--services/supervision/java/com/android/server/supervision/SupervisionService.java12
-rw-r--r--services/supervision/java/com/android/server/supervision/SupervisionUserData.java4
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java8
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java51
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt20
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java69
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerificationStatusTrackerTest.java113
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java535
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt28
-rw-r--r--services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java12
-rw-r--r--services/tests/apexsystemservices/services/Android.bp1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java6
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java25
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java41
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java33
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java22
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java19
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java7
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java55
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt24
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt97
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt100
-rw-r--r--services/tests/mockingservicestests/Android.bp2
-rw-r--r--services/tests/mockingservicestests/jni/Android.bp4
-rw-r--r--services/tests/mockingservicestests/jni/onload.cpp4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java86
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java59
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java15
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java21
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java30
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java10
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java60
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java133
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java381
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java91
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java113
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java27
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java102
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java104
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java22
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp2
-rw-r--r--services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java15
-rw-r--r--services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java374
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java6
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java10
-rw-r--r--services/tests/security/forensic/OWNERS3
-rw-r--r--services/tests/security/forensic/TEST_MAPPING7
-rw-r--r--services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java524
-rw-r--r--services/tests/security/intrusiondetection/Android.bp (renamed from services/tests/security/forensic/Android.bp)2
-rw-r--r--services/tests/security/intrusiondetection/AndroidManifest.xml (renamed from services/tests/security/forensic/AndroidManifest.xml)6
-rw-r--r--services/tests/security/intrusiondetection/AndroidTest.xml (renamed from services/tests/security/forensic/AndroidTest.xml)8
-rw-r--r--services/tests/security/intrusiondetection/OWNERS3
-rw-r--r--services/tests/security/intrusiondetection/TEST_MAPPING7
-rw-r--r--services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java410
-rw-r--r--services/tests/servicestests/Android.bp2
-rw-r--r--services/tests/servicestests/jni/Android.bp4
-rw-r--r--services/tests/servicestests/jni/onload.cpp4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java479
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java1444
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java61
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java128
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java95
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java197
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java468
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java281
-rw-r--r--services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java)36
-rw-r--r--services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java34
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java528
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java78
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java68
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java346
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java77
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java80
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java181
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/PrimitiveDelayAdapterTest.java195
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java12
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java143
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java242
-rw-r--r--services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java2
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java1
-rw-r--r--services/tests/wmtests/AndroidManifest.xml4
-rw-r--r--services/tests/wmtests/res/xml/bookmarks.xml47
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java100
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java29
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java63
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java42
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java78
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java74
-rw-r--r--services/usb/java/com/android/server/usb/flags/usb_flags.aconfig7
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java32
-rw-r--r--telephony/java/android/telephony/CellularIdentifierDisclosure.aidl20
-rw-r--r--telephony/java/android/telephony/CellularIdentifierDisclosure.java135
-rw-r--r--telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl (renamed from core/java/android/content/pm/verify/pkg/VerificationSession.aidl)6
-rw-r--r--telephony/java/android/telephony/SecurityAlgorithmUpdate.java269
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java54
-rw-r--r--telephony/java/android/telephony/satellite/EarfcnRange.java22
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteAccessConfiguration.java52
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteInfo.java73
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java79
-rw-r--r--telephony/java/android/telephony/satellite/SatellitePosition.java22
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl22
-rw-r--r--test-mock/src/android/test/mock/MockContentResolver.java3
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java92
-rw-r--r--tests/CtsSurfaceControlTestsStaging/AndroidManifest.xml8
-rw-r--r--tests/CtsSurfaceControlTestsStaging/AndroidTest.xml3
-rw-r--r--tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTest.java260
-rw-r--r--tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTestActivity.java43
-rw-r--r--tests/CtsSurfaceControlTestsStaging/src/main/res/layout/picture_profile_test_layout.xml32
-rw-r--r--tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt2
-rw-r--r--tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt2
-rw-r--r--tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt2
-rw-r--r--tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt2
-rw-r--r--tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt2
-rw-r--r--tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt2
-rw-r--r--tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt19
-rw-r--r--tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt62
-rw-r--r--tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt9
-rw-r--r--tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt44
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml18
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java18
-rw-r--r--tests/Input/res/xml/bookmarks.xml34
-rw-r--r--tests/Input/res/xml/bookmarks_legacy.xml60
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt216
-rw-r--r--tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt38
-rw-r--r--tests/PackageWatchdog/Android.bp2
-rw-r--r--tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java5
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java31
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java3
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java3
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java2
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java67
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java6
-rw-r--r--tests/broadcasts/OWNERS2
-rw-r--r--tests/broadcasts/unit/Android.bp45
-rw-r--r--tests/broadcasts/unit/AndroidManifest.xml27
-rw-r--r--tests/broadcasts/unit/AndroidTest.xml29
-rw-r--r--tests/broadcasts/unit/TEST_MAPPING15
-rw-r--r--tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java258
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java3
-rw-r--r--tools/aapt2/link/TableMerger.cpp15
-rw-r--r--tools/aapt2/util/Util.h9
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt3
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java2
2730 files changed, 96110 insertions, 33056 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index ad849002cca1..e18470498f39 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -56,7 +56,7 @@ aconfig_declarations_group {
"android.media.tv.flags-aconfig-java",
"android.multiuser.flags-aconfig-java",
"android.net.platform.flags-aconfig-java",
- "android.net.vcn.flags-aconfig-java",
+ "android.net.vcn.flags-aconfig-java-export",
"android.net.wifi.flags-aconfig-java",
"android.nfc.flags-aconfig-java",
"android.os.flags-aconfig-java",
@@ -72,6 +72,7 @@ aconfig_declarations_group {
"android.service.dreams.flags-aconfig-java",
"android.service.notification.flags-aconfig-java",
"android.service.appprediction.flags-aconfig-java",
+ "android.service.quickaccesswallet.flags-aconfig-java",
"android.service.voice.flags-aconfig-java",
"android.speech.flags-aconfig-java",
"android.systemserver.flags-aconfig-java",
@@ -99,7 +100,7 @@ aconfig_declarations_group {
"com.android.media.flags.performance-aconfig-java",
"com.android.media.flags.projection-aconfig-java",
"com.android.net.thread.platform.flags-aconfig-java",
- "com.android.ranging.flags.ranging-aconfig-java",
+ "com.android.ranging.flags.ranging-aconfig-java-export",
"com.android.server.contextualsearch.flags-java",
"com.android.server.flags.services-aconfig-java",
"com.android.text.flags-aconfig-java",
@@ -111,6 +112,7 @@ aconfig_declarations_group {
"framework_graphics_flags_java_lib",
"hwui_flags_java_lib",
"interaction_jank_monitor_flags_lib",
+ "keystore2_flags_java-framework",
"libcore_exported_aconfig_flags_lib",
"libcore_readonly_aconfig_flags_lib",
"libgui_flags_java_lib",
@@ -371,6 +373,11 @@ java_aconfig_library {
name: "android.security.flags-aconfig-java-export",
aconfig_declarations: "android.security.flags-aconfig",
mode: "exported",
+ min_sdk_version: "30",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
@@ -1168,16 +1175,21 @@ java_aconfig_library {
}
// VCN
+// TODO:376339506 Move the VCN code, the flag declaration and
+// java_aconfig_library to framework-connectivity-b
aconfig_declarations {
name: "android.net.vcn.flags-aconfig",
package: "android.net.vcn",
- container: "system",
+ container: "com.android.tethering",
+ exportable: true,
srcs: ["core/java/android/net/vcn/*.aconfig"],
}
java_aconfig_library {
- name: "android.net.vcn.flags-aconfig-java",
+ name: "android.net.vcn.flags-aconfig-java-export",
aconfig_declarations: "android.net.vcn.flags-aconfig",
+ mode: "exported",
+ min_sdk_version: "35",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
@@ -1644,13 +1656,6 @@ java_aconfig_library {
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
-// Ranging
-java_aconfig_library {
- name: "com.android.ranging.flags.ranging-aconfig-java",
- aconfig_declarations: "ranging_aconfig_flags",
- defaults: ["framework-minus-apex-aconfig-java-defaults"],
-}
-
// System Server
aconfig_declarations {
name: "android.systemserver.flags-aconfig",
@@ -1774,3 +1779,18 @@ java_aconfig_library {
aconfig_declarations: "aconfig_settingslib_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// Quick Access Wallet
+aconfig_declarations {
+ name: "android.service.quickaccesswallet.flags-aconfig",
+ package: "android.service.quickaccesswallet",
+ exportable: true,
+ container: "system",
+ srcs: ["core/java/android/service/quickaccesswallet/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.service.quickaccesswallet.flags-aconfig-java",
+ aconfig_declarations: "android.service.quickaccesswallet.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index 48f0928f24d7..424a4a71ce40 100644
--- a/Android.bp
+++ b/Android.bp
@@ -103,11 +103,10 @@ filegroup {
":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",
":android.hardware.keymaster-V4-java-source",
- ":android.hardware.radio-V3-java-source",
- ":android.hardware.radio.data-V3-java-source",
- ":android.hardware.radio.network-V3-java-source",
- ":android.hardware.radio.voice-V3-java-source",
- ":android.hardware.security.keymint-V3-java-source",
+ ":android.hardware.radio-V4-java-source",
+ ":android.hardware.radio.data-V4-java-source",
+ ":android.hardware.radio.network-V4-java-source",
+ ":android.hardware.radio.voice-V4-java-source",
":android.hardware.security.secureclock-V1-java-source",
":android.hardware.thermal-V3-java-source",
":android.hardware.tv.tuner-V3-java-source",
@@ -116,7 +115,6 @@ filegroup {
":android.security.legacykeystore-java-source",
":android.security.maintenance-java-source",
":android.security.metrics-java-source",
- ":android.system.keystore2-V4-java-source",
":android.hardware.cas-V1-java-source",
":credstore_aidl",
":dumpstate_aidl",
@@ -149,7 +147,16 @@ filegroup {
":statslog-framework-java-gen", // FrameworkStatsLog.java
":statslog-hwui-java-gen", // HwuiStatsLog.java
":audio_policy_configuration_V7_0",
- ],
+ ] + select(release_flag("RELEASE_ATTEST_MODULES"), {
+ true: [
+ ":android.hardware.security.keymint-V4-java-source",
+ ":android.system.keystore2-V5-java-source",
+ ],
+ default: [
+ ":android.hardware.security.keymint-V3-java-source",
+ ":android.system.keystore2-V4-java-source",
+ ],
+ }),
}
java_library {
@@ -225,13 +232,13 @@ java_library {
"android.hardware.gnss-V2.1-java",
"android.hardware.health-V1.0-java-constants",
"android.hardware.radio-V1.6-java",
- "android.hardware.radio.data-V3-java",
- "android.hardware.radio.ims-V2-java",
- "android.hardware.radio.messaging-V3-java",
- "android.hardware.radio.modem-V3-java",
- "android.hardware.radio.network-V3-java",
- "android.hardware.radio.sim-V3-java",
- "android.hardware.radio.voice-V3-java",
+ "android.hardware.radio.data-V4-java",
+ "android.hardware.radio.ims-V3-java",
+ "android.hardware.radio.messaging-V4-java",
+ "android.hardware.radio.modem-V4-java",
+ "android.hardware.radio.network-V4-java",
+ "android.hardware.radio.sim-V4-java",
+ "android.hardware.radio.voice-V4-java",
"android.hardware.thermal-V1.0-java-constants",
"android.hardware.thermal-V1.0-java",
"android.hardware.thermal-V1.1-java",
@@ -390,6 +397,8 @@ java_defaults {
"ext",
"framework-updatable-stubs-module_libs_api",
"unsupportedappusage",
+ // TODO(b/379770939): remove prod version of flags from other containers in framework
+ "aconfig_storage_stub",
],
sdk_version: "core_platform",
static_libs: [
@@ -398,6 +407,7 @@ java_defaults {
"bouncycastle-repackaged-unbundled",
"com.android.sysprop.foldlockbehavior",
"com.android.sysprop.view",
+ "configinfra_framework_flags_java_lib",
"framework-internal-utils",
"dynamic_instrumentation_manager_aidl-java",
// If MimeMap ever becomes its own APEX, then this dependency would need to be removed
diff --git a/FF_LEADS_OWNERS b/FF_LEADS_OWNERS
new file mode 100644
index 000000000000..a650c6b7a26f
--- /dev/null
+++ b/FF_LEADS_OWNERS
@@ -0,0 +1,10 @@
+bills@google.com
+carmenjackson@google.com
+nalini@google.com
+nosh@google.com
+olilan@google.com
+philipcuadra@google.com
+rajekumar@google.com
+shayba@google.com
+timmurray@google.com
+zezeozue@google.com
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
index 46250d74a4e3..d950b708dcc6 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
@@ -34,6 +34,8 @@ import org.junit.Test;
public class TextClassificationManagerPerfTest {
private static final String WRITE_DEVICE_CONFIG_PERMISSION =
"android.permission.WRITE_DEVICE_CONFIG";
+ private static final String WRITE_ALLOWLISTED_DEVICE_CONFIG_PERMISSION =
+ "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG";
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@@ -44,7 +46,7 @@ public class TextClassificationManagerPerfTest {
public static void setUpClass() {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(
- WRITE_DEVICE_CONFIG_PERMISSION);
+ WRITE_DEVICE_CONFIG_PERMISSION, WRITE_ALLOWLISTED_DEVICE_CONFIG_PERMISSION);
}
@AfterClass
diff --git a/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
index 7ef8c53d1d62..7168fbec07bc 100644
--- a/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
+++ b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
@@ -19,6 +19,9 @@ import android.app.Activity;
import android.os.Bundle;
import android.os.ServiceManager.ServiceNotFoundException;
import android.perftests.utils.Stats;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
import androidx.test.InstrumentationRegistry;
@@ -70,6 +73,8 @@ public class ProtoLogPerfTest {
}
private IProtoLog mProcessedProtoLogger;
+ private static ProtoLogDataSource sTestDataSource;
+ private static final String TEST_PROTOLOG_DATASOURCE_NAME = "test.android.protolog";
private static final String MOCK_TEST_FILE_PATH = "mock/file/path";
private static final perfetto.protos.Protolog.ProtoLogViewerConfig VIEWER_CONFIG =
perfetto.protos.Protolog.ProtoLogViewerConfig.newBuilder()
@@ -89,6 +94,17 @@ public class ProtoLogPerfTest {
@BeforeClass
public static void init() {
+ Producer.init(InitArguments.DEFAULTS);
+
+ sTestDataSource = new ProtoLogDataSource(TEST_PROTOLOG_DATASOURCE_NAME);
+ DataSourceParams params =
+ new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(
+ DataSourceParams
+ .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
+ .build();
+ sTestDataSource.register(params);
+
ProtoLog.init(TestProtoLogGroup.values());
}
@@ -98,9 +114,10 @@ public class ProtoLogPerfTest {
TestProtoLogGroup.TEST_GROUP.setLogToLogcat(mLogToLogcat);
mProcessedProtoLogger = new ProcessedPerfettoProtoLogImpl(
+ sTestDataSource,
MOCK_TEST_FILE_PATH,
() -> new AutoClosableProtoInputStream(VIEWER_CONFIG.toByteArray()),
- () -> {},
+ (instance) -> {},
TestProtoLogGroup.values()
);
}
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
index e9357f4a9d3c..1175677bbb04 100644
--- a/apct-tests/perftests/windowmanager/Android.bp
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
package {
- default_team: "trendy_team_input_framework",
+ default_team: "trendy_team_windowing_animations_transitions",
// 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"
diff --git a/apex/jobscheduler/service/aconfig/alarm.aconfig b/apex/jobscheduler/service/aconfig/alarm.aconfig
index d3068d7d37e8..a6e980726a9a 100644
--- a/apex/jobscheduler/service/aconfig/alarm.aconfig
+++ b/apex/jobscheduler/service/aconfig/alarm.aconfig
@@ -2,16 +2,6 @@ package: "com.android.server.alarm"
container: "system"
flag {
- name: "use_frozen_state_to_drop_listener_alarms"
- namespace: "backstage_power"
- description: "Use frozen state callback to drop listener alarms for cached apps"
- bug: "324470945"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "start_user_before_scheduled_alarms"
namespace: "multiuser"
description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due"
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 033da2df9bf6..60ba3b896a28 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -282,7 +282,6 @@ public class AlarmManagerService extends SystemService {
private final Injector mInjector;
int mBroadcastRefCount = 0;
- boolean mUseFrozenStateToDropListenerAlarms;
MetricsHelper mMetricsHelper;
PowerManager.WakeLock mWakeLock;
SparseIntArray mAlarmsPerUid = new SparseIntArray();
@@ -1784,40 +1783,37 @@ public class AlarmManagerService extends SystemService {
mMetricsHelper = new MetricsHelper(getContext(), mLock);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
- mUseFrozenStateToDropListenerAlarms = Flags.useFrozenStateToDropListenerAlarms();
mStartUserBeforeScheduledAlarms = Flags.startUserBeforeScheduledAlarms()
&& UserManager.supportsMultipleUsers();
if (mStartUserBeforeScheduledAlarms) {
mUserWakeupStore = new UserWakeupStore();
mUserWakeupStore.init();
}
- if (mUseFrozenStateToDropListenerAlarms) {
- final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> {
- final int size = frozenStates.length;
- if (uids.length != size) {
- Slog.wtf(TAG, "Got different length arrays in frozen state callback!"
- + " uids.length: " + uids.length + " frozenStates.length: " + size);
- // Cannot process received data in any meaningful way.
- return;
- }
- final IntArray affectedUids = new IntArray();
- for (int i = 0; i < size; i++) {
- if (frozenStates[i] != UID_FROZEN_STATE_FROZEN) {
- continue;
- }
- if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED,
- uids[i])) {
- continue;
- }
- affectedUids.add(uids[i]);
+ final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> {
+ final int size = frozenStates.length;
+ if (uids.length != size) {
+ Slog.wtf(TAG, "Got different length arrays in frozen state callback!"
+ + " uids.length: " + uids.length + " frozenStates.length: " + size);
+ // Cannot process received data in any meaningful way.
+ return;
+ }
+ final IntArray affectedUids = new IntArray();
+ for (int i = 0; i < size; i++) {
+ if (frozenStates[i] != UID_FROZEN_STATE_FROZEN) {
+ continue;
}
- if (affectedUids.size() > 0) {
- removeExactListenerAlarms(affectedUids.toArray());
+ if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED,
+ uids[i])) {
+ continue;
}
- };
- final ActivityManager am = getContext().getSystemService(ActivityManager.class);
- am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback);
- }
+ affectedUids.add(uids[i]);
+ }
+ if (affectedUids.size() > 0) {
+ removeExactListenerAlarms(affectedUids.toArray());
+ }
+ };
+ final ActivityManager am = getContext().getSystemService(ActivityManager.class);
+ am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback);
mListenerDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -2994,13 +2990,10 @@ public class AlarmManagerService extends SystemService {
pw.println("Feature Flags:");
pw.increaseIndent();
- pw.print(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS,
- mUseFrozenStateToDropListenerAlarms);
- pw.println();
pw.print(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS,
Flags.startUserBeforeScheduledAlarms());
- pw.decreaseIndent();
pw.println();
+ pw.decreaseIndent();
pw.println();
pw.println("App Standby Parole: " + mAppStandbyParole);
@@ -5146,38 +5139,6 @@ public class AlarmManagerService extends SystemService {
removeForStoppedLocked(uid);
}
}
-
- @Override
- public void handleUidCachedChanged(int uid, boolean cached) {
- if (mUseFrozenStateToDropListenerAlarms) {
- // Use ActivityManager#UidFrozenStateChangedCallback instead.
- return;
- }
- if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, uid)) {
- return;
- }
- // Apps can quickly get frozen after being cached, breaking the exactness guarantee on
- // listener alarms. So going forward, the contract of exact listener alarms explicitly
- // states that they will be removed as soon as the app goes out of lifecycle. We still
- // allow a short grace period for quick shuffling of proc-states that may happen
- // unexpectedly when switching between different lifecycles and is generally hard for
- // apps to avoid.
-
- final long delay;
- synchronized (mLock) {
- delay = mConstants.CACHED_LISTENER_REMOVAL_DELAY;
- }
- final Integer uidObj = uid;
-
- if (cached && !mHandler.hasEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED,
- uidObj)) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj),
- delay);
- } else {
- mHandler.removeEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj);
- }
- }
};
private final BroadcastStats getStatsLocked(PendingIntent pi) {
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 1c6e40e25a92..963307b110cf 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2085,8 +2085,12 @@ public class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.v(TAG, debugPrefix + " ready=" + jobReady);
}
- if (!jobReady) {
- return job.getPendingJobReasons();
+ final JobRestriction restriction = checkIfRestricted(job);
+ if (DEBUG) {
+ Slog.v(TAG, debugPrefix + " restriction=" + restriction);
+ }
+ if (!jobReady || restriction != null) {
+ return job.getPendingJobReasons(restriction);
}
final boolean userStarted = areUsersStartedLocked(job);
@@ -2106,18 +2110,6 @@ public class JobSchedulerService extends com.android.server.SystemService
return new int[] { JobScheduler.PENDING_JOB_REASON_APP };
}
- final JobRestriction restriction = checkIfRestricted(job);
- if (DEBUG) {
- Slog.v(TAG, debugPrefix + " restriction=" + restriction);
- }
- if (restriction != null) {
- // Currently this will return _DEVICE_STATE because of thermal reasons.
- // TODO (b/372031023): does it make sense to move this along with the
- // pendingJobReasons() call above and also get the pending reasons from
- // all of the restriction controllers?
- return new int[] { restriction.getPendingReason() };
- }
-
// The following can be a little more expensive, so we are doing it later,
// but still before checking with the package manager!
final boolean jobPending = mPendingJobQueue.contains(job);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index b0784f1c69fd..a3eaefd5f057 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -66,6 +66,7 @@ import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobServerProtoEnums;
import com.android.server.job.JobStatusDumpProto;
import com.android.server.job.JobStatusShortInfoProto;
+import com.android.server.job.restrictions.JobRestriction;
import dalvik.annotation.optimization.NeverCompile;
@@ -2179,11 +2180,20 @@ public final class JobStatus {
* This will return all potential reasons why the job is pending.
*/
@NonNull
- public int[] getPendingJobReasons() {
+ public int[] getPendingJobReasons(@Nullable JobRestriction restriction) {
final int unsatisfiedConstraints = ~satisfiedConstraints
& (requiredConstraints | mDynamicConstraints | IMPLICIT_CONSTRAINTS);
final ArrayList<Integer> reasons = constraintsToPendingJobReasons(unsatisfiedConstraints);
+ if (restriction != null) {
+ // Currently only ThermalStatusRestriction extends the JobRestriction class and
+ // returns PENDING_JOB_REASON_DEVICE_STATE if the job is restricted because of thermal.
+ @JobScheduler.PendingJobReason final int reason = restriction.getPendingReason();
+ if (!reasons.contains(reason)) {
+ reasons.addLast(reason);
+ }
+ }
+
if (reasons.isEmpty()) {
if (getEffectiveStandbyBucket() == NEVER_INDEX) {
Slog.wtf(TAG, "App in NEVER bucket querying pending job reason");
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 8bd3ef4f4d1a..637c726a9bd1 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
@@ -36,10 +36,14 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.UidObserver;
+import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.Overridable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -132,6 +136,27 @@ public final class QuotaController extends StateController {
return (int) (val ^ (val >>> 32));
}
+ /**
+ * When enabled this change id overrides the default quota policy enforcement to the jobs
+ * running in the foreground process state.
+ */
+ // TODO: b/379681266 - Might need some refactoring for a better app-compat strategy.
+ @VisibleForTesting
+ @ChangeId
+ @Disabled // Disabled by default
+ @Overridable // The change can be overridden in user build
+ static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS = 341201311L;
+
+ /**
+ * When enabled this change id overrides the default quota policy enforcement policy
+ * the jobs started when app was in the TOP state.
+ */
+ @VisibleForTesting
+ @ChangeId
+ @Disabled // Disabled by default
+ @Overridable // The change can be overridden in user build.
+ static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS = 374323858L;
+
@VisibleForTesting
static class ExecutionStats {
/**
@@ -622,7 +647,9 @@ public final class QuotaController extends StateController {
}
final int uid = jobStatus.getSourceUid();
- if (!Flags.enforceQuotaPolicyToTopStartedJobs() && mTopAppCache.get(uid)) {
+ if ((!Flags.enforceQuotaPolicyToTopStartedJobs()
+ || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+ uid)) && mTopAppCache.get(uid)) {
if (DEBUG) {
Slog.d(TAG, jobStatus.toShortString() + " is top started job");
}
@@ -659,7 +686,9 @@ public final class QuotaController extends StateController {
timer.stopTrackingJob(jobStatus);
}
}
- if (!Flags.enforceQuotaPolicyToTopStartedJobs()) {
+ if (!Flags.enforceQuotaPolicyToTopStartedJobs()
+ || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+ jobStatus.getSourceUid())) {
mTopStartedJobs.remove(jobStatus);
}
}
@@ -772,7 +801,13 @@ public final class QuotaController extends StateController {
/** @return true if the job was started while the app was in the TOP state. */
private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) {
- return !Flags.enforceQuotaPolicyToTopStartedJobs() && mTopStartedJobs.contains(jobStatus);
+ if (!Flags.enforceQuotaPolicyToTopStartedJobs()
+ || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+ jobStatus.getSourceUid())) {
+ return mTopStartedJobs.contains(jobStatus);
+ }
+
+ return false;
}
/** Returns the maximum amount of time this job could run for. */
@@ -2634,9 +2669,13 @@ public final class QuotaController extends StateController {
}
@VisibleForTesting
- int getProcessStateQuotaFreeThreshold() {
- return Flags.enforceQuotaPolicyToFgsJobs() ? ActivityManager.PROCESS_STATE_BOUND_TOP :
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ int getProcessStateQuotaFreeThreshold(int uid) {
+ if (Flags.enforceQuotaPolicyToFgsJobs()
+ && !CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS, uid)) {
+ return ActivityManager.PROCESS_STATE_BOUND_TOP;
+ }
+
+ return ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
}
private class QcHandler extends Handler {
@@ -2776,7 +2815,7 @@ public final class QuotaController extends StateController {
isQuotaFree = true;
} else {
final boolean reprocess;
- if (procState <= getProcessStateQuotaFreeThreshold()) {
+ if (procState <= getProcessStateQuotaFreeThreshold(uid)) {
reprocess = !mForegroundUids.get(uid);
mForegroundUids.put(uid, true);
isQuotaFree = true;
diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp
index 1ebe0cdfabd7..89351fd47ff8 100644
--- a/api/ApiDocs.bp
+++ b/api/ApiDocs.bp
@@ -61,6 +61,7 @@ stubs_defaults {
":framework-bluetooth-sources",
":framework-connectivity-tiramisu-updatable-sources",
":framework-graphics-srcs",
+ ":framework-healthfitness-sources",
":framework-mediaprovider-sources",
":framework-nearby-sources",
":framework-nfc-updatable-sources",
diff --git a/boot/boot-image-profile-extra.txt b/boot/boot-image-profile-extra.txt
index e31eb3a993f0..fd51f9cbcee1 100644
--- a/boot/boot-image-profile-extra.txt
+++ b/boot/boot-image-profile-extra.txt
@@ -23,4 +23,25 @@ HSPLandroid/graphics/Color;->luminance()F
# For now, compile all methods in MessageQueue to avoid performance cliffs for
# flagged/evolving hot code paths. See: b/338098106
HSPLandroid/os/MessageQueue;->*
-HSPLandroid/os/MessageQueue$*;->*
+HSPLandroid/os/MessageQueue$FileDescriptorRecord;->*
+HSPLandroid/os/MessageQueue$IdleHandler;->*
+HSPLandroid/os/MessageQueue$MessageCompare;->*
+HSPLandroid/os/MessageQueue$MatchAllFutureMessages;->*
+HSPLandroid/os/MessageQueue$MatchAllMessages;->*
+HSPLandroid/os/MessageQueue$MatchBarrierToken;->*
+HSPLandroid/os/MessageQueue$MatchDeliverableMessages;->*
+HSPLandroid/os/MessageQueue$MatchHandler;->*
+HSPLandroid/os/MessageQueue$MatchHandlerAndObject;->*
+HSPLandroid/os/MessageQueue$MatchHandlerAndObjectEquals;->*
+HSPLandroid/os/MessageQueue$MatchHandlerRunnableAndObject;->*
+HSPLandroid/os/MessageQueue$MatchHandlerRunnableAndObjectEquals;->*
+HSPLandroid/os/MessageQueue$MatchHandlerWhatAndObject;->*
+HSPLandroid/os/MessageQueue$MatchHandlerWhatAndObjectEquals;->*
+HSPLandroid/os/MessageQueue$MessageCounts;->*
+HSPLandroid/os/MessageQueue$StackNode;->*
+HSPLandroid/os/MessageQueue$MessageNode;->*
+HSPLandroid/os/MessageQueue$OnFileDescriptorEventListener$Events;->*
+HSPLandroid/os/MessageQueue$OnFileDescriptorEventListener;->*
+HSPLandroid/os/MessageQueue$StackNodeType;->*
+HSPLandroid/os/MessageQueue$StateNode;->*
+HSPLandroid/os/MessageQueue$TimedParkStateNode;->*
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 68800cde6101..2608c69be66f 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -99,7 +99,7 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
std::vector<std::string> idmap_paths;
for (const std::string& overlay_apk_path : overlay_apk_paths) {
- const std::string idmap_path = Idmap::CanonicalIdmapPathFor(idmap_dir, overlay_apk_path);
+ std::string idmap_path = Idmap::CanonicalIdmapPathFor(idmap_dir, overlay_apk_path);
const uid_t uid = getuid();
if (!UidHasWriteAccessToPath(uid, idmap_path)) {
LOG(WARNING) << "uid " << uid << "does not have write access to " << idmap_path.c_str();
@@ -111,7 +111,7 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
!ignore_overlayable)) {
const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
if (!overlay) {
- LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
+ LOG(WARNING) << "failed to load apk " << overlay_apk_path;
continue;
}
@@ -138,7 +138,7 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
}
}
- idmap_paths.emplace_back(idmap_path);
+ idmap_paths.emplace_back(std::move(idmap_path));
}
for (const std::string& idmap_path : idmap_paths) {
diff --git a/cmds/interrupter/Android.bp b/cmds/interrupter/Android.bp
deleted file mode 100644
index d7f744d0834e..000000000000
--- a/cmds/interrupter/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-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"],
-}
-
-cc_library_shared {
- name: "interrupter",
- host_supported: true,
- srcs: ["interrupter.c"],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
diff --git a/cmds/interrupter/interrupter.c b/cmds/interrupter/interrupter.c
deleted file mode 100644
index ae555150c969..000000000000
--- a/cmds/interrupter/interrupter.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 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.
- */
-
-
-/**
- * The probability of a syscall failing from 0.0 to 1.0
- */
-#define PROBABILITY 0.9
-
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-
-/* for various intercepted calls */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-/* For builds on glibc */
-#define __USE_GNU
-#include <dlfcn.h>
-
-#include "interrupter.h"
-
-static int probability = PROBABILITY * RAND_MAX;
-
-static int maybe_interrupt() {
- if (rand() < probability) {
- return 1;
- }
- return 0;
-}
-
-DEFINE_INTERCEPT(read, ssize_t, int, void*, size_t);
-DEFINE_INTERCEPT(write, ssize_t, int, const void*, size_t);
-DEFINE_INTERCEPT(accept, int, int, struct sockaddr*, socklen_t*);
-DEFINE_INTERCEPT(creat, int, const char*, mode_t);
diff --git a/cmds/interrupter/interrupter.h b/cmds/interrupter/interrupter.h
deleted file mode 100644
index 9ad0277eebbe..000000000000
--- a/cmds/interrupter/interrupter.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
-#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
-#define CONCATENATE2(arg1, arg2) arg1##arg2
-
-#define INTERRUPTER(sym) \
- if (real_##sym == NULL) \
- __init_##sym(); \
- if (maybe_interrupt()) { \
- errno = EINTR; \
- return -1; \
- }
-
-#define CALL_FUNCTION_1(sym, ret, type1) \
-ret (*real_##sym)(type1) = NULL; \
-ret sym(type1 arg1) { \
- INTERRUPTER(sym) \
- return real_##sym(arg1); \
-}
-
-#define CALL_FUNCTION_2(sym, ret, type1, type2) \
-ret (*real_##sym)(type1, type2) = NULL; \
-ret sym(type1 arg1, type2 arg2) { \
- INTERRUPTER(sym) \
- return real_##sym(arg1, arg2); \
-}
-
-#define CALL_FUNCTION_3(sym, ret, type1, type2, type3) \
-ret (*real_##sym)(type1, type2, type3) = NULL; \
-ret sym(type1 arg1, type2 arg2, type3 arg3) { \
- INTERRUPTER(sym) \
- return real_##sym(arg1, arg2, arg3); \
-}
-
-#define CALL_FUNCTION_4(sym, ret, type1, type2, type3, type4) \
-ret (*real_##sym)(type1, type2, type3, type4) = NULL; \
-ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
- INTERRUPTER(sym) \
- return real_##sym(arg1, arg2, arg3, arg4); \
-}
-
-#define CALL_FUNCTION_5(sym, ret, type1, type2, type3, type4, type5) \
-ret (*real_##sym)(type1, type2, type3, type4, type5) = NULL; \
-ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
- INTERRUPTER(sym) \
- return real_##sym(arg1, arg2, arg3, arg4, arg5); \
-}
-
-#define DEFINE_INTERCEPT_N(N, sym, ret, ...) \
-static void __init_##sym(void); \
-CONCATENATE(CALL_FUNCTION_, N)(sym, ret, __VA_ARGS__) \
-static void __init_##sym(void) { \
- real_##sym = dlsym(RTLD_NEXT, #sym); \
- if (real_##sym == NULL) { \
- fprintf(stderr, "Error hooking " #sym ": %s\n", dlerror()); \
- } \
-}
-
-#define INTERCEPT_NARG(...) INTERCEPT_NARG_N(__VA_ARGS__, INTERCEPT_RSEQ_N())
-#define INTERCEPT_NARG_N(...) INTERCEPT_ARG_N(__VA_ARGS__)
-#define INTERCEPT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
-#define INTERCEPT_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
-
-#define DEFINE_INTERCEPT(sym, ret, ...) DEFINE_INTERCEPT_N(INTERCEPT_NARG(__VA_ARGS__), sym, ret, __VA_ARGS__)
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index f726361effd6..a88796c38166 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
@@ -217,6 +217,9 @@ public class AccessibilityNodeInfoDumper {
serializer.attribute("", "selected", Boolean.toString(node.isSelected()));
serializer.attribute("", "bounds", AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(
node, width, height).toShortString());
+ serializer.attribute("", "drawing-order", Integer.toString(node.getDrawingOrder()));
+ serializer.attribute("", "hint", safeCharSeqToString(node.getHintText()));
+
int count = node.getChildCount();
for (int i = 0; i < count; i++) {
AccessibilityNodeInfo child = node.getChild(i);
diff --git a/core/api/current.txt b/core/api/current.txt
index d4d4b24810e8..3af8e7e17dbd 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -23,6 +23,7 @@ package android {
field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
+ field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String APPLY_PICTURE_PROFILE = "android.permission.APPLY_PICTURE_PROFILE";
field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -336,7 +337,7 @@ package android {
field public static final String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
field public static final String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
field public static final String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS";
- field @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final String WRITE_SYSTEM_PREFERENCES = "android.permission.WRITE_SYSTEM_PREFERENCES";
+ field @FlaggedApi("com.android.settingslib.flags.write_system_preference_permission_enabled") public static final String WRITE_SYSTEM_PREFERENCES = "android.permission.WRITE_SYSTEM_PREFERENCES";
field public static final String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL";
}
@@ -1276,6 +1277,7 @@ package android {
field public static final int paddingStart = 16843699; // 0x10103b3
field public static final int paddingTop = 16842967; // 0x10100d7
field public static final int paddingVertical = 16844094; // 0x101053e
+ field @FlaggedApi("android.content.pm.app_compat_option_16kb") public static final int pageSizeCompat;
field public static final int panelBackground = 16842846; // 0x101005e
field public static final int panelColorBackground = 16842849; // 0x1010061
field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -1500,6 +1502,7 @@ package android {
field public static final int shadowRadius = 16843108; // 0x1010164
field public static final int shape = 16843162; // 0x101019a
field public static final int shareInterpolator = 16843195; // 0x10101bb
+ field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final int shareRolePriority;
field @Deprecated public static final int sharedUserId = 16842763; // 0x101000b
field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
field public static final int sharedUserMaxSdkVersion = 16844365; // 0x101064d
@@ -2043,6 +2046,12 @@ package android {
field public static final int system_error_container_light = 17170554; // 0x106007a
field public static final int system_error_dark = 17170595; // 0x10600a3
field public static final int system_error_light = 17170552; // 0x1060078
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_on_surface_dark;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_on_surface_light;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_primary_dark;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_primary_light;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_surface_dark;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_surface_light;
field public static final int system_neutral1_0 = 17170461; // 0x106001d
field public static final int system_neutral1_10 = 17170462; // 0x106001e
field public static final int system_neutral1_100 = 17170464; // 0x1060020
@@ -2119,12 +2128,16 @@ package android {
field public static final int system_primary_fixed = 17170612; // 0x10600b4
field public static final int system_primary_fixed_dim = 17170613; // 0x10600b5
field public static final int system_primary_light = 17170528; // 0x1060060
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_scrim_dark;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_scrim_light;
field public static final int system_secondary_container_dark = 17170573; // 0x106008d
field public static final int system_secondary_container_light = 17170530; // 0x1060062
field public static final int system_secondary_dark = 17170575; // 0x106008f
field public static final int system_secondary_fixed = 17170616; // 0x10600b8
field public static final int system_secondary_fixed_dim = 17170617; // 0x10600b9
field public static final int system_secondary_light = 17170532; // 0x1060064
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_shadow_dark;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_shadow_light;
field public static final int system_surface_bright_dark = 17170590; // 0x106009e
field public static final int system_surface_bright_light = 17170547; // 0x1060073
field public static final int system_surface_container_dark = 17170587; // 0x106009b
@@ -2142,6 +2155,8 @@ package android {
field public static final int system_surface_dim_light = 17170548; // 0x1060074
field public static final int system_surface_disabled = 17170626; // 0x10600c2
field public static final int system_surface_light = 17170540; // 0x106006c
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_surface_tint_dark;
+ field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_surface_tint_light;
field public static final int system_surface_variant_dark = 17170592; // 0x10600a0
field public static final int system_surface_variant_light = 17170549; // 0x1060075
field public static final int system_tertiary_container_dark = 17170577; // 0x1060091
@@ -2437,6 +2452,7 @@ package android {
field public static final int primary = 16908300; // 0x102000c
field public static final int progress = 16908301; // 0x102000d
field public static final int redo = 16908339; // 0x1020033
+ field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final int remoteViewsMetricsId;
field public static final int replaceText = 16908340; // 0x1020034
field public static final int secondaryProgress = 16908303; // 0x102000f
field public static final int selectAll = 16908319; // 0x102001f
@@ -3816,7 +3832,7 @@ package android.accounts {
method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean notifyAccountAuthenticated(android.accounts.Account);
method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public String peekAuthToken(android.accounts.Account, String);
method @Deprecated @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
- method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+ method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @RequiresPermission(value="android.permission.REMOVE_ACCOUNTS", conditional=true) public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean removeAccountExplicitly(android.accounts.Account);
method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
@@ -4600,6 +4616,7 @@ package android.app {
method public void reportFullyDrawn();
method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
method public void requestFullscreenMode(int, @Nullable android.os.OutcomeReceiver<java.lang.Void,java.lang.Throwable>);
+ method @FlaggedApi("com.android.window.flags.enable_desktop_windowing_app_to_web_education") public final void requestOpenInBrowserEducation();
method public final void requestPermissions(@NonNull String[], int);
method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public final void requestPermissions(@NonNull String[], int, int);
method public final void requestShowKeyboardShortcuts();
@@ -4625,7 +4642,6 @@ package android.app {
method public void setInheritShowWhenLocked(boolean);
method public void setIntent(android.content.Intent);
method @FlaggedApi("android.security.content_uri_permission_apis") public void setIntent(@Nullable android.content.Intent, @Nullable android.app.ComponentCaller);
- method @FlaggedApi("com.android.window.flags.enable_desktop_windowing_app_to_web_education") public final void setLimitSystemEducationDialogs(boolean);
method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle);
method public final void setMediaController(android.media.session.MediaController);
method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams);
@@ -5096,8 +5112,11 @@ package android.app {
}
public class AppOpsManager {
- method @Deprecated public int checkOp(@NonNull String, int, @NonNull String);
- method @Deprecated public int checkOpNoThrow(@NonNull String, int, @NonNull String);
+ method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOp(@NonNull String, int, @NonNull String);
+ method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOp(@NonNull String, int, @NonNull String, @Nullable String);
+ method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpNoThrow(@NonNull String, int, @NonNull String, @Nullable String);
+ method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpNoThrow(@NonNull String, int, @NonNull String);
+ method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpRawNoThrow(@NonNull String, int, @NonNull String, @Nullable String);
method @Deprecated public void checkPackage(int, @NonNull String);
method @Deprecated public void finishOp(@NonNull String, int, @NonNull String);
method public void finishOp(@NonNull String, int, @NonNull String, @Nullable String);
@@ -5126,10 +5145,10 @@ package android.app {
method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener);
method public void stopWatchingActive(@NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
method public void stopWatchingMode(@NonNull android.app.AppOpsManager.OnOpChangedListener);
- method public int unsafeCheckOp(@NonNull String, int, @NonNull String);
- method public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String);
- method public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String);
- method public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String);
+ method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOp(@NonNull String, int, @NonNull String);
+ method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String);
+ method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String);
+ method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String);
field public static final int MODE_ALLOWED = 0; // 0x0
field public static final int MODE_DEFAULT = 3; // 0x3
field public static final int MODE_ERRORED = 2; // 0x2
@@ -6221,6 +6240,7 @@ package android.app {
}
public class KeyguardManager {
+ method @FlaggedApi("android.app.device_unlock_listener") @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addDeviceLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.DeviceLockedStateListener);
method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addKeyguardLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
@@ -6230,10 +6250,15 @@ package android.app {
method public boolean isKeyguardLocked();
method public boolean isKeyguardSecure();
method @Deprecated public android.app.KeyguardManager.KeyguardLock newKeyguardLock(String);
+ method @FlaggedApi("android.app.device_unlock_listener") @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeDeviceLockedStateListener(@NonNull android.app.KeyguardManager.DeviceLockedStateListener);
method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeKeyguardLockedStateListener(@NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
method public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
}
+ @FlaggedApi("android.app.device_unlock_listener") @java.lang.FunctionalInterface public static interface KeyguardManager.DeviceLockedStateListener {
+ method public void onDeviceLockedStateChanged(boolean);
+ }
+
public abstract static class KeyguardManager.KeyguardDismissCallback {
ctor public KeyguardManager.KeyguardDismissCallback();
method public void onDismissCancelled();
@@ -8075,8 +8100,10 @@ package android.app.admin {
method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeEnabled(@Nullable android.content.ComponentName);
+ method @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public int getAutoTimePolicy();
method @Deprecated public boolean getAutoTimeRequired();
method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeZoneEnabled(@Nullable android.content.ComponentName);
+ method @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public int getAutoTimeZonePolicy();
method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA, conditional=true) public boolean getCameraDisabled(@Nullable android.content.ComponentName);
@@ -8232,8 +8259,10 @@ package android.app.admin {
method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimeEnabled(@Nullable android.content.ComponentName, boolean);
+ method @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimePolicy(int);
method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@Nullable android.content.ComponentName, boolean);
+ method @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZonePolicy(int);
method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA, conditional=true) public void setCameraDisabled(@Nullable android.content.ComponentName, boolean);
@@ -8352,6 +8381,12 @@ package android.app.admin {
field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+ field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_DISABLED = 1; // 0x1
+ field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_ENABLED = 2; // 0x2
+ field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
+ field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_DISABLED = 1; // 0x1
+ field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_ENABLED = 2; // 0x2
+ field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_DISABLED = 1; // 0x1
field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_ENABLED = 2; // 0x2
field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
@@ -9859,6 +9894,8 @@ package android.appwidget {
field public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
field public static final String ACTION_APPWIDGET_RESTORED = "android.appwidget.action.APPWIDGET_RESTORED";
field public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
+ field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EVENT_CATEGORY_APPWIDGET = "android.appwidget";
+ field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EVENT_TYPE_WIDGET_INTERACTION = "widget_interaction";
field public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
field public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
field public static final String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds";
@@ -9868,6 +9905,10 @@ package android.appwidget {
field public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
field public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
field public static final String EXTRA_CUSTOM_INFO = "customInfo";
+ field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_CLICKED_VIEWS = "android.appwidget.extra.EVENT_CLICKED_VIEWS";
+ field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_DURATION_MS = "android.appwidget.extra.EVENT_DURATION_MS";
+ field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_POSITION_RECT = "android.appwidget.extra.EVENT_POSITION_RECT";
+ field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_SCROLLED_VIEWS = "android.appwidget.extra.EVENT_SCROLLED_VIEWS";
field public static final String EXTRA_HOST_ID = "hostId";
field public static final int INVALID_APPWIDGET_ID = 0; // 0x0
field public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
@@ -13113,9 +13154,9 @@ package android.content.pm {
method public void setAppLabel(@Nullable CharSequence);
method public void setAppPackageName(@Nullable String);
method public void setApplicationEnabledSettingPersistent();
+ method @FlaggedApi("android.content.pm.sdk_dependency_installer") public void setAutoInstallDependenciesEnabled(boolean);
method @Deprecated public void setAutoRevokePermissionsMode(boolean);
method public void setDontKillApp(boolean);
- method @FlaggedApi("android.content.pm.sdk_dependency_installer") public void setEnableAutoInstallDependencies(boolean);
method public void setInstallLocation(int);
method public void setInstallReason(int);
method public void setInstallScenario(int);
@@ -13366,6 +13407,7 @@ package android.content.pm {
field public static final String FEATURE_BACKUP = "android.software.backup";
field public static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
field public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
+ field @FlaggedApi("com.android.ranging.flags.ranging_cs_enabled") public static final String FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING = "android.hardware.bluetooth_le.channel_sounding";
field public static final String FEATURE_CAMERA = "android.hardware.camera";
field public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
field public static final String FEATURE_CAMERA_AR = "android.hardware.camera.ar";
@@ -13557,6 +13599,7 @@ package android.content.pm {
field public static final String PROPERTY_MEDIA_CAPABILITIES = "android.media.PROPERTY_MEDIA_CAPABILITIES";
field public static final String PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES = "android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES";
field public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE = "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE";
+ field @FlaggedApi("com.android.server.backup.enable_restricted_mode_changes") public static final String PROPERTY_USE_RESTRICTED_BACKUP_MODE = "android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE";
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
field public static final int SIGNATURE_MATCH = 0; // 0x0
field public static final int SIGNATURE_NEITHER_SIGNED = 1; // 0x1
@@ -13774,7 +13817,7 @@ package android.content.pm {
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, 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, android.Manifest.permission.UWB_RANGING, android.Manifest.permission.RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
- 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 @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled") @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, android.health.connect.HealthPermissions.READ_HEART_RATE, android.health.connect.HealthPermissions.READ_SKIN_TEMPERATURE, android.health.connect.HealthPermissions.READ_OXYGEN_SATURATION}) 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
@@ -13793,6 +13836,7 @@ package android.content.pm {
public final class SharedLibraryInfo implements android.os.Parcelable {
method public int describeContents();
+ method @FlaggedApi("android.content.pm.sdk_dependency_installer") @NonNull public java.util.List<java.lang.String> getCertDigests();
method @NonNull public android.content.pm.VersionedPackage getDeclaringPackage();
method @NonNull public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
method @IntRange(from=0xffffffff) public long getLongVersion();
@@ -17460,6 +17504,7 @@ package android.graphics {
method public void setFloatUniform(@NonNull String, @NonNull float[]);
method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter);
method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
+ method public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode);
method public void setIntUniform(@NonNull String, int);
method public void setIntUniform(@NonNull String, int, int);
method public void setIntUniform(@NonNull String, int, int, int);
@@ -17478,7 +17523,29 @@ package android.graphics {
method public void setFloatUniform(@NonNull String, float, float, float, float);
method public void setFloatUniform(@NonNull String, @NonNull float[]);
method public void setInputBuffer(@NonNull String, @NonNull android.graphics.BitmapShader);
+ method @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter);
+ method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
+ method @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode);
+ method public void setIntUniform(@NonNull String, int);
+ method public void setIntUniform(@NonNull String, int, int);
+ method public void setIntUniform(@NonNull String, int, int, int);
+ method public void setIntUniform(@NonNull String, int, int, int, int);
+ method public void setIntUniform(@NonNull String, @NonNull int[]);
+ }
+
+ @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public class RuntimeXfermode extends android.graphics.Xfermode {
+ ctor public RuntimeXfermode(@NonNull String);
+ method public void setColorUniform(@NonNull String, @ColorInt int);
+ method public void setColorUniform(@NonNull String, @ColorLong long);
+ method public void setColorUniform(@NonNull String, @NonNull android.graphics.Color);
+ method public void setFloatUniform(@NonNull String, float);
+ method public void setFloatUniform(@NonNull String, float, float);
+ method public void setFloatUniform(@NonNull String, float, float, float);
+ method public void setFloatUniform(@NonNull String, float, float, float, float);
+ method public void setFloatUniform(@NonNull String, @NonNull float[]);
+ method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter);
method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
+ method public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode);
method public void setIntUniform(@NonNull String, int);
method public void setIntUniform(@NonNull String, int, int);
method public void setIntUniform(@NonNull String, int, int, int);
@@ -18816,6 +18883,19 @@ package android.hardware {
field public static final int TRANSFER_UNSPECIFIED = 0; // 0x0
}
+ @FlaggedApi("android.hardware.flags.luts_api") public final class DisplayLuts {
+ ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts();
+ method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry);
+ method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry, @NonNull android.hardware.DisplayLuts.Entry);
+ }
+
+ @FlaggedApi("android.hardware.flags.luts_api") public static class DisplayLuts.Entry {
+ ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts.Entry(@NonNull float[], int, int);
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public float[] getBuffer();
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension();
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getSamplingKey();
+ }
+
public class GeomagneticField {
ctor public GeomagneticField(float, float, float, long);
method public float getDeclination();
@@ -18877,8 +18957,20 @@ package android.hardware {
field @FlaggedApi("android.media.codec.p210_format_support") public static final int YCBCR_P210 = 60; // 0x3c
}
+ @FlaggedApi("android.hardware.flags.luts_api") public final class LutProperties {
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension();
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public int[] getSamplingKeys();
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getSize();
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int ONE_DIMENSION = 1; // 0x1
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_CIE_Y = 2; // 0x2
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_MAX_RGB = 1; // 0x1
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_RGB = 0; // 0x0
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int THREE_DIMENSION = 3; // 0x3
+ }
+
@FlaggedApi("android.hardware.flags.overlayproperties_class_api") public final class OverlayProperties implements android.os.Parcelable {
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public int describeContents();
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.hardware.LutProperties[] getLutProperties();
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isCombinationSupported(int, int);
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isMixedColorSpacesSupported();
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -20618,8 +20710,14 @@ package android.hardware.display {
method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionMode();
method public int getMatchContentFrameRateUserPreference();
method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
+ method @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public void registerDisplayListener(@NonNull java.util.concurrent.Executor, long, @NonNull android.hardware.display.DisplayManager.DisplayListener);
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_ADDED = 1L; // 0x1L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_CHANGED = 4L; // 0x4L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_REFRESH_RATE = 8L; // 0x8L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_REMOVED = 2L; // 0x2L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_STATE = 16L; // 0x10L
field public static final int MATCH_CONTENT_FRAMERATE_ALWAYS = 2; // 0x2
field public static final int MATCH_CONTENT_FRAMERATE_NEVER = 0; // 0x0
field public static final int MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY = 1; // 0x1
@@ -21009,6 +21107,7 @@ package android.inputmethodservice {
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
method public boolean onGenericMotionEvent(android.view.MotionEvent);
+ method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
}
@@ -21026,6 +21125,7 @@ package android.inputmethodservice {
method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public boolean isEnabled();
method public boolean isRevoked();
+ method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent);
method public void revokeSelf();
method public void setEnabled(boolean);
}
@@ -21076,6 +21176,7 @@ package android.inputmethodservice {
method @Deprecated public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
method public android.view.View onCreateInputView();
method protected void onCurrentInputMethodSubtypeChanged(android.view.inputmethod.InputMethodSubtype);
+ method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") public void onCustomImeSwitcherButtonRequestedVisible(boolean);
method public void onDisplayCompletions(android.view.inputmethod.CompletionInfo[]);
method public boolean onEvaluateFullscreenMode();
method @CallSuper public boolean onEvaluateInputViewShown();
@@ -21124,6 +21225,7 @@ package android.inputmethodservice {
method public void setExtractView(android.view.View);
method public void setExtractViewShown(boolean);
method public void setInputView(android.view.View);
+ method @FlaggedApi("android.view.inputmethod.adaptive_handwriting_bounds") public final void setStylusHandwritingRegion(@NonNull android.graphics.Region);
method public final void setStylusHandwritingSessionTimeout(@NonNull java.time.Duration);
method public final boolean shouldOfferSwitchingToNextInputMethod();
method public void showStatusIcon(@DrawableRes int);
@@ -21477,6 +21579,7 @@ package android.media {
method public int getId();
method public CharSequence getProductName();
method @NonNull public int[] getSampleRates();
+ method @FlaggedApi("android.media.audio.speaker_layout_api") public int getSpeakerLayoutChannelMask();
method public int getType();
method public boolean isSink();
method public boolean isSource();
@@ -21965,7 +22068,7 @@ package android.media {
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.media.AudioAttributes getAudioAttributes();
- method @Nullable public android.media.AudioDeviceInfo getAudioDeviceInfo();
+ method @Deprecated @FlaggedApi("android.media.audio.routed_device_ids") @Nullable public android.media.AudioDeviceInfo getAudioDeviceInfo();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioPlaybackConfiguration> CREATOR;
}
@@ -22048,6 +22151,7 @@ package android.media {
method public android.media.AudioDeviceInfo getPreferredDevice();
method public int getRecordingState();
method public android.media.AudioDeviceInfo getRoutedDevice();
+ method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
method public int getSampleRate();
method public int getState();
method public int getTimestamp(@NonNull android.media.AudioTimestamp, int);
@@ -22142,6 +22246,7 @@ package android.media {
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public android.media.AudioDeviceInfo getPreferredDevice();
method public android.media.AudioDeviceInfo getRoutedDevice();
+ method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public default java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
}
@@ -22200,6 +22305,7 @@ package android.media {
method public int getPositionNotificationPeriod();
method public android.media.AudioDeviceInfo getPreferredDevice();
method public android.media.AudioDeviceInfo getRoutedDevice();
+ method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
method public int getSampleRate();
method @IntRange(from=1) public int getStartThresholdInFrames();
method public int getState();
@@ -23096,7 +23202,6 @@ package android.media {
method public boolean isVendor();
field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_MEMORY_SAFE = 1; // 0x1
field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_SANDBOXED = 0; // 0x0
- field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2; // 0x2
}
public static final class MediaCodecInfo.AudioCapabilities {
@@ -23413,6 +23518,18 @@ package android.media {
field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
field public static final int HEVCProfileMain10HDR10Plus = 8192; // 0x2000
field public static final int HEVCProfileMainStill = 4; // 0x4
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseAac = 16908290; // 0x1020002
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedAac = 17039362; // 0x1040002
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedFlac = 17039364; // 0x1040004
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedOpus = 17039361; // 0x1040001
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedPcm = 17039368; // 0x1040008
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseFlac = 16908292; // 0x1020004
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseOpus = 16908289; // 0x1020001
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBasePcm = 16908296; // 0x1020008
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimpleAac = 16842754; // 0x1010002
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimpleFlac = 16842756; // 0x1010004
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimpleOpus = 16842753; // 0x1010001
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimplePcm = 16842760; // 0x1010008
field public static final int MPEG2LevelH14 = 2; // 0x2
field public static final int MPEG2LevelHL = 3; // 0x3
field public static final int MPEG2LevelHP = 4; // 0x4
@@ -23987,7 +24104,6 @@ package android.media {
field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_MEMORY_SAFE = 2; // 0x2
field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_SANDBOXED = 1; // 0x1
- field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 4; // 0x4
field public static final String KEY_AAC_DRC_ALBUM_MODE = "aac-drc-album-mode";
field public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
field public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
@@ -24059,6 +24175,8 @@ package android.media {
field public static final String KEY_OPERATING_RATE = "operating-rate";
field public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
field public static final String KEY_PCM_ENCODING = "pcm-encoding";
+ field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String KEY_PICTURE_PROFILE_ID = "picture-profile-id";
+ field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String KEY_PICTURE_PROFILE_INSTANCE = "picture-profile-instance";
field public static final String KEY_PICTURE_TYPE = "picture-type";
field public static final String KEY_PIXEL_ASPECT_RATIO_HEIGHT = "sar-height";
field public static final String KEY_PIXEL_ASPECT_RATIO_WIDTH = "sar-width";
@@ -24111,6 +24229,7 @@ package android.media {
field public static final String MIMETYPE_AUDIO_FLAC = "audio/flac";
field public static final String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
field public static final String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
+ field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final String MIMETYPE_AUDIO_IAMF = "audio/iamf";
field public static final String MIMETYPE_AUDIO_IEC61937 = "audio/x-iec61937";
field public static final String MIMETYPE_AUDIO_MPEG = "audio/mpeg";
field public static final String MIMETYPE_AUDIO_MPEGH_BL_L3 = "audio/mhm1.03";
@@ -24368,6 +24487,7 @@ package android.media {
method @NonNull public android.media.PlaybackParams getPlaybackParams();
method public android.media.AudioDeviceInfo getPreferredDevice();
method public android.media.AudioDeviceInfo getRoutedDevice();
+ method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method @NonNull public android.media.SyncParams getSyncParams();
method @Nullable public android.media.MediaTimestamp getTimestamp();
@@ -24581,6 +24701,7 @@ package android.media {
method public android.os.PersistableBundle getMetrics();
method public android.media.AudioDeviceInfo getPreferredDevice();
method public android.media.AudioDeviceInfo getRoutedDevice();
+ method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
method public android.view.Surface getSurface();
method public boolean isPrivacySensitive();
method public void pause() throws java.lang.IllegalStateException;
@@ -25503,6 +25624,7 @@ package android.media {
method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
method public int getImmersiveAudioLevel();
+ method @FlaggedApi("android.media.audio.spatializer_capabilities") @NonNull public java.util.List<java.lang.Integer> getSpatializedChannelMasks();
method public boolean isAvailable();
method public boolean isEnabled();
method public boolean isHeadTrackerAvailable();
@@ -26963,6 +27085,192 @@ package android.media.projection {
}
+package android.media.quality {
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class AmbientBacklightEvent implements android.os.Parcelable {
+ ctor public AmbientBacklightEvent(int, @Nullable android.media.quality.AmbientBacklightMetadata);
+ method public int describeContents();
+ method public int getEventType();
+ method @Nullable public android.media.quality.AmbientBacklightMetadata getMetadata();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int AMBIENT_BACKLIGHT_EVENT_DISABLED = 2; // 0x2
+ field public static final int AMBIENT_BACKLIGHT_EVENT_ENABLED = 1; // 0x1
+ field public static final int AMBIENT_BACKLIGHT_EVENT_INTERRUPTED = 4; // 0x4
+ field public static final int AMBIENT_BACKLIGHT_EVENT_METADATA = 3; // 0x3
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.AmbientBacklightEvent> CREATOR;
+ }
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class AmbientBacklightMetadata implements android.os.Parcelable {
+ ctor public AmbientBacklightMetadata(@NonNull String, int, int, int, int, int, @NonNull int[]);
+ method public int describeContents();
+ method public int getColorFormat();
+ method public int getCompressAlgorithm();
+ method @IntRange(from=0) public int getHorizontalZonesNumber();
+ method @NonNull public String getPackageName();
+ method public int getSource();
+ method @IntRange(from=0) public int getVerticalZonesNumber();
+ method @NonNull public int[] getZonesColors();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.AmbientBacklightMetadata> CREATOR;
+ }
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class AmbientBacklightSettings implements android.os.Parcelable {
+ ctor public AmbientBacklightSettings(int, int, int, int, int, boolean, int);
+ method public int describeContents();
+ method public int getColorFormat();
+ method @IntRange(from=0) public int getHorizontalZonesNumber();
+ method @IntRange(from=1) public int getMaxFps();
+ method public int getSource();
+ method public int getThreshold();
+ method @IntRange(from=0) public int getVerticalZonesNumber();
+ method public boolean isLetterboxOmitted();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int ALGORITHM_NONE = 0; // 0x0
+ field public static final int ALGORITHM_RLE = 1; // 0x1
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.AmbientBacklightSettings> CREATOR;
+ field public static final int SOURCE_AUDIO = 1; // 0x1
+ field public static final int SOURCE_AUDIO_VIDEO = 3; // 0x3
+ field public static final int SOURCE_NONE = 0; // 0x0
+ field public static final int SOURCE_VIDEO = 2; // 0x2
+ }
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public class MediaQualityContract {
+ }
+
+ public static final class MediaQualityContract.PictureQuality {
+ field public static final String PARAMETER_BRIGHTNESS = "brightness";
+ field public static final String PARAMETER_CONTRAST = "contrast";
+ field public static final String PARAMETER_SATURATION = "saturation";
+ field public static final String PARAMETER_SHARPNESS = "sharpness";
+ }
+
+ public static final class MediaQualityContract.SoundQuality {
+ field public static final String PARAMETER_BALANCE = "balance";
+ field public static final String PARAMETER_BASS = "bass";
+ field public static final String PARAMETER_TREBLE = "treble";
+ }
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager {
+ method public void createPictureProfile(@NonNull android.media.quality.PictureProfile);
+ method public void createSoundProfile(@NonNull android.media.quality.SoundProfile);
+ method @NonNull public java.util.List<android.media.quality.PictureProfile> getAvailablePictureProfiles();
+ method @NonNull public java.util.List<android.media.quality.SoundProfile> getAvailableSoundProfiles();
+ method @NonNull public java.util.List<android.media.quality.ParamCapability> getParamCapabilities(@NonNull java.util.List<java.lang.String>);
+ method @Nullable public android.media.quality.PictureProfile getPictureProfile(int, @NonNull String);
+ method @Nullable public android.media.quality.SoundProfile getSoundProfile(int, @NonNull String);
+ method public boolean isAmbientBacklightEnabled();
+ method public boolean isAutoPictureQualityEnabled();
+ method public boolean isAutoSoundQualityEnabled();
+ method public boolean isSuperResolutionEnabled();
+ method public void registerAmbientBacklightCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.AmbientBacklightCallback);
+ method public void registerPictureProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.PictureProfileCallback);
+ method public void registerSoundProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.SoundProfileCallback);
+ method public void removePictureProfile(@NonNull String);
+ method public void removeSoundProfile(@NonNull String);
+ method public void setAmbientBacklightEnabled(boolean);
+ method public void setAmbientBacklightSettings(@NonNull android.media.quality.AmbientBacklightSettings);
+ method public void unregisterAmbientBacklightCallback(@NonNull android.media.quality.MediaQualityManager.AmbientBacklightCallback);
+ method public void unregisterPictureProfileCallback(@NonNull android.media.quality.MediaQualityManager.PictureProfileCallback);
+ method public void unregisterSoundProfileCallback(@NonNull android.media.quality.MediaQualityManager.SoundProfileCallback);
+ method public void updatePictureProfile(@NonNull String, @NonNull android.media.quality.PictureProfile);
+ method public void updateSoundProfile(@NonNull String, @NonNull android.media.quality.SoundProfile);
+ }
+
+ public abstract static class MediaQualityManager.AmbientBacklightCallback {
+ ctor public MediaQualityManager.AmbientBacklightCallback();
+ method public void onAmbientBacklightEvent(@NonNull android.media.quality.AmbientBacklightEvent);
+ }
+
+ public abstract static class MediaQualityManager.PictureProfileCallback {
+ ctor public MediaQualityManager.PictureProfileCallback();
+ method public void onError(int);
+ method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List<android.media.quality.ParamCapability>);
+ method public void onPictureProfileAdded(@NonNull String, @NonNull android.media.quality.PictureProfile);
+ method public void onPictureProfileRemoved(@NonNull String, @NonNull android.media.quality.PictureProfile);
+ method public void onPictureProfileUpdated(@NonNull String, @NonNull android.media.quality.PictureProfile);
+ }
+
+ public abstract static class MediaQualityManager.SoundProfileCallback {
+ ctor public MediaQualityManager.SoundProfileCallback();
+ method public void onError(int);
+ method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List<android.media.quality.ParamCapability>);
+ method public void onSoundProfileAdded(@NonNull String, @NonNull android.media.quality.SoundProfile);
+ method public void onSoundProfileRemoved(@NonNull String, @NonNull android.media.quality.SoundProfile);
+ method public void onSoundProfileUpdated(@NonNull String, @NonNull android.media.quality.SoundProfile);
+ }
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class ParamCapability implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.os.Bundle getCapabilities();
+ method @NonNull public String getParamName();
+ method public int getParamType();
+ method public boolean isSupported();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final String CAPABILITY_DEFAULT = "default";
+ field public static final String CAPABILITY_ENUM = "enum";
+ field public static final String CAPABILITY_MAX = "max";
+ field public static final String CAPABILITY_MIN = "min";
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.ParamCapability> CREATOR;
+ field public static final int TYPE_DOUBLE = 3; // 0x3
+ field public static final int TYPE_INT = 1; // 0x1
+ field public static final int TYPE_LONG = 2; // 0x2
+ field public static final int TYPE_STRING = 4; // 0x4
+ }
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class PictureProfile implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getInputId();
+ method @NonNull public String getName();
+ method @Nullable public String getPackageName();
+ method @NonNull public android.os.PersistableBundle getParameters();
+ method @Nullable public String getProfileId();
+ method public int getProfileType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.PictureProfile> CREATOR;
+ field public static final int ERROR_DUPLICATE = 2; // 0x2
+ field public static final int ERROR_INVALID_ARGUMENT = 3; // 0x3
+ field public static final int ERROR_NOT_ALLOWLISTED = 4; // 0x4
+ field public static final int ERROR_NO_PERMISSION = 1; // 0x1
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_APPLICATION = 2; // 0x2
+ field public static final int TYPE_SYSTEM = 1; // 0x1
+ }
+
+ public static final class PictureProfile.Builder {
+ ctor public PictureProfile.Builder(@NonNull String);
+ ctor public PictureProfile.Builder(@NonNull android.media.quality.PictureProfile);
+ method @NonNull public android.media.quality.PictureProfile build();
+ method @NonNull public android.media.quality.PictureProfile.Builder setParameters(@NonNull android.os.PersistableBundle);
+ }
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class SoundProfile implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getInputId();
+ method @NonNull public String getName();
+ method @Nullable public String getPackageName();
+ method @NonNull public android.os.PersistableBundle getParameters();
+ method @Nullable public String getProfileId();
+ method public int getProfileType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.SoundProfile> CREATOR;
+ field public static final int ERROR_DUPLICATE = 2; // 0x2
+ field public static final int ERROR_INVALID_ARGUMENT = 3; // 0x3
+ field public static final int ERROR_NOT_ALLOWLISTED = 4; // 0x4
+ field public static final int ERROR_NO_PERMISSION = 1; // 0x1
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_APPLICATION = 2; // 0x2
+ field public static final int TYPE_SYSTEM = 1; // 0x1
+ }
+
+ public static final class SoundProfile.Builder {
+ ctor public SoundProfile.Builder(@NonNull String);
+ ctor public SoundProfile.Builder(@NonNull android.media.quality.SoundProfile);
+ method @NonNull public android.media.quality.SoundProfile build();
+ method @NonNull public android.media.quality.SoundProfile.Builder setParameters(@NonNull android.os.PersistableBundle);
+ }
+
+}
+
package android.media.session {
public final class MediaController {
@@ -28512,6 +28820,8 @@ package android.media.tv.ad {
method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.ad.TvAdView.TvAdCallback);
method public void setOnUnhandledInputEventListener(@NonNull android.media.tv.ad.TvAdView.OnUnhandledInputEventListener);
method public boolean setTvView(@Nullable android.media.tv.TvView);
+ method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void setZOrderMediaOverlay(boolean);
+ method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void setZOrderOnTop(boolean);
method public void startAdService();
method public void stopAdService();
field public static final String ERROR_KEY_ERROR_CODE = "error_code";
@@ -28784,6 +29094,8 @@ package android.media.tv.interactive {
method public void setOnUnhandledInputEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener);
method public void setTeletextAppEnabled(boolean);
method public int setTvView(@Nullable android.media.tv.TvView);
+ method @FlaggedApi("android.media.tv.flags.tiaf_v_apis") public void setZOrderMediaOverlay(boolean);
+ method @FlaggedApi("android.media.tv.flags.tiaf_v_apis") public void setZOrderOnTop(boolean);
method public void startInteractiveApp();
method public void stopInteractiveApp();
field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
@@ -29823,6 +30135,7 @@ package android.net.vcn {
method @NonNull public java.util.List<android.net.vcn.VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities();
method public boolean hasGatewayOption(int);
method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled();
+ field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; // 0xffffffff
field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0
}
@@ -33296,6 +33609,14 @@ package android.os {
method public final android.os.CountDownTimer start();
}
+ @FlaggedApi("android.os.cpu_gpu_headrooms") public final class CpuHeadroomParams {
+ ctor public CpuHeadroomParams();
+ method public int getCalculationType();
+ method public void setCalculationType(int);
+ field public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1
+ field public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0
+ }
+
public final class CpuUsageInfo implements android.os.Parcelable {
method public int describeContents();
method public long getActive();
@@ -33543,6 +33864,14 @@ package android.os {
method public void onProgress(long);
}
+ @FlaggedApi("android.os.cpu_gpu_headrooms") public final class GpuHeadroomParams {
+ ctor public GpuHeadroomParams();
+ method public int getCalculationType();
+ method public void setCalculationType(int);
+ field public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1
+ field public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0
+ }
+
public class Handler {
ctor @Deprecated public Handler();
ctor @Deprecated public Handler(@Nullable android.os.Handler.Callback);
@@ -33613,7 +33942,7 @@ package android.os {
}
public interface IBinder {
- method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
+ method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
@@ -34244,6 +34573,7 @@ package android.os {
method public void finishBroadcast();
method public Object getBroadcastCookie(int);
method public E getBroadcastItem(int);
+ method @FlaggedApi("android.os.binder_frozen_state_change_callback") @Nullable public java.util.concurrent.Executor getExecutor();
method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getFrozenCalleePolicy();
method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getMaxQueueSize();
method public Object getRegisteredCallbackCookie(int);
@@ -34264,6 +34594,7 @@ package android.os {
@FlaggedApi("android.os.binder_frozen_state_change_callback") public static final class RemoteCallbackList.Builder<E extends android.os.IInterface> {
ctor public RemoteCallbackList.Builder(int);
method @NonNull public android.os.RemoteCallbackList<E> build();
+ method @NonNull public android.os.RemoteCallbackList.Builder setExecutor(@NonNull java.util.concurrent.Executor);
method @NonNull public android.os.RemoteCallbackList.Builder setInterfaceDiedCallback(@NonNull android.os.RemoteCallbackList.Builder.InterfaceDiedCallback<E>);
method @NonNull public android.os.RemoteCallbackList.Builder setMaxQueueSize(int);
}
@@ -34643,8 +34974,6 @@ package android.os {
method public static android.os.VibrationEffect createWaveform(long[], int[], int);
method public int describeContents();
method @NonNull public static android.os.VibrationEffect.Composition startComposition();
- method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope();
- method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(@FloatRange(from=0) float);
field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect> CREATOR;
field public static final int DEFAULT_AMPLITUDE = -1; // 0xffffffff
field public static final int EFFECT_CLICK = 0; // 0x0
@@ -34653,11 +34982,21 @@ package android.os {
field public static final int EFFECT_TICK = 2; // 0x2
}
+ @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public static final class VibrationEffect.BasicEnvelopeBuilder {
+ ctor public VibrationEffect.BasicEnvelopeBuilder();
+ method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.BasicEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0, to=1) float, long);
+ method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect build();
+ method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.BasicEnvelopeBuilder setInitialSharpness(@FloatRange(from=0, to=1) float);
+ }
+
public static final class VibrationEffect.Composition {
method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int);
method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float);
method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
+ method @FlaggedApi("android.os.vibrator.primitive_composition_absolute_delay") @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int, int);
method @NonNull public android.os.VibrationEffect compose();
+ field @FlaggedApi("android.os.vibrator.primitive_composition_absolute_delay") public static final int DELAY_TYPE_PAUSE = 0; // 0x0
+ field @FlaggedApi("android.os.vibrator.primitive_composition_absolute_delay") public static final int DELAY_TYPE_RELATIVE_START_OFFSET = 1; // 0x1
field public static final int PRIMITIVE_CLICK = 1; // 0x1
field public static final int PRIMITIVE_LOW_TICK = 8; // 0x8
field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6
@@ -34669,8 +35008,10 @@ package android.os {
}
@FlaggedApi("android.os.vibrator.normalized_pwle_effects") public static final class VibrationEffect.WaveformEnvelopeBuilder {
- method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0) float, int);
+ ctor public VibrationEffect.WaveformEnvelopeBuilder();
+ method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0) float, long);
method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect build();
+ method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder setInitialFrequencyHz(@FloatRange(from=0) float);
}
public abstract class Vibrator {
@@ -34680,12 +35021,9 @@ package android.os {
method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public boolean areEnvelopeEffectsSupported();
method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...);
method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel();
+ method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.vibrator.VibratorEnvelopeEffectInfo getEnvelopeEffectInfo();
method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @Nullable public android.os.vibrator.VibratorFrequencyProfile getFrequencyProfile();
method public int getId();
- method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectControlPointDurationMillis();
- method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectDurationMillis();
- method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectSize();
- method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMinEnvelopeEffectControlPointDurationMillis();
method @NonNull public int[] getPrimitiveDurations(@NonNull int...);
method public float getQFactor();
method public float getResonantFrequency();
@@ -34793,6 +35131,10 @@ package android.os.health {
}
public class SystemHealthManager {
+ method @FlaggedApi("android.os.cpu_gpu_headrooms") @FloatRange(from=0.0f, to=100.0f) public float getCpuHeadroom(@Nullable android.os.CpuHeadroomParams);
+ method @FlaggedApi("android.os.cpu_gpu_headrooms") public long getCpuHeadroomMinIntervalMillis();
+ method @FlaggedApi("android.os.cpu_gpu_headrooms") @FloatRange(from=0.0f, to=100.0f) public float getGpuHeadroom(@Nullable android.os.GpuHeadroomParams);
+ method @FlaggedApi("android.os.cpu_gpu_headrooms") public long getGpuHeadroomMinIntervalMillis();
method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getPowerMonitorReadings(@NonNull java.util.List<android.os.PowerMonitor>, @Nullable java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.os.PowerMonitorReadings,java.lang.RuntimeException>);
method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getSupportedPowerMonitors(@Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.os.PowerMonitor>>);
method public android.os.health.HealthStats takeMyUidSnapshot();
@@ -35036,6 +35378,16 @@ package android.os.strictmode {
package android.os.vibrator {
+ @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public final class VibratorEnvelopeEffectInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getMaxControlPointDurationMillis();
+ method public long getMaxDurationMillis();
+ method public int getMaxSize();
+ method public long getMinControlPointDurationMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.VibratorEnvelopeEffectInfo> CREATOR;
+ }
+
@FlaggedApi("android.os.vibrator.normalized_pwle_effects") public final class VibratorFrequencyProfile {
method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.util.SparseArray<java.lang.Float> getFrequenciesOutputAcceleration();
method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @Nullable public android.util.Range<java.lang.Float> getFrequencyRange(float);
@@ -37361,7 +37713,6 @@ package android.provider {
}
@FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState {
- ctor public ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState(int, @Nullable android.accounts.Account);
method @Nullable public android.accounts.Account getAccount();
method public int getState();
method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofCloud(@NonNull android.accounts.Account);
@@ -40654,6 +41005,7 @@ package android.service.autofill {
method public int describeContents();
method @Deprecated @Nullable public android.os.Bundle getClientState();
method @Nullable public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getSessionId();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR;
}
@@ -40663,10 +41015,12 @@ package android.service.autofill {
method @Nullable public android.os.Bundle getClientState();
method @Nullable public String getDatasetId();
method @NonNull public java.util.Map<android.view.autofill.AutofillId,android.service.autofill.FieldClassification> getFieldsClassification();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") @Nullable public android.view.autofill.AutofillId getFocusedId();
method @NonNull public java.util.Set<java.lang.String> getIgnoredDatasetIds();
method @NonNull public java.util.Map<android.view.autofill.AutofillId,java.util.Set<java.lang.String>> getManuallyEnteredField();
method public int getNoSaveUiReason();
method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") @NonNull public java.util.Set<java.lang.String> getShownDatasetIds();
method public int getType();
method public int getUiType();
field public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6; // 0x6
@@ -40675,6 +41029,7 @@ package android.service.autofill {
field public static final int NO_SAVE_UI_REASON_NONE = 0; // 0x0
field public static final int NO_SAVE_UI_REASON_NO_SAVE_INFO = 1; // 0x1
field public static final int NO_SAVE_UI_REASON_NO_VALUE_CHANGED = 4; // 0x4
+ field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int NO_SAVE_UI_REASON_USING_CREDMAN = 7; // 0x7
field public static final int NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG = 2; // 0x2
field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4
@@ -40683,6 +41038,7 @@ package android.service.autofill {
field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6
+ field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int UI_TYPE_CREDMAN = 4; // 0x4
field public static final int UI_TYPE_DIALOG = 3; // 0x3
field public static final int UI_TYPE_INLINE = 2; // 0x2
field public static final int UI_TYPE_MENU = 1; // 0x1
@@ -40702,7 +41058,7 @@ package android.service.autofill {
field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
field public static final int FLAG_COMPATIBILITY_MODE_REQUEST = 2; // 0x2
field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
- field public static final int FLAG_SUPPORTS_FILL_DIALOG = 64; // 0x40
+ field @Deprecated @FlaggedApi("android.service.autofill.fill_dialog_improvements") public static final int FLAG_SUPPORTS_FILL_DIALOG = 64; // 0x40
}
public final class FillResponse implements android.os.Parcelable {
@@ -40964,6 +41320,18 @@ package android.service.carrier {
method @Deprecated public void onSendTextSms(@NonNull String, int, @NonNull String, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
method public void onSendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 606; // 0x25e
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED = 610; // 0x262
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE = 603; // 0x25b
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 609; // 0x261
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN = 601; // 0x259
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 608; // 0x260
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR = 604; // 0x25c
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 611; // 0x263
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK = 607; // 0x25f
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_RETRY = 605; // 0x25d
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 602; // 0x25a
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED = 600; // 0x258
field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
@@ -40971,7 +41339,38 @@ package android.service.carrier {
field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE = 2; // 0x2
field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
field public static final int SEND_STATUS_ERROR = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 406; // 0x196
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_DATA_DISABLED = 410; // 0x19a
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_HTTP_FAILURE = 403; // 0x193
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 409; // 0x199
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INVALID_APN = 401; // 0x191
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 408; // 0x198
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_IO_ERROR = 404; // 0x194
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 411; // 0x19b
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK = 407; // 0x197
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_RETRY = 405; // 0x195
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 402; // 0x192
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_UNSPECIFIED = 400; // 0x190
field public static final int SEND_STATUS_OK = 0; // 0x0
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_CANCELLED = 215; // 0xd7
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ENCODING_ERROR = 212; // 0xd4
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE = 204; // 0xcc
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE = 200; // 0xc8
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED = 203; // 0xcb
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_NO_SERVICE = 202; // 0xca
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_NULL_PDU = 201; // 0xc9
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 206; // 0xce
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 205; // 0xcd
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_ARGUMENTS = 208; // 0xd0
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS = 213; // 0xd5
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_SMS_FORMAT = 210; // 0xd2
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_STATE = 209; // 0xd1
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_NETWORK_ERROR = 211; // 0xd3
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_NETWORK_REJECT = 207; // 0xcf
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED = 214; // 0xd6
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED = 216; // 0xd8
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY = 217; // 0xd9
+ field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED = 218; // 0xda
field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
field public static final String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
}
@@ -41968,6 +42367,7 @@ package android.service.quickaccesswallet {
public abstract class QuickAccessWalletService extends android.app.Service {
ctor public QuickAccessWalletService();
+ method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") @Nullable public android.app.PendingIntent getGestureTargetActivityPendingIntent();
method @Nullable public android.app.PendingIntent getTargetActivityPendingIntent();
method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onWalletCardSelected(@NonNull android.service.quickaccesswallet.SelectWalletCardRequest);
@@ -42194,7 +42594,7 @@ package android.service.settings.preferences {
method @NonNull public java.util.List<java.lang.String> getBreadcrumbs();
method @NonNull public android.os.Bundle getExtras();
method @NonNull public String getKey();
- method @Nullable public android.app.PendingIntent getLaunchIntent();
+ method @Nullable public android.content.Intent getLaunchIntent();
method @NonNull public java.util.List<java.lang.String> getReadPermissions();
method @NonNull public String getScreenKey();
method @Nullable public String getSummary();
@@ -42219,7 +42619,7 @@ package android.service.settings.preferences {
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setBreadcrumbs(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setEnabled(boolean);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setExtras(@NonNull android.os.Bundle);
- method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setLaunchIntent(@Nullable android.app.PendingIntent);
+ method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setLaunchIntent(@Nullable android.content.Intent);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setReadPermissions(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setRestricted(boolean);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setSummary(@Nullable String);
@@ -42239,19 +42639,18 @@ package android.service.settings.preferences {
}
@FlaggedApi("com.android.settingslib.flags.settings_catalyst") public class SettingsPreferenceServiceClient implements java.lang.AutoCloseable {
- ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String);
+ ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.service.settings.preferences.SettingsPreferenceServiceClient,java.lang.Exception>);
method public void close();
method public void getAllPreferenceMetadata(@NonNull android.service.settings.preferences.MetadataRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.service.settings.preferences.MetadataResult,java.lang.Exception>);
method public void getPreferenceValue(@NonNull android.service.settings.preferences.GetValueRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.service.settings.preferences.GetValueResult,java.lang.Exception>);
method public void setPreferenceValue(@NonNull android.service.settings.preferences.SetValueRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.service.settings.preferences.SetValueResult,java.lang.Exception>);
- method public void start();
- method public void stop();
}
@FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class SettingsPreferenceValue implements android.os.Parcelable {
method public int describeContents();
method public boolean getBooleanValue();
method public double getDoubleValue();
+ method public int getIntValue();
method public long getLongValue();
method @Nullable public String getStringValue();
method public int getType();
@@ -42259,6 +42658,7 @@ package android.service.settings.preferences {
field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.SettingsPreferenceValue> CREATOR;
field public static final int TYPE_BOOLEAN = 0; // 0x0
field public static final int TYPE_DOUBLE = 2; // 0x2
+ field public static final int TYPE_INT = 4; // 0x4
field public static final int TYPE_LONG = 1; // 0x1
field public static final int TYPE_STRING = 3; // 0x3
}
@@ -42268,6 +42668,7 @@ package android.service.settings.preferences {
method @NonNull public android.service.settings.preferences.SettingsPreferenceValue build();
method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setBooleanValue(boolean);
method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setDoubleValue(double);
+ method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setIntValue(int);
method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setLongValue(long);
method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setStringValue(@Nullable String);
}
@@ -46645,6 +47046,8 @@ package android.telephony {
method public long getDataUsageBytes();
method public long getDataUsageTime();
method @NonNull public int[] getNetworkTypes();
+ method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") @Nullable public java.time.ZonedDateTime getPlanEndDate();
+ method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public int getSubscriptionStatus();
method @Nullable public CharSequence getSummary();
method @Nullable public CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
@@ -46655,6 +47058,11 @@ package android.telephony {
field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0
field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2
field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff
+ field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_ACTIVE = 1; // 0x1
+ field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_INACTIVE = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_SUSPENDED = 4; // 0x4
+ field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_TRIAL = 3; // 0x3
+ field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_UNKNOWN = 0; // 0x0
field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
}
@@ -46666,6 +47074,7 @@ package android.telephony {
method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int);
method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long);
method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@NonNull int[]);
+ method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") @NonNull public android.telephony.SubscriptionPlan.Builder setSubscriptionStatus(int);
method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence);
method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence);
}
@@ -49645,6 +50054,14 @@ package android.text.style {
method public abstract void updateMeasureState(@NonNull android.text.TextPaint);
}
+ @FlaggedApi("android.view.inputmethod.writing_tools") public final class NoWritingToolsSpan implements android.text.ParcelableSpan {
+ ctor public NoWritingToolsSpan();
+ method public int describeContents();
+ method public int getSpanTypeId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.text.style.NoWritingToolsSpan> CREATOR;
+ }
+
public interface ParagraphStyle {
}
@@ -50035,9 +50452,9 @@ package android.text.style {
public static class TtsSpan.TimeBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.TimeBuilder> {
ctor public TtsSpan.TimeBuilder();
ctor public TtsSpan.TimeBuilder(int, int);
- method public android.text.style.TtsSpan.TimeBuilder setHours(int);
- method public android.text.style.TtsSpan.TimeBuilder setMinutes(int);
- method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.TimeBuilder setSeconds(int);
+ method public android.text.style.TtsSpan.TimeBuilder setHours(@IntRange(from=0, to=24) int);
+ method public android.text.style.TtsSpan.TimeBuilder setMinutes(@IntRange(from=0, to=59) int);
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.TimeBuilder setSeconds(@IntRange(from=0, to=59) int);
}
public static class TtsSpan.VerbatimBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.VerbatimBuilder> {
@@ -51396,6 +51813,7 @@ package android.view {
method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
method public default int getBufferTransformHint();
method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken getInputTransferToken();
+ method @FlaggedApi("com.android.window.flags.jank_api") @NonNull public default android.view.SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.OnJankDataListener);
method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
method public default void setChildBoundingInsets(@NonNull android.graphics.Rect);
method public default void setTouchableRegion(@Nullable android.graphics.Region);
@@ -51519,7 +51937,7 @@ package android.view {
method public int getState();
method @FlaggedApi("com.android.server.display.feature.flags.enable_get_suggested_frame_rate") public float getSuggestedFrameRate(int);
method public android.view.Display.Mode[] getSupportedModes();
- method @Deprecated public float[] getSupportedRefreshRates();
+ method @FlaggedApi("com.android.server.display.feature.flags.enable_get_supported_refresh_rates") @NonNull public float[] getSupportedRefreshRates();
method @Deprecated public int getWidth();
method @FlaggedApi("com.android.server.display.feature.flags.enable_has_arr_support") public boolean hasArrSupport();
method public boolean isHdr();
@@ -51653,6 +52071,7 @@ package android.view {
field public static final int DEADLINE = 13; // 0xd
field public static final int DRAW_DURATION = 4; // 0x4
field public static final int FIRST_DRAW_FRAME = 9; // 0x9
+ field @FlaggedApi("com.android.window.flags.jank_api") public static final int FRAME_TIMELINE_VSYNC_ID = 14; // 0xe
field public static final int GPU_DURATION = 12; // 0xc
field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
field public static final int INTENDED_VSYNC_TIMESTAMP = 10; // 0xa
@@ -53090,6 +53509,26 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Builder setParent(@Nullable android.view.SurfaceControl);
}
+ @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.JankData {
+ method public long getActualAppFrameTimeNanos();
+ method public int getJankType();
+ method public long getScheduledAppFrameTimeNanos();
+ method public long getVsyncId();
+ field public static final int JANK_APPLICATION = 2; // 0x2
+ field public static final int JANK_COMPOSER = 1; // 0x1
+ field public static final int JANK_NONE = 0; // 0x0
+ field public static final int JANK_OTHER = 4; // 0x4
+ }
+
+ @FlaggedApi("com.android.window.flags.jank_api") public static interface SurfaceControl.OnJankDataListener {
+ method public void onJankDataAvailable(@NonNull java.util.List<android.view.SurfaceControl.JankData>);
+ }
+
+ @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.OnJankDataListenerRegistration {
+ method public void flush();
+ method public void removeAfter(long);
+ }
+
public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable {
ctor public SurfaceControl.Transaction();
method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
@@ -53107,6 +53546,7 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence, @Nullable java.util.function.Consumer<android.hardware.SyncFence>);
method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int);
+ method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") @NonNull public android.view.SurfaceControl.Transaction setContentPriority(@NonNull android.view.SurfaceControl, int);
method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
method @NonNull public android.view.SurfaceControl.Transaction setDamageRegion(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Region);
method @NonNull public android.view.SurfaceControl.Transaction setDataSpace(@NonNull android.view.SurfaceControl, int);
@@ -53119,6 +53559,7 @@ package android.view {
method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setFrameTimeline(long);
method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.view.SurfaceControl.Transaction setLuts(@NonNull android.view.SurfaceControl, @Nullable android.hardware.DisplayLuts);
method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float);
method @NonNull public android.view.SurfaceControl.Transaction setScale(@NonNull android.view.SurfaceControl, float, float);
@@ -54793,6 +55234,8 @@ package android.view {
method public abstract void setTransformation(android.graphics.Matrix);
method public abstract void setVisibility(int);
method public abstract void setWebDomain(@Nullable String);
+ field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE";
+ field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER";
}
public abstract static class ViewStructure.HtmlInfo {
@@ -56052,6 +56495,7 @@ package android.view.accessibility {
method public float getMin();
method public int getType();
method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
+ field @FlaggedApi("android.view.accessibility.indeterminate_range_info") @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.RangeInfo INDETERMINATE;
field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
field @FlaggedApi("android.view.accessibility.indeterminate_range_info") public static final int RANGE_TYPE_INDETERMINATE = 3; // 0x3
field public static final int RANGE_TYPE_INT = 0; // 0x0
@@ -56515,6 +56959,11 @@ package android.view.autofill {
public final class AutofillId implements android.os.Parcelable {
method @NonNull public static android.view.autofill.AutofillId create(@NonNull android.view.View, int);
method public int describeContents();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getAutofillVirtualId();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getSessionId();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getViewId();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") public boolean isInAutofillSession();
+ method @FlaggedApi("android.service.autofill.autofill_w_metrics") public boolean isVirtual();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.autofill.AutofillId> CREATOR;
}
@@ -56543,13 +56992,13 @@ package android.view.autofill {
method public void notifyViewExited(@NonNull android.view.View, int);
method public void notifyViewVisibilityChanged(@NonNull android.view.View, boolean);
method public void notifyViewVisibilityChanged(@NonNull android.view.View, int, boolean);
- method public void notifyVirtualViewsReady(@NonNull android.view.View, @NonNull android.util.SparseArray<android.view.autofill.VirtualViewFillInfo>);
+ method @Deprecated @FlaggedApi("android.service.autofill.fill_dialog_improvements") public void notifyVirtualViewsReady(@NonNull android.view.View, @NonNull android.util.SparseArray<android.view.autofill.VirtualViewFillInfo>);
method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
method public void requestAutofill(@NonNull android.view.View);
method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
method public void setUserData(@Nullable android.service.autofill.UserData);
- method public boolean showAutofillDialog(@NonNull android.view.View);
- method public boolean showAutofillDialog(@NonNull android.view.View, int);
+ method @Deprecated @FlaggedApi("android.service.autofill.fill_dialog_improvements") public boolean showAutofillDialog(@NonNull android.view.View);
+ method @Deprecated @FlaggedApi("android.service.autofill.fill_dialog_improvements") public boolean showAutofillDialog(@NonNull android.view.View, int);
method public void unregisterCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
field public static final String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
@@ -56902,6 +57351,7 @@ package android.view.inputmethod {
ctor public EditorInfo();
method public int describeContents();
method public void dump(android.util.Printer, String);
+ method @FlaggedApi("android.view.inputmethod.public_autofill_id_in_editorinfo") @Nullable public android.view.autofill.AutofillId getAutofillId();
method @Nullable public CharSequence getInitialSelectedText(int);
method @Nullable public android.view.inputmethod.SurroundingText getInitialSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int);
method @Nullable public CharSequence getInitialTextAfterCursor(@IntRange(from=0) int, int);
@@ -56910,13 +57360,16 @@ package android.view.inputmethod {
method @NonNull public java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>> getSupportedHandwritingGesturePreviews();
method @NonNull public java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>> getSupportedHandwritingGestures();
method @FlaggedApi("android.view.inputmethod.editorinfo_handwriting_enabled") public boolean isStylusHandwritingEnabled();
+ method @FlaggedApi("android.view.inputmethod.writing_tools") public boolean isWritingToolsEnabled();
method public final void makeCompatible(int);
+ method @FlaggedApi("android.view.inputmethod.public_autofill_id_in_editorinfo") public void setAutofillId(@Nullable android.view.autofill.AutofillId);
method public void setInitialSurroundingSubText(@NonNull CharSequence, int);
method public void setInitialSurroundingText(@NonNull CharSequence);
method public void setInitialToolType(int);
method @FlaggedApi("android.view.inputmethod.editorinfo_handwriting_enabled") public void setStylusHandwritingEnabled(boolean);
method public void setSupportedHandwritingGesturePreviews(@NonNull java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>>);
method public void setSupportedHandwritingGestures(@NonNull java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>>);
+ method @FlaggedApi("android.view.inputmethod.writing_tools") public void setWritingToolsEnabled(boolean);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorInfo> CREATOR;
field public static final int IME_ACTION_DONE = 6; // 0x6
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index 4ada53e1bf34..ad5bd31828e0 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -1,4 +1,10 @@
// Baseline format: 1.0
+ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_TYPE:
+ Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE`
+ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER:
+ Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`
+
+
BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED:
Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior
BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED:
@@ -1185,6 +1191,10 @@ UnflaggedApi: android.R.dimen#system_corner_radius_xlarge:
New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xlarge
UnflaggedApi: android.R.dimen#system_corner_radius_xsmall:
New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xsmall
+UnflaggedApi: android.R.integer#status_bar_notification_info_maxnum:
+ Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.integer.status_bar_notification_info_maxnum
+UnflaggedApi: android.R.string#status_bar_notification_info_overflow:
+ Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.string.status_bar_notification_info_overflow
UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INTERNAL_ERROR:
New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INTERNAL_ERROR
UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INVALID:
@@ -1477,7 +1487,6 @@ UnflaggedApi: android.graphics.text.PositionedGlyphs#getItalicOverride(int):
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getItalicOverride(int)
UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
-
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_CAR:
New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_CAR
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_COMPUTER:
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index bc73220cb4c1..1a949d84c052 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -251,6 +251,10 @@ package android.media.session {
package android.net {
+ @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class ConnectivityFrameworkInitializerBaklava {
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static void registerServiceWrappers();
+ }
+
public class LocalSocket implements java.io.Closeable {
ctor public LocalSocket(@NonNull java.io.FileDescriptor);
}
@@ -310,6 +314,25 @@ package android.net.netstats {
}
+package android.net.vcn {
+
+ @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class VcnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int describeContents();
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public long getApplicableRedactions();
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int getMinUdpPort4500NatTimeoutSeconds();
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.TransportInfo makeCopy(long);
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnTransportInfo> CREATOR;
+ }
+
+ @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final class VcnTransportInfo.Builder {
+ ctor @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public VcnTransportInfo.Builder();
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo build();
+ method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int);
+ }
+
+}
+
package android.net.wifi {
public final class WifiMigration {
@@ -379,6 +402,13 @@ package android.os {
field public static final int DEVICE_INITIAL_SDK_INT;
}
+ public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
+ method @FlaggedApi("android.os.enable_has_binders") public int hasBinders();
+ field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_NOT_PRESENT = 0; // 0x0
+ field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_PRESENT = 1; // 0x1
+ field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_UNKNOWN = 2; // 0x2
+ }
+
public class Handler {
method @FlaggedApi("android.os.mainline_vcn_platform_api") public final boolean hasMessagesOrCallbacks();
method @FlaggedApi("android.os.mainline_vcn_platform_api") public final void removeCallbacksAndEqualMessages(@Nullable Object);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f9ef62f6b2e8..5c0b22792348 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -34,6 +34,7 @@ package android {
field public static final String ACCESS_VIBRATOR_STATE = "android.permission.ACCESS_VIBRATOR_STATE";
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final String ADD_ALWAYS_UNLOCKED_DISPLAY = "android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY";
+ field @FlaggedApi("android.companion.virtualdevice.flags.enable_limited_vdm_role") public static final String ADD_MIRROR_DISPLAY = "android.permission.ADD_MIRROR_DISPLAY";
field public static final String ADD_TRUSTED_DISPLAY = "android.permission.ADD_TRUSTED_DISPLAY";
field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
@@ -57,6 +58,7 @@ package android {
field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
field public static final String BIND_CONTENT_SUGGESTIONS_SERVICE = "android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE";
+ field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String BIND_DEPENDENCY_INSTALLER = "android.permission.BIND_DEPENDENCY_INSTALLER";
field public static final String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
field public static final String BIND_DISPLAY_HASHING_SERVICE = "android.permission.BIND_DISPLAY_HASHING_SERVICE";
field @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") public static final String BIND_DOMAIN_SELECTION_SERVICE = "android.permission.BIND_DOMAIN_SELECTION_SERVICE";
@@ -68,6 +70,7 @@ package android {
field public static final String BIND_GBA_SERVICE = "android.permission.BIND_GBA_SERVICE";
field public static final String BIND_HOTWORD_DETECTION_SERVICE = "android.permission.BIND_HOTWORD_DETECTION_SERVICE";
field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
+ field @FlaggedApi("android.security.afl_api") public static final String BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE = "android.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE";
field public static final String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
field public static final String BIND_MUSIC_RECOGNITION_SERVICE = "android.permission.BIND_MUSIC_RECOGNITION_SERVICE";
field public static final String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
@@ -92,7 +95,6 @@ package android {
field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE";
field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
- field @FlaggedApi("android.content.pm.verification_service") public static final String BIND_VERIFICATION_AGENT = "android.permission.BIND_VERIFICATION_AGENT";
field public static final String BIND_VISUAL_QUERY_DETECTION_SERVICE = "android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE";
field public static final String BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE = "android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE";
field public static final String BIND_WEARABLE_SENSING_SERVICE = "android.permission.BIND_WEARABLE_SENSING_SERVICE";
@@ -101,6 +103,7 @@ package android {
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
+ field @FlaggedApi("android.media.audio.concurrent_audio_record_bypass_permission") public static final String BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION = "android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION";
field public static final String BYPASS_ROLE_QUALIFICATION = "android.permission.BYPASS_ROLE_QUALIFICATION";
field public static final String CALL_AUDIO_INTERCEPTION = "android.permission.CALL_AUDIO_INTERCEPTION";
field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
@@ -132,6 +135,7 @@ package android {
field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
field public static final String CONTROL_OEM_PAID_NETWORK_PREFERENCE = "android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE";
field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN";
+ field @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") public static final String COPY_ACCOUNTS = "android.permission.COPY_ACCOUNTS";
field public static final String CREATE_USERS = "android.permission.CREATE_USERS";
field public static final String CREATE_VIRTUAL_DEVICE = "android.permission.CREATE_VIRTUAL_DEVICE";
field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
@@ -164,6 +168,7 @@ package android {
field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
field @Deprecated public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
+ field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String INSTALL_DEPENDENCY_SHARED_LIBRARIES = "android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES";
field public static final String INSTALL_DPC_PACKAGES = "android.permission.INSTALL_DPC_PACKAGES";
field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
field public static final String INSTALL_EXISTING_PACKAGES = "com.android.permission.INSTALL_EXISTING_PACKAGES";
@@ -189,6 +194,7 @@ package android {
field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS";
+ field @FlaggedApi("android.security.aapm_api") public static final String MANAGE_ADVANCED_PROTECTION_MODE = "android.permission.MANAGE_ADVANCED_PROTECTION_MODE";
field public static final String MANAGE_APP_HIBERNATION = "android.permission.MANAGE_APP_HIBERNATION";
field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
@@ -214,6 +220,7 @@ package android {
field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE = "android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE";
field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String MANAGE_GLOBAL_SOUND_QUALITY_SERVICE = "android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE";
field public static final String MANAGE_HOTWORD_DETECTION = "android.permission.MANAGE_HOTWORD_DETECTION";
+ field @FlaggedApi("android.security.afl_api") public static final String MANAGE_INTRUSION_DETECTION_STATE = "android.permission.MANAGE_INTRUSION_DETECTION_STATE";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final String MANAGE_LOW_POWER_STANDBY = "android.permission.MANAGE_LOW_POWER_STANDBY";
field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
@@ -225,6 +232,7 @@ package android {
field public static final String MANAGE_ROTATION_RESOLVER = "android.permission.MANAGE_ROTATION_RESOLVER";
field public static final String MANAGE_SAFETY_CENTER = "android.permission.MANAGE_SAFETY_CENTER";
field public static final String MANAGE_SEARCH_UI = "android.permission.MANAGE_SEARCH_UI";
+ field @FlaggedApi("android.security.secure_lockdown") public static final String MANAGE_SECURE_LOCK_DEVICE = "android.permission.MANAGE_SECURE_LOCK_DEVICE";
field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
field public static final String MANAGE_SMARTSPACE = "android.permission.MANAGE_SMARTSPACE";
field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
@@ -307,6 +315,7 @@ package android {
field public static final String READ_GLOBAL_APP_SEARCH_DATA = "android.permission.READ_GLOBAL_APP_SEARCH_DATA";
field @FlaggedApi("android.content.pm.get_resolved_apk_path") public static final String READ_INSTALLED_SESSION_PATHS = "android.permission.READ_INSTALLED_SESSION_PATHS";
field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
+ field @FlaggedApi("android.security.afl_api") public static final String READ_INTRUSION_DETECTION_STATE = "android.permission.READ_INTRUSION_DETECTION_STATE";
field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
field public static final String READ_PEOPLE_DATA = "android.permission.READ_PEOPLE_DATA";
@@ -340,6 +349,7 @@ package android {
field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
+ field @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") public static final String REMOVE_ACCOUNTS = "android.permission.REMOVE_ACCOUNTS";
field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS";
@@ -367,7 +377,6 @@ package android {
field public static final String SERIAL_PORT = "android.permission.SERIAL_PORT";
field @FlaggedApi("android.security.fsverity_api") public static final String SETUP_FSVERITY = "android.permission.SETUP_FSVERITY";
field public static final String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
- field @FlaggedApi("android.security.aapm_api") public static final String SET_ADVANCED_PROTECTION_MODE = "android.permission.SET_ADVANCED_PROTECTION_MODE";
field public static final String SET_CLIP_SOURCE = "android.permission.SET_CLIP_SOURCE";
field public static final String SET_DEFAULT_ACCOUNT_FOR_CONTACTS = "android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS";
field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
@@ -421,7 +430,6 @@ package android {
field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String USE_ON_DEVICE_INTELLIGENCE = "android.permission.USE_ON_DEVICE_INTELLIGENCE";
field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final String UWB_PRIVILEGED = "android.permission.UWB_PRIVILEGED";
- field @FlaggedApi("android.content.pm.verification_service") public static final String VERIFICATION_AGENT = "android.permission.VERIFICATION_AGENT";
field @FlaggedApi("android.os.vibrator.vendor_vibration_effects") public static final String VIBRATE_VENDOR_EFFECTS = "android.permission.VIBRATE_VENDOR_EFFECTS";
field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
@@ -528,6 +536,7 @@ package android {
field public static final int config_systemCallStreaming = 17039431; // 0x1040047
field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039
field public static final int config_systemContacts = 17039403; // 0x104002b
+ field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final int config_systemDependencyInstaller;
field public static final int config_systemFinancedDeviceController = 17039430; // 0x1040046
field public static final int config_systemGallery = 17039399; // 0x1040027
field public static final int config_systemNotificationIntelligence = 17039413; // 0x1040035
@@ -564,6 +573,7 @@ package android.accessibilityservice {
package android.accounts {
public class AccountManager {
+ method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @NonNull @RequiresPermission(anyOf={android.Manifest.permission.COPY_ACCOUNTS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public android.accounts.AccountManagerFuture<java.lang.Boolean> copyAccountToUser(@NonNull android.accounts.Account, @NonNull android.os.UserHandle, @NonNull android.os.UserHandle, @Nullable android.accounts.AccountManagerCallback<java.lang.Boolean>, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
}
@@ -1336,8 +1346,10 @@ package android.app.admin {
public class DevicePolicyManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPrecondition(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void clearAuditLogEventCallback();
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
+ method @Deprecated @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
+ method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
+ method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeCreateManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams, @NonNull android.os.UserHandle) throws android.app.admin.ProvisioningException;
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeWorkProfileProvisioning(@NonNull android.os.UserHandle, @Nullable android.accounts.Account);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS) public java.util.Set<java.lang.Integer> getApplicationExemptions(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
@@ -1378,7 +1390,8 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setMaxPolicyStorageLimit(int);
method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
- method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
+ method @Deprecated @FlaggedApi("android.app.admin.flags.secondary_lockscreen_api_enabled") public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
+ method @FlaggedApi("android.app.admin.flags.secondary_lockscreen_api_enabled") public void setSecondaryLockscreenEnabled(boolean, @Nullable android.os.PersistableBundle);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
@@ -1931,6 +1944,7 @@ package android.app.backup {
method public android.os.IBinder getBinder();
method public long getCurrentRestoreSet();
method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor);
+ method @FlaggedApi("com.android.server.backup.enable_restricted_mode_changes") @NonNull public java.util.List<java.lang.String> getPackagesThatShouldNotUseRestrictedMode(@NonNull java.util.List<java.lang.String>, int);
method public int getRestoreData(android.os.ParcelFileDescriptor);
method public int getTransportFlags();
method public int initializeDevice();
@@ -2309,6 +2323,24 @@ package android.app.ondeviceintelligence {
field public static final int FEATURE_STATUS_UNAVAILABLE = 0; // 0x0
}
+ @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence_module") public final class InferenceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getEndTimeMillis();
+ method public long getStartTimeMillis();
+ method public long getSuspendedTimeMillis();
+ method public int getUid();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.ondeviceintelligence.InferenceInfo> CREATOR;
+ }
+
+ public static final class InferenceInfo.Builder {
+ ctor public InferenceInfo.Builder(int);
+ method @NonNull public android.app.ondeviceintelligence.InferenceInfo build();
+ method @NonNull public android.app.ondeviceintelligence.InferenceInfo.Builder setEndTimeMillis(long);
+ method @NonNull public android.app.ondeviceintelligence.InferenceInfo.Builder setStartTimeMillis(long);
+ method @NonNull public android.app.ondeviceintelligence.InferenceInfo.Builder setSuspendedTimeMillis(long);
+ }
+
@FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public class OnDeviceIntelligenceException extends java.lang.Exception {
ctor public OnDeviceIntelligenceException(int, @NonNull String, @NonNull android.os.PersistableBundle);
ctor public OnDeviceIntelligenceException(int, @NonNull android.os.PersistableBundle);
@@ -2338,6 +2370,7 @@ package android.app.ondeviceintelligence {
@FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class OnDeviceIntelligenceManager {
method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getFeature(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.Feature,android.app.ondeviceintelligence.OnDeviceIntelligenceException>);
method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getFeatureDetails(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.FeatureDetails,android.app.ondeviceintelligence.OnDeviceIntelligenceException>);
+ method @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence_module") @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ondeviceintelligence.InferenceInfo> getLatestInferenceInfo(long);
method @Nullable @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public String getRemoteServicePackageName();
method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getVersion(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.LongConsumer);
method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void listFeatures(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.util.List<android.app.ondeviceintelligence.Feature>,android.app.ondeviceintelligence.OnDeviceIntelligenceException>);
@@ -3403,14 +3436,14 @@ package android.app.wearable {
public class WearableSensingManager {
method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public int getAvailableConnectionCount();
method @Nullable public static android.app.wearable.WearableSensingDataRequest getDataRequestFromIntent(@NonNull android.content.Intent);
- method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @Deprecated @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.app.wearable.WearableConnection, @NonNull java.util.concurrent.Executor);
method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideData(@NonNull android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideDataStream(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_provide_read_only_pfd") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideReadOnlyParcelFileDescriptor(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void registerDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void removeAllConnections();
- method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public boolean removeConnection(@NonNull android.app.wearable.WearableConnection);
+ method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void removeConnection(@NonNull android.app.wearable.WearableConnection);
method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void startHotwordRecognition(@Nullable android.content.ComponentName, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void stopHotwordRecognition(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void unregisterDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -3859,6 +3892,7 @@ package android.content {
field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
field public static final String APP_PREDICTION_SERVICE = "app_prediction";
field public static final String AUDIO_DEVICE_VOLUME_SERVICE = "audio_device_volume";
+ field @FlaggedApi("android.security.secure_lockdown") public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy";
field public static final String BACKUP_SERVICE = "backup";
field public static final String BATTERY_STATS_SERVICE = "batterystats";
field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
@@ -4211,13 +4245,12 @@ package android.content.pm {
}
public class PackageInstaller {
- method @FlaggedApi("android.content.pm.verification_service") @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public final int getVerificationPolicy();
method @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull java.io.File, int) throws android.content.pm.PackageInstaller.PackageParsingException;
method @FlaggedApi("android.content.pm.read_install_info") @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull android.os.ParcelFileDescriptor, @Nullable String, int) throws android.content.pm.PackageInstaller.PackageParsingException;
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean);
- method @FlaggedApi("android.content.pm.verification_service") @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public final boolean setVerificationPolicy(int);
field public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL";
field public static final String ACTION_CONFIRM_PRE_APPROVAL = "android.content.pm.action.CONFIRM_PRE_APPROVAL";
+ field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String ACTION_INSTALL_DEPENDENCY = "android.content.pm.action.INSTALL_DEPENDENCY";
field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2
field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0
field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1
@@ -4226,20 +4259,12 @@ package android.content.pm {
field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_DELETE_FLAGS = "android.content.pm.extra.DELETE_FLAGS";
field public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
field @Deprecated public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH";
- field @FlaggedApi("android.content.pm.verification_service") public static final String EXTRA_VERIFICATION_FAILURE_REASON = "android.content.pm.extra.VERIFICATION_FAILURE_REASON";
field public static final int LOCATION_DATA_APP = 0; // 0x0
field public static final int LOCATION_MEDIA_DATA = 2; // 0x2
field public static final int LOCATION_MEDIA_OBB = 1; // 0x1
field public static final int REASON_CONFIRM_PACKAGE_CHANGE = 0; // 0x0
field public static final int REASON_OWNERSHIP_CHANGED = 1; // 0x1
field public static final int REASON_REMIND_OWNERSHIP = 2; // 0x2
- field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE = 1; // 0x1
- field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED = 2; // 0x2
- field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_UNKNOWN = 0; // 0x0
- field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_CLOSED = 3; // 0x3
- field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_OPEN = 1; // 0x1
- field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_WARN = 2; // 0x2
- field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_NONE = 0; // 0x0
}
public static class PackageInstaller.InstallInfo {
@@ -4359,7 +4384,6 @@ package android.content.pm {
method @Deprecated @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, @NonNull java.util.List<java.lang.String>);
field public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
field public static final String ACTION_REQUEST_PERMISSIONS_FOR_OTHER = "android.content.pm.action.REQUEST_PERMISSIONS_FOR_OTHER";
- field @FlaggedApi("android.content.pm.verification_service") public static final String ACTION_VERIFY_PACKAGE = "android.content.pm.action.VERIFY_PACKAGE";
field @FlaggedApi("android.content.pm.asl_in_apk_app_metadata_source") public static final int APP_METADATA_SOURCE_APK = 1; // 0x1
field @FlaggedApi("android.content.pm.asl_in_apk_app_metadata_source") public static final int APP_METADATA_SOURCE_INSTALLER = 2; // 0x2
field @FlaggedApi("android.content.pm.asl_in_apk_app_metadata_source") public static final int APP_METADATA_SOURCE_SYSTEM_IMAGE = 3; // 0x3
@@ -4584,6 +4608,24 @@ package android.content.pm {
}
+package android.content.pm.dependencyinstaller {
+
+ @FlaggedApi("android.content.pm.sdk_dependency_installer") public final class DependencyInstallerCallback implements android.os.Parcelable {
+ method public int describeContents();
+ method public void onAllDependenciesResolved(@NonNull int[]);
+ method public void onFailureToResolveAllDependencies();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.dependencyinstaller.DependencyInstallerCallback> CREATOR;
+ }
+
+ @FlaggedApi("android.content.pm.sdk_dependency_installer") public abstract class DependencyInstallerService extends android.app.Service {
+ ctor public DependencyInstallerService();
+ method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method public abstract void onDependenciesRequired(@NonNull java.util.List<android.content.pm.SharedLibraryInfo>, @NonNull android.content.pm.dependencyinstaller.DependencyInstallerCallback);
+ }
+
+}
+
package android.content.pm.dex {
public class ArtManager {
@@ -4673,62 +4715,6 @@ package android.content.pm.verify.domain {
}
-package android.content.pm.verify.pkg {
-
- @FlaggedApi("android.content.pm.verification_service") public final class VerificationSession implements android.os.Parcelable {
- method public int describeContents();
- method public long extendTimeRemaining(long);
- method @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getDeclaredLibraries();
- method @NonNull public android.os.PersistableBundle getExtensionParams();
- method public int getId();
- method public int getInstallSessionId();
- method @NonNull public String getPackageName();
- method @NonNull public android.content.pm.SigningInfo getSigningInfo();
- method @NonNull public android.net.Uri getStagedPackageUri();
- method public long getTimeoutTime();
- method public int getVerificationPolicy();
- method public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus);
- method public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus, @NonNull android.os.PersistableBundle);
- method public void reportVerificationIncomplete(int);
- method public boolean setVerificationPolicy(int);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.pkg.VerificationSession> CREATOR;
- field public static final int VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE = 1; // 0x1
- field public static final int VERIFICATION_INCOMPLETE_UNKNOWN = 0; // 0x0
- }
-
- @FlaggedApi("android.content.pm.verification_service") public final class VerificationStatus implements android.os.Parcelable {
- method public int describeContents();
- method public int getAslStatus();
- method @NonNull public String getFailureMessage();
- method public boolean isVerified();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.pkg.VerificationStatus> CREATOR;
- field public static final int VERIFIER_STATUS_ASL_BAD = 2; // 0x2
- field public static final int VERIFIER_STATUS_ASL_GOOD = 1; // 0x1
- field public static final int VERIFIER_STATUS_ASL_UNDEFINED = 0; // 0x0
- }
-
- public static final class VerificationStatus.Builder {
- ctor public VerificationStatus.Builder();
- method @NonNull public android.content.pm.verify.pkg.VerificationStatus build();
- method @NonNull public android.content.pm.verify.pkg.VerificationStatus.Builder setAslStatus(int);
- method @NonNull public android.content.pm.verify.pkg.VerificationStatus.Builder setFailureMessage(@NonNull String);
- method @NonNull public android.content.pm.verify.pkg.VerificationStatus.Builder setVerified(boolean);
- }
-
- @FlaggedApi("android.content.pm.verification_service") public abstract class VerifierService extends android.app.Service {
- ctor public VerifierService();
- method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
- method public abstract void onPackageNameAvailable(@NonNull String);
- method public abstract void onVerificationCancelled(@NonNull String);
- method public abstract void onVerificationRequired(@NonNull android.content.pm.verify.pkg.VerificationSession);
- method public abstract void onVerificationRetry(@NonNull android.content.pm.verify.pkg.VerificationSession);
- method public abstract void onVerificationTimeout(int);
- }
-
-}
-
package android.content.rollback {
public final class PackageRollbackInfo implements android.os.Parcelable {
@@ -5044,15 +5030,27 @@ package android.hardware.biometrics {
package android.hardware.camera2 {
+ public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CameraCharacteristics.Key<?>> {
+ field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.SharedSessionConfiguration> SHARED_SESSION_CONFIGURATION;
+ }
+
public abstract class CameraDevice implements java.lang.AutoCloseable {
method @Deprecated public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1
field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0
+ field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public static final int SESSION_OPERATION_MODE_SHARED = 2; // 0x2
field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000
}
+ public abstract static class CameraDevice.StateCallback {
+ method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public void onClientSharedAccessPriorityChanged(@NonNull android.hardware.camera2.CameraDevice, boolean);
+ method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public void onOpenedInSharedMode(@NonNull android.hardware.camera2.CameraDevice, boolean);
+ }
+
public final class CameraManager {
+ method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public boolean isCameraDeviceSharingSupported(@NonNull String) 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;
+ method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openSharedCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
}
public abstract static class CameraManager.AvailabilityCallback {
@@ -5060,6 +5058,12 @@ package android.hardware.camera2 {
method @RequiresPermission(android.Manifest.permission.CAMERA_OPEN_CLOSE_LISTENER) public void onCameraOpened(@NonNull String, @NonNull String);
}
+ @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract class CameraSharedCaptureSession extends android.hardware.camera2.CameraCaptureSession {
+ ctor public CameraSharedCaptureSession();
+ method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract int startStreaming(@NonNull java.util.List<android.view.Surface>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
+ method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract void stopStreaming() throws android.hardware.camera2.CameraAccessException;
+ }
+
}
package android.hardware.camera2.extension {
@@ -5168,6 +5172,140 @@ package android.hardware.camera2.params {
field public static final int ROTATION_90 = 1; // 0x1
}
+ public final class SessionConfiguration implements android.os.Parcelable {
+ field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public static final int SESSION_SHARED = 2; // 0x2
+ }
+
+ @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public final class SharedSessionConfiguration {
+ method @Nullable public android.graphics.ColorSpace getColorSpace();
+ method @NonNull public java.util.List<android.hardware.camera2.params.SharedSessionConfiguration.SharedOutputConfiguration> getOutputStreamsInformation();
+ }
+
+ public static final class SharedSessionConfiguration.SharedOutputConfiguration {
+ method public int getDataspace();
+ method public int getFormat();
+ method public int getMirrorMode();
+ method @Nullable public String getPhysicalCameraId();
+ method @NonNull public android.util.Size getSize();
+ method public long getStreamUseCase();
+ method public int getSurfaceType();
+ method public int getTimestampBase();
+ method public long getUsage();
+ method public boolean isReadoutTimestampEnabled();
+ }
+
+}
+
+package android.hardware.contexthub {
+
+ @FlaggedApi("android.chre.flags.offload_api") public class HubDiscoveryInfo {
+ method @NonNull public android.hardware.contexthub.HubEndpointInfo getHubEndpointInfo();
+ method @Nullable public android.hardware.contexthub.HubServiceInfo getHubServiceInfo();
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public class HubEndpoint {
+ method @Nullable public android.hardware.contexthub.IHubEndpointLifecycleCallback getLifecycleCallback();
+ method @Nullable public android.hardware.contexthub.IHubEndpointMessageCallback getMessageCallback();
+ method @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection();
+ method @Nullable public String getTag();
+ method public int getVersion();
+ }
+
+ public static final class HubEndpoint.Builder {
+ ctor public HubEndpoint.Builder(@NonNull android.content.Context);
+ method @NonNull public android.hardware.contexthub.HubEndpoint build();
+ method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback);
+ method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback);
+ method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull android.hardware.contexthub.IHubEndpointMessageCallback);
+ method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointMessageCallback);
+ method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setServiceInfoCollection(@NonNull java.util.Collection<android.hardware.contexthub.HubServiceInfo>);
+ method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setTag(@NonNull String);
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public final class HubEndpointInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.hardware.contexthub.HubEndpointInfo.HubEndpointIdentifier getIdentifier();
+ method @NonNull public String getName();
+ method @NonNull public java.util.Collection<java.lang.String> getRequiredPermissions();
+ method @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection();
+ method @Nullable public String getTag();
+ method public int getType();
+ method public int getVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubEndpointInfo> CREATOR;
+ field public static final int TYPE_APP = 2; // 0x2
+ field public static final int TYPE_FRAMEWORK = 1; // 0x1
+ field public static final int TYPE_HUB_ENDPOINT = 5; // 0x5
+ field public static final int TYPE_NANOAPP = 4; // 0x4
+ field public static final int TYPE_NATIVE = 3; // 0x3
+ }
+
+ public static class HubEndpointInfo.HubEndpointIdentifier {
+ method public long getEndpoint();
+ method public long getHub();
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSession implements java.lang.AutoCloseable {
+ method public void close();
+ method @Nullable public android.hardware.contexthub.HubServiceInfo getServiceInfo();
+ method @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> sendMessage(@NonNull android.hardware.contexthub.HubMessage);
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSessionResult {
+ method @NonNull public static android.hardware.contexthub.HubEndpointSessionResult accept();
+ method @Nullable public String getReason();
+ method public boolean isAccepted();
+ method @NonNull public static android.hardware.contexthub.HubEndpointSessionResult reject(@NonNull String);
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public final class HubMessage implements android.os.Parcelable {
+ method @NonNull public static android.hardware.contexthub.HubMessage createMessage(int, @NonNull byte[]);
+ method @NonNull public static android.hardware.contexthub.HubMessage createMessage(int, @NonNull byte[], @NonNull android.hardware.contexthub.HubMessage.DeliveryParams);
+ method public int describeContents();
+ method @NonNull public byte[] getMessageBody();
+ method public int getMessageType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubMessage> CREATOR;
+ }
+
+ public static class HubMessage.DeliveryParams {
+ method public boolean isResponseRequired();
+ method @NonNull public static android.hardware.contexthub.HubMessage.DeliveryParams makeBasic();
+ method @NonNull public android.hardware.contexthub.HubMessage.DeliveryParams setResponseRequired(boolean);
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public final class HubServiceInfo implements android.os.Parcelable {
+ ctor public HubServiceInfo(@NonNull String, int, int, int);
+ method public int describeContents();
+ method public int getFormat();
+ method public int getMajorVersion();
+ method public int getMinorVersion();
+ method @NonNull public String getServiceDescriptor();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubServiceInfo> CREATOR;
+ field public static final int FORMAT_AIDL = 1; // 0x1
+ field public static final int FORMAT_CUSTOM = 0; // 0x0
+ field public static final int FORMAT_PW_RPC_PROTOBUF = 2; // 0x2
+ }
+
+ public static final class HubServiceInfo.Builder {
+ ctor public HubServiceInfo.Builder(@NonNull String, int, int, int);
+ method @NonNull public android.hardware.contexthub.HubServiceInfo build();
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointLifecycleCallback {
+ method public void onSessionClosed(@NonNull android.hardware.contexthub.HubEndpointSession, int);
+ method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo, @Nullable android.hardware.contexthub.HubServiceInfo);
+ method public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession);
+ field public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; // 0x4
+ field public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; // 0x3
+ field public static final int REASON_UNSPECIFIED = 0; // 0x0
+ }
+
+ @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointMessageCallback {
+ method public void onMessageReceived(@NonNull android.hardware.contexthub.HubEndpointSession, @NonNull android.hardware.contexthub.HubMessage);
+ }
+
}
package android.hardware.devicestate {
@@ -5300,6 +5438,7 @@ package android.hardware.display {
method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
method public android.util.Pair<float[],float[]> getMinimumBrightnessCurve();
method public android.graphics.Point getStableDisplaySize();
+ method @FlaggedApi("com.android.server.display.feature.flags.is_always_on_available_api") public boolean isAlwaysOnDisplayCurrentlyAvailable();
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
@@ -6161,6 +6300,8 @@ package android.hardware.location {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+ method @FlaggedApi("android.chre.flags.offload_api") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public java.util.List<android.hardware.contexthub.HubDiscoveryInfo> findEndpoints(long);
+ method @FlaggedApi("android.chre.flags.offload_api") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public java.util.List<android.hardware.contexthub.HubDiscoveryInfo> findEndpoints(@NonNull String);
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int[] getContextHubHandles();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
@@ -6168,13 +6309,17 @@ package android.hardware.location {
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
+ method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo);
+ method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo, @NonNull android.hardware.contexthub.HubServiceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
+ method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpoint(@NonNull android.hardware.contexthub.HubEndpoint);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int unloadNanoApp(int);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
+ method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpoint(@NonNull android.hardware.contexthub.HubEndpoint);
field public static final int AUTHORIZATION_DENIED = 0; // 0x0
field public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; // 0x1
field public static final int AUTHORIZATION_GRANTED = 2; // 0x2
@@ -6230,6 +6375,8 @@ package android.hardware.location {
field public static final int RESULT_SUCCESS = 0; // 0x0
field public static final int TYPE_DISABLE_NANOAPP = 3; // 0x3
field public static final int TYPE_ENABLE_NANOAPP = 2; // 0x2
+ field @FlaggedApi("android.chre.flags.offload_api") public static final int TYPE_HUB_MESSAGE_DEFAULT = 6; // 0x6
+ field @FlaggedApi("android.chre.flags.offload_api") public static final int TYPE_HUB_MESSAGE_REQUIRES_RESPONSE = 7; // 0x7
field public static final int TYPE_LOAD_NANOAPP = 0; // 0x0
field public static final int TYPE_QUERY_NANOAPPS = 4; // 0x4
field public static final int TYPE_RELIABLE_MESSAGE = 5; // 0x5
@@ -7463,6 +7610,7 @@ package android.media {
}
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
+ method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceInfo> getAudioDeviceInfos();
method public int getChannelMask();
method public int getClientPid();
method public int getClientUid();
@@ -7617,7 +7765,7 @@ package android.media {
public final class MediaCas implements java.lang.AutoCloseable {
method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceHolderRetain(boolean);
- method @FlaggedApi("com.android.media.flags.update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int);
+ method @FlaggedApi("android.media.tv.flags.mediacas_update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int);
}
public final class MediaCodec {
@@ -7956,6 +8104,44 @@ package android.media.musicrecognition {
}
+package android.media.quality {
+
+ @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager {
+ method @NonNull public java.util.List<java.lang.String> getPictureProfileAllowList();
+ method @NonNull public java.util.List<java.lang.String> getPictureProfilePackageNames();
+ method @NonNull public java.util.List<android.media.quality.PictureProfile> getPictureProfilesByPackage(@NonNull String);
+ method @NonNull public java.util.List<java.lang.String> getSoundProfileAllowList();
+ method @NonNull public java.util.List<java.lang.String> getSoundProfilePackageNames();
+ method @NonNull public java.util.List<android.media.quality.SoundProfile> getSoundProfilesByPackage(@NonNull String);
+ method public void setAutoPictureQualityEnabled(boolean);
+ method public void setAutoSoundQualityEnabled(boolean);
+ method public void setPictureProfileAllowList(@NonNull java.util.List<java.lang.String>);
+ method public void setSoundProfileAllowList(@NonNull java.util.List<java.lang.String>);
+ method public void setSuperResolutionEnabled(boolean);
+ }
+
+ public static final class PictureProfile.Builder {
+ method @NonNull public android.media.quality.PictureProfile.Builder setInputId(@NonNull String);
+ method @NonNull public android.media.quality.PictureProfile.Builder setPackageName(@NonNull String);
+ method @NonNull public android.media.quality.PictureProfile.Builder setProfileType(int);
+ }
+
+ @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public final class PictureProfileHandle implements android.os.Parcelable {
+ method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public int describeContents();
+ method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public long getId();
+ method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") @NonNull public static final android.os.Parcelable.Creator<android.media.quality.PictureProfileHandle> CREATOR;
+ field @NonNull public static final android.media.quality.PictureProfileHandle NONE;
+ }
+
+ public static final class SoundProfile.Builder {
+ method @NonNull public android.media.quality.SoundProfile.Builder setInputId(@NonNull String);
+ method @NonNull public android.media.quality.SoundProfile.Builder setPackageName(@NonNull String);
+ method @NonNull public android.media.quality.SoundProfile.Builder setProfileType(int);
+ }
+
+}
+
package android.media.session {
public final class MediaSessionManager {
@@ -8246,6 +8432,104 @@ package android.media.tv {
method public void onSetMain(boolean);
}
+ @FlaggedApi("android.media.tv.flags.tif_extension_standardization") public final class TvInputServiceExtensionManager {
+ method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public int registerExtensionIBinder(@NonNull String, @NonNull android.os.IBinder);
+ field public static final String IANALOG_ATTRIBUTE_INTERFACE = "android.media.tv.extension.analog.IAnalogAttributeInterface";
+ field public static final String IANALOG_AUDIO_INFO = "android.media.tv.extension.signal.IAnalogAudioInfo";
+ field public static final String IAUDIO_SIGNAL_INFO = "android.media.tv.extension.signal.IAudioSignalInfo";
+ field public static final String IAUDIO_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IAudioSignalInfoListener";
+ field public static final String IBROADCAST_TIME = "android.media.tv.extension.time.IBroadcastTime";
+ field public static final String ICAM_APP_INFO_LISTENER = "android.media.tv.extension.cam.ICamAppInfoListener";
+ field public static final String ICAM_APP_INFO_SERVICE = "android.media.tv.extension.cam.ICamAppInfoService";
+ field public static final String ICAM_DRM_INFO_LISTENER = "android.media.tv.extension.cam.ICamDrmInfoListener";
+ field public static final String ICAM_HOST_CONTROL_ASK_RELEASE_REPLY_CALLBACK = "android.media.tv.extension.cam.ICamHostControlAskReleaseReplyCallback";
+ field public static final String ICAM_HOST_CONTROL_INFO_LISTENER = "android.media.tv.extension.cam.ICamHostControlInfoListener";
+ field public static final String ICAM_HOST_CONTROL_SERVICE = "android.media.tv.extension.cam.ICamHostControlService";
+ field public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG = "android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlag";
+ field public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG_LISTENER = "android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlagListener";
+ field public static final String ICAM_INFO_LISTENER = "android.media.tv.extension.cam.ICamInfoListener";
+ field public static final String ICAM_MONITORING_SERVICE = "android.media.tv.extension.cam.ICamMonitoringService";
+ field public static final String ICAM_PIN_CAPABILITY_LISTENER = "android.media.tv.extension.cam.ICamPinCapabilityListener";
+ field public static final String ICAM_PIN_SERVICE = "android.media.tv.extension.cam.ICamPinService";
+ field public static final String ICAM_PIN_STATUS_LISTENER = "android.media.tv.extension.cam.ICamPinStatusListener";
+ field public static final String ICAM_PROFILE_INTERFACE = "android.media.tv.extension.cam.ICamProfileInterface";
+ field public static final String ICHANNEL_LIST_TRANSFER = "android.media.tv.extension.servicedb.IChannelListTransfer";
+ field public static final String ICHANNEL_TUNED_INTERFACE = "android.media.tv.extension.tune.IChannelTunedInterface";
+ field public static final String ICHANNEL_TUNED_LISTENER = "android.media.tv.extension.tune.IChannelTunedListener";
+ field public static final String ICI_OPERATOR_INTERFACE = "android.media.tv.extension.cam.ICiOperatorInterface";
+ field public static final String ICI_OPERATOR_LISTENER = "android.media.tv.extension.cam.ICiOperatorListener";
+ field public static final String ICLIENT_TOKEN = "android.media.tv.extension.clienttoken.IClientToken";
+ field public static final String ICONTENT_CONTROL_SERVICE = "android.media.tv.extension.cam.IContentControlService";
+ field public static final String IDATA_SERVICE_SIGNAL_INFO = "android.media.tv.extension.teletext.IDataServiceSignalInfo";
+ field public static final String IDATA_SERVICE_SIGNAL_INFO_LISTENER = "android.media.tv.extension.teletext.IDataServiceSignalInfoListener";
+ field public static final String IDELETE_RECORDED_CONTENTS_CALLBACK = "android.media.tv.extension.pvr.IDeleteRecordedContentsCallback";
+ field public static final String IDOWNLOADABLE_RATING_TABLE_MONITOR = "android.media.tv.extension.rating.IDownloadableRatingTableMonitor";
+ field public static final String IENTER_MENU_ERROR_CALLBACK = "android.media.tv.extension.cam.IEnterMenuErrorCallback";
+ field public static final String IEVENT_DOWNLOAD = "android.media.tv.extension.event.IEventDownload";
+ field public static final String IEVENT_DOWNLOAD_LISTENER = "android.media.tv.extension.event.IEventDownloadListener";
+ field public static final String IEVENT_DOWNLOAD_SESSION = "android.media.tv.extension.event.IEventDownloadSession";
+ field public static final String IEVENT_MONITOR = "android.media.tv.extension.event.IEventMonitor";
+ field public static final String IEVENT_MONITOR_LISTENER = "android.media.tv.extension.event.IEventMonitorListener";
+ field public static final String IFAVORITE_NETWORK = "android.media.tv.extension.scan.IFavoriteNetwork";
+ field public static final String IFAVORITE_NETWORK_LISTENER = "android.media.tv.extension.scan.IFavoriteNetworkListener";
+ field public static final String IGET_INFO_RECORDED_CONTENTS_CALLBACK = "android.media.tv.extension.pvr.IGetInfoRecordedContentsCallback";
+ field public static final String IHDMI_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IHdmiSignalInfoListener";
+ field public static final String IHDMI_SIGNAL_INTERFACE = "android.media.tv.extension.signal.IHdmiSignalInterface";
+ field public static final String IHDPLUS_INFO = "android.media.tv.extension.scan.IHDPlusInfo";
+ field public static final String ILCNV2_CHANNEL_LIST = "android.media.tv.extension.scan.ILcnV2ChannelList";
+ field public static final String ILCNV2_CHANNEL_LIST_LISTENER = "android.media.tv.extension.scan.ILcnV2ChannelListListener";
+ field public static final String ILCN_CONFLICT = "android.media.tv.extension.scan.ILcnConflict";
+ field public static final String ILCN_CONFLICT_LISTENER = "android.media.tv.extension.scan.ILcnConflictListener";
+ field public static final String IMMI_INTERFACE = "android.media.tv.extension.cam.IMmiInterface";
+ field public static final String IMMI_SESSION = "android.media.tv.extension.cam.IMmiSession";
+ field public static final String IMMI_STATUS_CALLBACK = "android.media.tv.extension.cam.IMmiStatusCallback";
+ field public static final String IMUX_TUNE = "android.media.tv.extension.tune.IMuxTune";
+ field public static final String IMUX_TUNE_SESSION = "android.media.tv.extension.tune.IMuxTuneSession";
+ field public static final String IOAD_UPDATE_INTERFACE = "android.media.tv.extension.oad.IOadUpdateInterface";
+ field public static final String IOPERATOR_DETECTION = "android.media.tv.extension.scan.IOperatorDetection";
+ field public static final String IOPERATOR_DETECTION_LISTENER = "android.media.tv.extension.scan.IOperatorDetectionListener";
+ field public static final String IPMT_RATING_INTERFACE = "android.media.tv.extension.rating.IPmtRatingInterface";
+ field public static final String IPMT_RATING_LISTENER = "android.media.tv.extension.rating.IPmtRatingListener";
+ field public static final String IPROGRAM_INFO = "android.media.tv.extension.rating.IProgramInfo";
+ field public static final String IPROGRAM_INFO_LISTENER = "android.media.tv.extension.rating.IProgramInfoListener";
+ field public static final String IRATING_INTERFACE = "android.media.tv.extension.rating.IRatingInterface";
+ field public static final String IRECORDED_CONTENTS = "android.media.tv.extension.pvr.IRecordedContents";
+ field public static final String IREGION_CHANNEL_LIST = "android.media.tv.extension.scan.IRegionChannelList";
+ field public static final String IREGION_CHANNEL_LIST_LISTENER = "android.media.tv.extension.scan.IRegionChannelListListener";
+ field public static final String ISCAN_BACKGROUND_SERVICE_UPDATE = "android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdate";
+ field public static final String ISCAN_BACKGROUND_SERVICE_UPDATE_LISTENER = "android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdateListener";
+ field public static final String ISCAN_INTERFACE = "android.media.tv.extension.scan.IScanInterface";
+ field public static final String ISCAN_LISTENER = "android.media.tv.extension.scan.IScanListener";
+ field public static final String ISCAN_SAT_SEARCH = "android.media.tv.extension.scan.IScanSatSearch";
+ field public static final String ISCAN_SESSION = "android.media.tv.extension.scan.IScanSession";
+ field public static final String ISCREEN_MODE_SETTINGS = "android.media.tv.extension.screenmode.IScreenModeSettings";
+ field public static final String ISERVICE_LIST = "android.media.tv.extension.servicedb.IServiceList";
+ field public static final String ISERVICE_LIST_EDIT = "android.media.tv.extension.servicedb.IServiceListEdit";
+ field public static final String ISERVICE_LIST_EDIT_LISTENER = "android.media.tv.extension.servicedb.IServiceListEditListener";
+ field public static final String ISERVICE_LIST_EXPORT_LISTENER = "android.media.tv.extension.servicedb.IServiceListExportListener";
+ field public static final String ISERVICE_LIST_EXPORT_SESSION = "android.media.tv.extension.servicedb.IServiceListExportSession";
+ field public static final String ISERVICE_LIST_IMPORT_LISTENER = "android.media.tv.extension.servicedb.IServiceListImportListener";
+ field public static final String ISERVICE_LIST_IMPORT_SESSION = "android.media.tv.extension.servicedb.IServiceListImportSession";
+ field public static final String ISERVICE_LIST_SET_CHANNEL_LIST_LISTENER = "android.media.tv.extension.servicedb.IServiceListSetChannelListListener";
+ field public static final String ISERVICE_LIST_SET_CHANNEL_LIST_SESSION = "android.media.tv.extension.servicedb.IServiceListSetChannelListSession";
+ field public static final String ISERVICE_LIST_TRANSFER_INTERFACE = "android.media.tv.extension.servicedb.IServiceListTransferInterface";
+ field public static final String ITARGET_REGION = "android.media.tv.extension.scan.ITargetRegion";
+ field public static final String ITARGET_REGION_LISTENER = "android.media.tv.extension.scan.ITargetRegionListener";
+ field public static final String ITELETEXT_PAGE_SUB_CODE = "android.media.tv.extension.teletext.ITeletextPageSubCode";
+ field public static final String ITKGS_INFO = "android.media.tv.extension.scan.ITkgsInfo";
+ field public static final String ITKGS_INFO_LISTENER = "android.media.tv.extension.scan.ITkgsInfoListener";
+ field public static final String ITUNER_FRONTEND_SIGNAL_INFO_INTERFACE = "android.media.tv.extension.signal.ITunerFrontendSignalInfoInterface";
+ field public static final String ITUNER_FRONTEND_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.ITunerFrontendSignalInfoListener";
+ field public static final String IVBI_RATING_INTERFACE = "android.media.tv.extension.rating.IVbiRatingInterface";
+ field public static final String IVBI_RATING_LISTENER = "android.media.tv.extension.rating.IVbiRatingListener";
+ field public static final String IVIDEO_SIGNAL_INFO = "android.media.tv.extension.signal.IVideoSignalInfo";
+ field public static final String IVIDEO_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IVideoSignalInfoListener";
+ field public static final int REGISTER_FAIL_IMPLEMENTATION_NOT_STANDARDIZED = 2; // 0x2
+ field public static final int REGISTER_FAIL_NAME_NOT_STANDARDIZED = 1; // 0x1
+ field public static final int REGISTER_FAIL_REMOTE_EXCEPTION = 3; // 0x3
+ field public static final int REGISTER_SUCCESS = 0; // 0x0
+ }
+
public abstract static class TvRecordingClient.RecordingCallback {
method public void onEvent(String, String, android.os.Bundle);
}
@@ -9584,7 +9868,7 @@ package android.media.tv.tuner.frontend {
method public int getSignalStrength();
method public int getSnr();
method public int getSpectralInversion();
- method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @NonNull public android.media.tv.tuner.frontend.StandardExt getStandardExt();
+ method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @NonNull public android.media.tv.tuner.frontend.StandardExtension getStandardExtension();
method @NonNull public int[] getStreamIds();
method public int getSymbolRate();
method @IntRange(from=0, to=65535) public int getSystemId();
@@ -9639,7 +9923,7 @@ package android.media.tv.tuner.frontend {
field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa
- field @FlaggedApi("android.media.tv.flags.tuner_w_apis") public static final int FRONTEND_STATUS_TYPE_STANDARD_EXT = 47; // 0x2f
+ field @FlaggedApi("android.media.tv.flags.tuner_w_apis") public static final int FRONTEND_STATUS_TYPE_STANDARD_EXTENSION = 47; // 0x2f
field public static final int FRONTEND_STATUS_TYPE_STREAM_IDS = 39; // 0x27
field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7
field public static final int FRONTEND_STATUS_TYPE_T2_SYSTEM_ID = 29; // 0x1d
@@ -9931,9 +10215,9 @@ package android.media.tv.tuner.frontend {
method public default void onUnlocked();
}
- @FlaggedApi("android.media.tv.flags.tuner_w_apis") public final class StandardExt {
- method public int getDvbsStandardExt();
- method public int getDvbtStandardExt();
+ @FlaggedApi("android.media.tv.flags.tuner_w_apis") public final class StandardExtension {
+ method public int getDvbsStandardExtension();
+ method public int getDvbtStandardExtension();
}
}
@@ -10826,6 +11110,7 @@ package android.nfc.cardemulation {
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
method @FlaggedApi("android.nfc.nfc_observe_mode") public void setShouldDefaultToObserveMode(boolean);
+ method @FlaggedApi("android.nfc.nfc_associated_role_services") public boolean shareRolePriority();
method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean shouldDefaultToObserveMode();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
@@ -12532,8 +12817,96 @@ package android.security.advancedprotection {
}
@FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures();
- method @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean);
+ method @NonNull public android.content.Intent createSupportIntent(@NonNull String, @Nullable String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean);
+ field @FlaggedApi("android.security.aapm_api") public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG = "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG";
+ field public static final String EXTRA_SUPPORT_DIALOG_FEATURE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE";
+ field public static final String EXTRA_SUPPORT_DIALOG_TYPE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE";
+ field public static final String FEATURE_ID_DISALLOW_CELLULAR_2G = "android.security.advancedprotection.feature_disallow_2g";
+ field public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = "android.security.advancedprotection.feature_disallow_install_unknown_sources";
+ field public static final String FEATURE_ID_DISALLOW_USB = "android.security.advancedprotection.feature_disallow_usb";
+ field public static final String FEATURE_ID_DISALLOW_WEP = "android.security.advancedprotection.feature_disallow_wep";
+ field public static final String FEATURE_ID_ENABLE_MTE = "android.security.advancedprotection.feature_enable_mte";
+ field public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION = "android.security.advancedprotection.type_blocked_interaction";
+ field public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING = "android.security.advancedprotection.type_disabled_setting";
+ }
+
+}
+
+package android.security.authenticationpolicy {
+
+ @FlaggedApi("android.security.secure_lockdown") public final class AuthenticationPolicyManager {
+ method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int disableSecureLockDevice(@NonNull android.security.authenticationpolicy.DisableSecureLockDeviceParams);
+ method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int enableSecureLockDevice(@NonNull android.security.authenticationpolicy.EnableSecureLockDeviceParams);
+ field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_ALREADY_ENABLED = 6; // 0x6
+ field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5; // 0x5
+ field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INVALID_PARAMS = 3; // 0x3
+ field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4; // 0x4
+ field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNKNOWN = 0; // 0x0
+ field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNSUPPORTED = 2; // 0x2
+ field @FlaggedApi("android.security.secure_lockdown") public static final int SUCCESS = 1; // 0x1
+ }
+
+ @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable {
+ ctor public DisableSecureLockDeviceParams(@NonNull String);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.DisableSecureLockDeviceParams> CREATOR;
+ }
+
+ @FlaggedApi("android.security.secure_lockdown") public final class EnableSecureLockDeviceParams implements android.os.Parcelable {
+ ctor public EnableSecureLockDeviceParams(@NonNull String);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.EnableSecureLockDeviceParams> CREATOR;
+ }
+
+}
+
+package android.security.intrusiondetection {
+
+ @FlaggedApi("android.security.afl_api") public final class IntrusionDetectionEvent implements android.os.Parcelable {
+ ctor public IntrusionDetectionEvent(@NonNull android.app.admin.SecurityLog.SecurityEvent);
+ ctor public IntrusionDetectionEvent(@NonNull android.app.admin.DnsEvent);
+ ctor public IntrusionDetectionEvent(@NonNull android.app.admin.ConnectEvent);
+ method @FlaggedApi("android.security.afl_api") public int describeContents();
+ method @NonNull public android.app.admin.ConnectEvent getConnectEvent();
+ method @NonNull public android.app.admin.DnsEvent getDnsEvent();
+ method @NonNull public android.app.admin.SecurityLog.SecurityEvent getSecurityEvent();
+ method @NonNull public int getType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.security.intrusiondetection.IntrusionDetectionEvent> CREATOR;
+ field public static final int NETWORK_EVENT_CONNECT = 2; // 0x2
+ field public static final int NETWORK_EVENT_DNS = 1; // 0x1
+ field public static final int SECURITY_EVENT = 0; // 0x0
+ }
+
+ @FlaggedApi("android.security.afl_api") public class IntrusionDetectionEventTransport {
+ ctor public IntrusionDetectionEventTransport();
+ method public boolean addData(@NonNull java.util.List<android.security.intrusiondetection.IntrusionDetectionEvent>);
+ method @NonNull public android.os.IBinder getBinder();
+ method public boolean initialize();
+ method public boolean release();
+ }
+
+ @FlaggedApi("android.security.afl_api") public class IntrusionDetectionManager {
+ method @RequiresPermission(android.Manifest.permission.READ_INTRUSION_DETECTION_STATE) public void addStateCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE) public void disable(@NonNull java.util.concurrent.Executor, @NonNull android.security.intrusiondetection.IntrusionDetectionManager.CommandCallback);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE) public void enable(@NonNull java.util.concurrent.Executor, @NonNull android.security.intrusiondetection.IntrusionDetectionManager.CommandCallback);
+ method @RequiresPermission(android.Manifest.permission.READ_INTRUSION_DETECTION_STATE) public void removeStateCallback(@NonNull java.util.function.Consumer<java.lang.Integer>);
+ field public static final int ERROR_DATA_SOURCE_UNAVAILABLE = 4; // 0x4
+ field public static final int ERROR_PERMISSION_DENIED = 1; // 0x1
+ field public static final int ERROR_TRANSPORT_UNAVAILABLE = 3; // 0x3
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_DISABLED = 1; // 0x1
+ field public static final int STATE_ENABLED = 2; // 0x2
+ field public static final int STATE_UNKNOWN = 0; // 0x0
+ }
+
+ public static interface IntrusionDetectionManager.CommandCallback {
+ method public void onFailure(int);
+ method public void onSuccess();
}
}
@@ -14203,7 +14576,7 @@ package android.service.wearable {
method @BinderThread public abstract void onDataStreamProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @BinderThread public abstract void onQueryServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
method @FlaggedApi("android.app.wearable.enable_provide_read_only_pfd") @BinderThread public void onReadOnlyParcelFileDescriptorProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @Deprecated @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>);
method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStartHotwordRecognition(@NonNull java.util.function.Consumer<android.service.voice.HotwordAudioStream>, @NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -14937,6 +15310,32 @@ package android.telephony {
method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo();
}
+ @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public final class CellularIdentifierDisclosure implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCellularIdentifier();
+ method public int getNasProtocolMessage();
+ method @NonNull public String getPlmn();
+ method public boolean isEmergency();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CELLULAR_IDENTIFIER_IMEI = 2; // 0x2
+ field public static final int CELLULAR_IDENTIFIER_IMSI = 1; // 0x1
+ field public static final int CELLULAR_IDENTIFIER_SUCI = 3; // 0x3
+ field public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellularIdentifierDisclosure> CREATOR;
+ field public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1; // 0x1
+ field public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6; // 0x6
+ field public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9; // 0x9
+ field public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10; // 0xa
+ field public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8; // 0x8
+ field public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3; // 0x3
+ field public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2; // 0x2
+ field public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11; // 0xb
+ field public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5; // 0x5
+ field public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7; // 0x7
+ field public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4; // 0x4
+ field public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0; // 0x0
+ }
+
public final class DataFailCause {
field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
}
@@ -15388,6 +15787,75 @@ package android.telephony {
field public static final int USER_NOT_MEMBER_OF_CUG = 87; // 0x57
}
+ @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public final class SecurityAlgorithmUpdate implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getConnectionEvent();
+ method public int getEncryption();
+ method public int getIntegrity();
+ method public boolean isUnprotectedEmergency();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 11; // 0xb
+ field public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5; // 0x5
+ field public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2; // 0x2
+ field public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0; // 0x0
+ field public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 10; // 0xa
+ field public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4; // 0x4
+ field public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3; // 0x3
+ field public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1; // 0x1
+ field public static final int CONNECTION_EVENT_VOLTE_RTP = 8; // 0x8
+ field public static final int CONNECTION_EVENT_VOLTE_RTP_SOS = 9; // 0x9
+ field public static final int CONNECTION_EVENT_VOLTE_SIP = 6; // 0x6
+ field public static final int CONNECTION_EVENT_VOLTE_SIP_SOS = 7; // 0x7
+ field public static final int CONNECTION_EVENT_VONR_RTP = 14; // 0xe
+ field public static final int CONNECTION_EVENT_VONR_RTP_SOS = 15; // 0xf
+ field public static final int CONNECTION_EVENT_VONR_SIP = 12; // 0xc
+ field public static final int CONNECTION_EVENT_VONR_SIP_SOS = 13; // 0xd
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SecurityAlgorithmUpdate> CREATOR;
+ field public static final int SECURITY_ALGORITHM_A50 = 0; // 0x0
+ field public static final int SECURITY_ALGORITHM_A51 = 1; // 0x1
+ field public static final int SECURITY_ALGORITHM_A52 = 2; // 0x2
+ field public static final int SECURITY_ALGORITHM_A53 = 3; // 0x3
+ field public static final int SECURITY_ALGORITHM_A54 = 4; // 0x4
+ field public static final int SECURITY_ALGORITHM_AES_CBC = 71; // 0x47
+ field public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73; // 0x49
+ field public static final int SECURITY_ALGORITHM_AES_GCM = 69; // 0x45
+ field public static final int SECURITY_ALGORITHM_AES_GMAC = 70; // 0x46
+ field public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101; // 0x65
+ field public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72; // 0x48
+ field public static final int SECURITY_ALGORITHM_EEA0 = 41; // 0x29
+ field public static final int SECURITY_ALGORITHM_EEA1 = 42; // 0x2a
+ field public static final int SECURITY_ALGORITHM_EEA2 = 43; // 0x2b
+ field public static final int SECURITY_ALGORITHM_EEA3 = 44; // 0x2c
+ field public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100; // 0x64
+ field public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99; // 0x63
+ field public static final int SECURITY_ALGORITHM_GEA0 = 14; // 0xe
+ field public static final int SECURITY_ALGORITHM_GEA1 = 15; // 0xf
+ field public static final int SECURITY_ALGORITHM_GEA2 = 16; // 0x10
+ field public static final int SECURITY_ALGORITHM_GEA3 = 17; // 0x11
+ field public static final int SECURITY_ALGORITHM_GEA4 = 18; // 0x12
+ field public static final int SECURITY_ALGORITHM_GEA5 = 19; // 0x13
+ field public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 75; // 0x4b
+ field public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74; // 0x4a
+ field public static final int SECURITY_ALGORITHM_IMS_NULL = 67; // 0x43
+ field public static final int SECURITY_ALGORITHM_NEA0 = 55; // 0x37
+ field public static final int SECURITY_ALGORITHM_NEA1 = 56; // 0x38
+ field public static final int SECURITY_ALGORITHM_NEA2 = 57; // 0x39
+ field public static final int SECURITY_ALGORITHM_NEA3 = 58; // 0x3a
+ field public static final int SECURITY_ALGORITHM_ORYX = 124; // 0x7c
+ field public static final int SECURITY_ALGORITHM_OTHER = 114; // 0x72
+ field public static final int SECURITY_ALGORITHM_RTP = 85; // 0x55
+ field public static final int SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG = 66; // 0x42
+ field public static final int SECURITY_ALGORITHM_SIP_NULL = 68; // 0x44
+ field public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87; // 0x57
+ field public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88; // 0x58
+ field public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89; // 0x59
+ field public static final int SECURITY_ALGORITHM_SRTP_NULL = 86; // 0x56
+ field public static final int SECURITY_ALGORITHM_UEA0 = 29; // 0x1d
+ field public static final int SECURITY_ALGORITHM_UEA1 = 30; // 0x1e
+ field public static final int SECURITY_ALGORITHM_UEA2 = 31; // 0x1f
+ field public static final int SECURITY_ALGORITHM_UNKNOWN = 113; // 0x71
+ }
+
public class ServiceState implements android.os.Parcelable {
method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
@@ -15612,6 +16080,7 @@ package android.telephony {
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
field public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
+ field @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED = 47; // 0x2f
field @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
@@ -15636,6 +16105,7 @@ package android.telephony {
field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18
field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f
+ field @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SECURITY_ALGORITHMS_CHANGED = 46; // 0x2e
field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1
field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9
field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2
@@ -15654,6 +16124,10 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallStatesChanged(@NonNull java.util.List<android.telephony.CallState>);
}
+ @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public static interface TelephonyCallback.CellularIdentifierDisclosedListener {
+ method public void onCellularIdentifierDisclosedChanged(@NonNull android.telephony.CellularIdentifierDisclosure);
+ }
+
public static interface TelephonyCallback.DataEnabledListener {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
}
@@ -15692,6 +16166,10 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
}
+ @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public static interface TelephonyCallback.SecurityAlgorithmsListener {
+ method public void onSecurityAlgorithmsChanged(@NonNull android.telephony.SecurityAlgorithmUpdate);
+ }
+
@FlaggedApi("com.android.internal.telephony.flags.simultaneous_calling_indications") public static interface TelephonyCallback.SimultaneousCellularCallingSupportListener {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSimultaneousCellularCallingSubscriptionsChanged(@NonNull java.util.Set<java.lang.Integer>);
}
@@ -15743,6 +16221,7 @@ package android.telephony {
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_id_from_carrier_identifier") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getCarrierIdFromCarrierIdentifier(@NonNull android.service.carrier.CarrierIdentifier);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -18515,6 +18994,10 @@ package android.util {
package android.view {
+ public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable {
+ method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") @NonNull public android.view.SurfaceControl.Transaction setPictureProfileHandle(@NonNull android.view.SurfaceControl, @NonNull android.media.quality.PictureProfileHandle);
+ }
+
@UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
method @NonNull public final java.util.List<android.graphics.Rect> getUnrestrictedPreferKeepClearRects();
method @RequiresPermission(android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS) public final void setUnrestrictedPreferKeepClearRects(@NonNull java.util.List<android.graphics.Rect>);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c8ecfa94ec87..967f6194969e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1805,6 +1805,7 @@ package android.hardware.input {
method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void remapModifierKey(int, int);
method @FlaggedApi("com.android.input.flags.device_associations") @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociationByDescriptor(@NonNull String);
method @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociationByPort(@NonNull String);
+ method public void resetLockedModifierState();
field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
}
@@ -2065,6 +2066,29 @@ package android.media {
method public boolean isAidlHal();
}
+ public final class MediaCodec {
+ method @FlaggedApi("android.media.codec.codec_availability") @NonNull public static java.util.List<android.media.MediaCodec.GlobalResourceInfo> getGloballyAvailableResources();
+ method @FlaggedApi("android.media.codec.codec_availability") @NonNull public java.util.List<android.media.MediaCodec.InstanceResourceInfo> getRequiredResources();
+ }
+
+ public abstract static class MediaCodec.Callback {
+ method @FlaggedApi("android.media.codec.codec_availability") public void onRequiredResourcesChanged(@NonNull android.media.MediaCodec);
+ }
+
+ @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.GlobalResourceInfo {
+ ctor public MediaCodec.GlobalResourceInfo();
+ method public long getAvailable();
+ method public long getCapacity();
+ method @NonNull public String getName();
+ }
+
+ @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.InstanceResourceInfo {
+ ctor public MediaCodec.InstanceResourceInfo();
+ method @NonNull public String getName();
+ method public long getPerFrameCount();
+ method public long getStaticCount();
+ }
+
public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
@@ -2295,7 +2319,7 @@ package android.net.wifi.sharedconnectivity.app {
public class SharedConnectivityManager {
method @Nullable public static android.net.wifi.sharedconnectivity.app.SharedConnectivityManager create(@NonNull android.content.Context, @NonNull String, @NonNull String);
- method @FlaggedApi("com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api") @NonNull public android.content.BroadcastReceiver getBroadcastReceiver();
+ method @NonNull public android.content.BroadcastReceiver getBroadcastReceiver();
method @Nullable public android.content.ServiceConnection getServiceConnection();
method public void setService(@Nullable android.os.IInterface);
}
@@ -2469,6 +2493,7 @@ package android.os {
method public boolean areAutoPowerSaveModesEnabled();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public void forceLowPowerStandbyActive(boolean);
method @FlaggedApi("android.os.battery_saver_supported_check_api") public boolean isBatterySaverSupported();
+ method public boolean isInteractive(int);
field public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED = "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED";
field @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public static final int SYSTEM_WAKELOCK = -2147483648; // 0x80000000
}
@@ -2758,6 +2783,17 @@ package android.os.storage {
package android.os.vibrator {
+ @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public final class BasicPwleSegment extends android.os.vibrator.VibrationEffectSegment {
+ method public int describeContents();
+ method public long getDuration();
+ method public float getEndIntensity();
+ method public float getEndSharpness();
+ method public float getStartIntensity();
+ method public float getStartSharpness();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.BasicPwleSegment> CREATOR;
+ }
+
public final class PrebakedSegment extends android.os.vibrator.VibrationEffectSegment {
method public int describeContents();
method public long getDuration();
@@ -3217,6 +3253,7 @@ package android.service.quickaccesswallet {
method @Nullable public android.content.Intent createWalletIntent();
method @Nullable public android.content.Intent createWalletSettingsIntent();
method public void disconnect();
+ method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public void getGestureTargetActivityPendingIntent(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.GesturePendingIntentCallback);
method public void getWalletCards(@NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback);
method public void getWalletCards(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback);
method public void getWalletPendingIntent(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.WalletPendingIntentCallback);
@@ -3228,6 +3265,10 @@ package android.service.quickaccesswallet {
method public void selectWalletCard(@NonNull android.service.quickaccesswallet.SelectWalletCardRequest);
}
+ @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public static interface QuickAccessWalletClient.GesturePendingIntentCallback {
+ method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public void onGesturePendingIntentRetrieved(@Nullable android.app.PendingIntent);
+ }
+
public static interface QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
method public void onWalletCardRetrievalError(@NonNull android.service.quickaccesswallet.GetWalletCardsError);
method public void onWalletCardsRetrieved(@NonNull android.service.quickaccesswallet.GetWalletCardsResponse);
@@ -3254,7 +3295,7 @@ package android.service.quicksettings {
package android.service.settings.preferences {
@FlaggedApi("com.android.settingslib.flags.settings_catalyst") public class SettingsPreferenceServiceClient implements java.lang.AutoCloseable {
- ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String, boolean, @Nullable android.content.ServiceConnection);
+ ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.service.settings.preferences.SettingsPreferenceServiceClient,java.lang.Exception>);
}
}
@@ -3370,6 +3411,10 @@ package android.telephony {
ctor public BarringInfo.BarringServiceInfo(int, boolean, int, int);
}
+ @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public final class CellularIdentifierDisclosure implements android.os.Parcelable {
+ ctor public CellularIdentifierDisclosure(int, int, @NonNull String, boolean);
+ }
+
public class MbmsDownloadSession implements java.lang.AutoCloseable {
field public static final String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override";
}
@@ -3397,6 +3442,10 @@ package android.telephony {
ctor @Deprecated public PreciseDataConnectionState(int, int, int, @NonNull String, @Nullable android.net.LinkProperties, int);
}
+ @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public final class SecurityAlgorithmUpdate implements android.os.Parcelable {
+ ctor public SecurityAlgorithmUpdate(int, int, int, boolean);
+ }
+
public class ServiceState implements android.os.Parcelable {
method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
method public int getDataNetworkType();
@@ -3681,6 +3730,7 @@ package android.view {
method @NonNull public android.view.Display.Mode getDefaultMode();
method public int getRemoveMode();
method @NonNull public int[] getReportedHdrTypes();
+ method @NonNull public float[] getSupportedRefreshRatesLegacy();
method @NonNull public android.graphics.ColorSpace[] getSupportedWideColorGamut();
method @Nullable public android.view.Display.Mode getSystemPreferredDisplayMode();
method public int getType();
@@ -3703,6 +3753,7 @@ package android.view {
public static final class Display.Mode implements android.os.Parcelable {
ctor public Display.Mode(int, int, float);
+ method public float getVsyncRate();
method public boolean isSynthetic();
method public boolean matches(int, int, float);
}
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 08bb08254476..9140bdf4fba7 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -1,4 +1,10 @@
// Baseline format: 1.0
+ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_TYPE:
+ Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE`
+ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER:
+ Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`
+
+
BannedThrow: android.os.vibrator.persistence.VibrationXmlSerializer#serialize(android.os.VibrationEffect, java.io.Writer):
Methods must not throw unchecked exceptions
@@ -2133,6 +2139,8 @@ UnflaggedApi: android.os.BugreportParams#BUGREPORT_MODE_MAX_VALUE:
New API must be flagged with @FlaggedApi: field android.os.BugreportParams.BUGREPORT_MODE_MAX_VALUE
UnflaggedApi: android.os.PowerManager#isBatterySaverSupported():
New API must be flagged with @FlaggedApi: method android.os.PowerManager.isBatterySaverSupported()
+UnflaggedApi: android.os.PowerManager#isInteractive(int):
+ New API must be flagged with @FlaggedApi: method android.os.PowerManager.isInteractive(int)
UnflaggedApi: android.os.UserHandle#USER_CURRENT:
New API must be flagged with @FlaggedApi: field android.os.UserHandle.USER_CURRENT
UnflaggedApi: android.os.UserManager#getAliveUsers():
diff --git a/core/java/Android.bp b/core/java/Android.bp
index cf5ebbaa37b4..ce767f46dd50 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -232,8 +232,11 @@ aidl_interface {
"android.hardware.power-aidl",
],
srcs: [
+ "android/os/CpuHeadroomParamsInternal.aidl",
+ "android/os/GpuHeadroomParamsInternal.aidl",
"android/os/IHintManager.aidl",
"android/os/IHintSession.aidl",
+ "android/os/SessionCreationConfig.aidl",
],
unstable: true,
backend: {
@@ -687,43 +690,8 @@ java_library {
// protolog end
-// Whether to enable read-only system feature codegen.
-gen_readonly_feature_apis = select(release_flag("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS"), {
- true: "true",
- false: "false",
- default: "false",
-})
-
-// Generates com.android.internal.pm.RoSystemFeatures, optionally compiling in
-// details about fixed system features defined by build flags. When disabled,
-// the APIs are simply passthrough stubs with no meaningful side effects.
-// TODO(b/203143243): Implement the `--feature=` aggregation directly with a native soong module.
-genrule {
+java_system_features_srcs {
name: "systemfeatures-gen-srcs",
- cmd: "$(location systemfeatures-gen-tool) com.android.internal.pm.RoSystemFeatures " +
- // --readonly=false (default) makes the codegen an effective no-op passthrough API.
- " --readonly=" + gen_readonly_feature_apis +
- " --feature=AUTOMOTIVE:" + select(release_flag("RELEASE_SYSTEM_FEATURE_AUTOMOTIVE"), {
- any @ value: value,
- default: "",
- }) + " --feature=EMBEDDED:" + select(release_flag("RELEASE_SYSTEM_FEATURE_EMBEDDED"), {
- any @ value: value,
- default: "",
- }) + " --feature=LEANBACK:" + select(release_flag("RELEASE_SYSTEM_FEATURE_LEANBACK"), {
- any @ value: value,
- default: "",
- }) + " --feature=PC:" + select(release_flag("RELEASE_SYSTEM_FEATURE_PC"), {
- any @ value: value,
- default: "",
- }) + " --feature=TELEVISION:" + select(release_flag("RELEASE_SYSTEM_FEATURE_TELEVISION"), {
- any @ value: value,
- default: "",
- }) + " --feature=WATCH:" + select(release_flag("RELEASE_SYSTEM_FEATURE_WATCH"), {
- any @ value: value,
- default: "",
- }) + " > $(out)",
- out: [
- "RoSystemFeatures.java",
- ],
- tools: ["systemfeatures-gen-tool"],
+ full_class_name: "com.android.internal.pm.RoSystemFeatures",
+ visibility: ["//visibility:private"],
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 87acbbf65b2f..72450999993d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -16,9 +16,13 @@
package android.accounts;
+import static android.Manifest.permission.COPY_ACCOUNTS;
+import static android.Manifest.permission.REMOVE_ACCOUNTS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED;
import android.annotation.BroadcastBehavior;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,6 +30,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.Size;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UserHandleAware;
@@ -1312,7 +1317,8 @@ public class AccountManager {
* {@link AccountManagerFuture} must not be used on the main thread.
*
* <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * authenticator that manages the specified account, be a profile owner or have the
+ * {@link android.Manifest.permission#REMOVE_ACCOUNTS} permission.
*
* <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
* MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
@@ -1344,6 +1350,8 @@ public class AccountManager {
* </ul>
*/
@UserHandleAware
+ @RequiresPermission(value = REMOVE_ACCOUNTS, conditional = true)
+ @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
public AccountManagerFuture<Bundle> removeAccount(final Account account,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
return removeAccountAsUser(account, activity, callback, handler, mContext.getUser());
@@ -2019,9 +2027,15 @@ public class AccountManager {
* succeeded.
* @hide
*/
+ @SuppressLint("SamShouldBeLast")
+ @NonNull
+ @SystemApi
+ @RequiresPermission(anyOf = {COPY_ACCOUNTS, INTERACT_ACROSS_USERS_FULL})
+ @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
public AccountManagerFuture<Boolean> copyAccountToUser(
- final Account account, final UserHandle fromUser, final UserHandle toUser,
- AccountManagerCallback<Boolean> callback, Handler handler) {
+ @NonNull final Account account, @NonNull final UserHandle fromUser,
+ @NonNull final UserHandle toUser, @Nullable AccountManagerCallback<Boolean> callback,
+ @Nullable Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
if (toUser == null || fromUser == null) {
throw new IllegalArgumentException("fromUser and toUser cannot be null");
diff --git a/core/java/android/adaptiveauth/OWNERS b/core/java/android/adaptiveauth/OWNERS
index bc8efa92c16f..4310d1a3a9db 100644
--- a/core/java/android/adaptiveauth/OWNERS
+++ b/core/java/android/adaptiveauth/OWNERS
@@ -1 +1 @@
-include /services/core/java/com/android/server/security/adaptiveauthentication/OWNERS \ No newline at end of file
+include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS \ No newline at end of file
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 76098db2dc5b..78566d2fe98d 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1227,7 +1227,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
}
if (finished) {
- endAnimation();
+ endAnimation(true /* fromLastFrame */);
return true;
}
return false;
@@ -1442,8 +1442,12 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
}
private void endAnimation() {
+ endAnimation(false /* fromLastFrame */);
+ }
+
+ private void endAnimation(boolean fromLastFrame) {
final boolean postNotifyEndListener = sPostNotifyEndListenerEnabled && mListeners != null
- && mLastFrameTime > 0;
+ && fromLastFrame && mTotalDuration > 0;
mStarted = false;
mLastFrameTime = -1;
mFirstFrame = -1;
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e849abaf4aec..492c2ffc561f 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1281,16 +1281,20 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
return true;
}
+ private void endAnimation() {
+ endAnimation(false /* fromLastFrame */);
+ }
+
/**
* Called internally to end an animation by removing it from the animations list. Must be
* called on the UI thread.
*/
- private void endAnimation() {
+ private void endAnimation(boolean fromLastFrame) {
if (mAnimationEndRequested) {
return;
}
final boolean postNotifyEndListener = sPostNotifyEndListenerEnabled && mListeners != null
- && mLastFrameTime > 0;
+ && fromLastFrame && getScaledDuration() > 0;
removeAnimationCallback();
mAnimationEndRequested = true;
@@ -1570,7 +1574,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
- endAnimation();
+ endAnimation(true /* fromLastFrame */);
}
return finished;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 419eb7dac5f0..38aea64386a0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1270,27 +1270,22 @@ public class Activity extends ContextThemeWrapper
}
/**
- * To make users aware of system features such as the app header menu and its various
- * functionalities, educational dialogs are shown to demonstrate how to find and utilize these
- * features. Using this method, an activity can specify if it wants these educational dialogs to
- * be shown. When set to {@code true}, these dialogs are not completely blocked; however, the
- * system will be notified that they should not be shown unless necessary. If this API is not
- * called, the system's educational dialogs are not limited by default.
- *
- * <p>This method can be utilized when activities have states where showing an
- * educational dialog would be disruptive to the user. For example, if a game application is
- * expecting prompt user input, this method can be used to limit educational dialogs such as the
- * dialogs that showcase the app header's features which, in this instance, would disrupt the
- * user's experience if shown.</p>
- *
- * <p>Note that educational dialogs may be shown soon after this activity is launched, so
- * this method must be called early if the intent is to limit the dialogs from the start.</p>
+ * Requests to show the “Open in browser” education. “Open in browser” is a feature
+ * within the app header that allows users to switch from an app to the web. The feature
+ * is made available when an application is opened by a user clicking a link or when a
+ * link is provided by an application. Links can be provided by utilizing
+ * {@link AssistContent#EXTRA_AUTHENTICATING_USER_WEB_URI} or
+ * {@link AssistContent#setWebUri}.
+ *
+ * <p>This method should be utilized when an activity wants to nudge the user to switch
+ * to the web application in cases where the web may provide the user with a better
+ * experience. Note that this method does not guarantee that the education will be shown.</p>
*/
@FlaggedApi(com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION)
- public final void setLimitSystemEducationDialogs(boolean limitSystemEducationDialogs) {
+ public final void requestOpenInBrowserEducation() {
try {
ActivityTaskManager
- .getService().setLimitSystemEducationDialogs(mToken, limitSystemEducationDialogs);
+ .getService().requestOpenInBrowserEducation(mToken);
} catch (RemoteException e) {
// Empty
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b447897733e1..33ba05865042 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1017,6 +1017,12 @@ public class ActivityManager {
public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 1 << 6;
/**
+ * @hide
+ * Process is guaranteed cpu time (IE. it will not be frozen).
+ */
+ public static final int PROCESS_CAPABILITY_CPU_TIME = 1 << 7;
+
+ /**
* @hide all capabilities, the ORing of all flags in {@link ProcessCapability}.
*
* Don't expose it as TestApi -- we may add new capabilities any time, which could
@@ -1028,7 +1034,8 @@ public class ActivityManager {
| PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_BFSL
| PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK
- | PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
+ | PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL
+ | PROCESS_CAPABILITY_CPU_TIME;
/**
* All implicit capabilities. This capability set is currently only used for processes under
@@ -1053,6 +1060,7 @@ public class ActivityManager {
pw.print((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
pw.print((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
+ pw.print((caps & PROCESS_CAPABILITY_CPU_TIME) != 0 ? 'T' : '-');
}
/** @hide */
@@ -1065,6 +1073,7 @@ public class ActivityManager {
sb.append((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
sb.append((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
+ sb.append((caps & PROCESS_CAPABILITY_CPU_TIME) != 0 ? 'T' : '-');
}
/**
@@ -2670,62 +2679,6 @@ public class ActivityManager {
*/
public static class RecentTaskInfo extends TaskInfo implements Parcelable {
/**
- * @hide
- */
- public static class PersistedTaskSnapshotData {
- /**
- * The bounds of the task when the last snapshot was taken, may be null if the task is
- * not yet attached to the hierarchy.
- * @see {@link android.window.TaskSnapshot#mTaskSize}.
- * @hide
- */
- public @Nullable Point taskSize;
-
- /**
- * The content insets of the task when the task snapshot was taken.
- * @see {@link android.window.TaskSnapshot#mContentInsets}.
- * @hide
- */
- public @Nullable Rect contentInsets;
-
- /**
- * The size of the last snapshot taken, may be null if there is no associated snapshot.
- * @see {@link android.window.TaskSnapshot#mSnapshot}.
- * @hide
- */
- public @Nullable Point bufferSize;
-
- /**
- * Sets the data from the other data.
- * @hide
- */
- public void set(PersistedTaskSnapshotData other) {
- taskSize = other.taskSize;
- contentInsets = other.contentInsets;
- bufferSize = other.bufferSize;
- }
-
- /**
- * Sets the data from the provided {@param snapshot}.
- * @hide
- */
- public void set(TaskSnapshot snapshot) {
- if (snapshot == null) {
- taskSize = null;
- contentInsets = null;
- bufferSize = null;
- return;
- }
- final HardwareBuffer buffer = snapshot.getHardwareBuffer();
- taskSize = new Point(snapshot.getTaskSize());
- contentInsets = new Rect(snapshot.getContentInsets());
- bufferSize = buffer != null
- ? new Point(buffer.getWidth(), buffer.getHeight())
- : null;
- }
- }
-
- /**
* If this task is currently running, this is the identifier for it.
* If it is not running, this will be -1.
*
@@ -2761,24 +2714,6 @@ public class ActivityManager {
@Deprecated
public int affiliatedTaskId;
- /**
- * Information of organized child tasks.
- *
- * @deprecated No longer used
- * @hide
- */
- @Deprecated
- public ArrayList<RecentTaskInfo> childrenTaskInfos = new ArrayList<>();
-
- /**
- * Information about the last snapshot taken for this task.
- *
- * @deprecated No longer used
- * @hide
- */
- @Deprecated
- public PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
-
public RecentTaskInfo() {
}
@@ -2794,10 +2729,6 @@ public class ActivityManager {
public void readFromParcel(Parcel source) {
id = source.readInt();
persistentId = source.readInt();
- childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader(), android.app.ActivityManager.RecentTaskInfo.class);
- lastSnapshotData.taskSize = source.readTypedObject(Point.CREATOR);
- lastSnapshotData.contentInsets = source.readTypedObject(Rect.CREATOR);
- lastSnapshotData.bufferSize = source.readTypedObject(Point.CREATOR);
super.readTaskFromParcel(source);
}
@@ -2805,10 +2736,6 @@ public class ActivityManager {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeInt(persistentId);
- dest.writeList(childrenTaskInfos);
- dest.writeTypedObject(lastSnapshotData.taskSize, flags);
- dest.writeTypedObject(lastSnapshotData.contentInsets, flags);
- dest.writeTypedObject(lastSnapshotData.bufferSize, flags);
super.writeTaskToParcel(dest, flags);
}
@@ -2875,11 +2802,6 @@ public class ActivityManager {
pw.println(" }");
}
pw.print(" ");
- pw.print(" lastSnapshotData {");
- pw.print(" taskSize=" + lastSnapshotData.taskSize);
- pw.print(" contentInsets=" + lastSnapshotData.contentInsets);
- pw.print(" bufferSize=" + lastSnapshotData.bufferSize);
- pw.println(" }");
}
}
@@ -5291,7 +5213,6 @@ public class ActivityManager {
if (!exported) {
/*
RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
here);
*/
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f80121d0c9b6..eccb6ffb281c 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1150,6 +1150,33 @@ public abstract class ActivityManagerInternal {
public abstract void stopForegroundServiceDelegate(@NonNull ServiceConnection connection);
/**
+ * Notifies that a media foreground service associated with a media session has
+ * transitioned to a "user-disengaged" state.
+ * Upon receiving this notification, service may be removed from the foreground state. It
+ * should only be called by {@link com.android.server.media.MediaSessionService}
+ *
+ * @param packageName The package name of the app running the media foreground service.
+ * @param userId The user ID associated with the foreground service.
+ * @param notificationId The ID of the media notification associated with the foreground
+ * service.
+ */
+ public abstract void notifyInactiveMediaForegroundService(@NonNull String packageName,
+ @UserIdInt int userId, int notificationId);
+
+ /**
+ * Notifies that a media service associated with a media session has transitioned to a
+ * "user-engaged" state. Upon receiving this notification, service will transition to the
+ * foreground state. It should only be called by
+ * {@link com.android.server.media.MediaSessionService}
+ *
+ * @param packageName The package name of the app running the media service.
+ * @param userId The user ID associated with the service.
+ * @param notificationId The ID of the media notification associated with the service.
+ */
+ public abstract void notifyActiveMediaForegroundService(@NonNull String packageName,
+ @UserIdInt int userId, int notificationId);
+
+ /**
* Same as {@link android.app.IActivityManager#startProfile(int userId)}, but it would succeed
* even if the profile is disabled - it should only be called by
* {@link com.android.server.devicepolicy.DevicePolicyManagerService} when starting a profile
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 60b8f80d8f2d..f8186d68e210 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1961,12 +1961,8 @@ public final class ActivityThread extends ClientTransactionHandler
@Override
public void dumpCacheInfo(ParcelFileDescriptor pfd, String[] args) {
- try {
- PropertyInvalidatedCache.dumpCacheInfo(pfd, args);
- BroadcastStickyCache.dump(pfd);
- } finally {
- IoUtils.closeQuietly(pfd);
- }
+ PropertyInvalidatedCache.dumpCacheInfo(pfd, args);
+ IoUtils.closeQuietly(pfd);
}
private File getDatabasesDir(Context context) {
@@ -8847,10 +8843,10 @@ public final class ActivityThread extends ClientTransactionHandler
// Call per-process mainline module initialization.
initializeMainlineModules();
- Process.setArgV0("<pre-initialized>");
-
Looper.prepareMainLooper();
+ Process.setArgV0("<pre-initialized>");
+
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8b37dbd04bec..34765781d105 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1624,9 +1624,19 @@ public class AppOpsManager {
/** @hide Access to read oxygen saturation. */
public static final int OP_READ_OXYGEN_SATURATION = AppOpEnums.APP_OP_READ_OXYGEN_SATURATION;
+ /** @hide Access to write system preferences. */
+ public static final int OP_WRITE_SYSTEM_PREFERENCES =
+ AppOpEnums.APP_OP_WRITE_SYSTEM_PREFERENCES;
+
+ /** @hide Access to audio playback and control APIs. */
+ public static final int OP_CONTROL_AUDIO = AppOpEnums.APP_OP_CONTROL_AUDIO;
+
+ /** @hide Similar to {@link OP_CONTROL_AUDIO}, but doesn't require capabilities. */
+ public static final int OP_CONTROL_AUDIO_PARTIAL = AppOpEnums.APP_OP_CONTROL_AUDIO_PARTIAL;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 153;
+ public static final int _NUM_OP = 156;
/**
* All app ops represented as strings.
@@ -1783,6 +1793,9 @@ public class AppOpsManager {
OPSTR_READ_SKIN_TEMPERATURE,
OPSTR_RANGING,
OPSTR_READ_OXYGEN_SATURATION,
+ OPSTR_WRITE_SYSTEM_PREFERENCES,
+ OPSTR_CONTROL_AUDIO,
+ OPSTR_CONTROL_AUDIO_PARTIAL,
})
public @interface AppOpString {}
@@ -2540,6 +2553,15 @@ public class AppOpsManager {
@FlaggedApi(Flags.FLAG_RANGING_PERMISSION_ENABLED)
public static final String OPSTR_RANGING = "android:ranging";
+ /** @hide Access to system preferences write services */
+ public static final String OPSTR_WRITE_SYSTEM_PREFERENCES = "android:write_system_preferences";
+
+ /** @hide Access to audio playback and control APIs */
+ public static final String OPSTR_CONTROL_AUDIO = "android:control_audio";
+
+ /** @hide Access to a audio playback and control APIs without capability requirements */
+ public static final String OPSTR_CONTROL_AUDIO_PARTIAL = "android:control_audio_partial";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2656,6 +2678,7 @@ public class AppOpsManager {
OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
OP_MEDIA_ROUTING_CONTROL,
OP_READ_SYSTEM_GRAMMATICAL_GENDER,
+ OP_WRITE_SYSTEM_PREFERENCES,
};
@SuppressWarnings("FlaggedApi")
@@ -3144,6 +3167,14 @@ public class AppOpsManager {
Flags.replaceBodySensorPermissionEnabled()
? HealthPermissions.READ_OXYGEN_SATURATION : null)
.setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_SYSTEM_PREFERENCES, OPSTR_WRITE_SYSTEM_PREFERENCES,
+ "WRITE_SYSTEM_PREFERENCES").setPermission(
+ com.android.settingslib.flags.Flags.writeSystemPreferencePermissionEnabled()
+ ? Manifest.permission.WRITE_SYSTEM_PREFERENCES : null).build(),
+ new AppOpInfo.Builder(OP_CONTROL_AUDIO, OPSTR_CONTROL_AUDIO,
+ "CONTROL_AUDIO").setDefaultMode(AppOpsManager.MODE_FOREGROUND).build(),
+ new AppOpInfo.Builder(OP_CONTROL_AUDIO_PARTIAL, OPSTR_CONTROL_AUDIO_PARTIAL,
+ "CONTROL_AUDIO_PARTIAL").setDefaultMode(AppOpsManager.MODE_FOREGROUND).build(),
};
// The number of longs needed to form a full bitmask of app ops
@@ -8903,12 +8934,21 @@ public class AppOpsManager {
}
/**
- * Do a quick check for whether an application might be able to perform an operation.
- * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
- * String, String)} or {@link #startOp(String, int, String, String, String)} for your actual
- * security checks. This function can just be used for a quick check to see if an operation has
- * been disabled for the application, as an early reject of some work. This does not modify the
- * time stamp or other data about the operation.
+ * Check whether an application might be able to perform an operation.
+ * <p>
+ * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is
+ * <em>not</em> a security check; you must use {@link #noteOp(String, int, String, String,
+ * String)} or {@link #startOp(String, int, String, String, String)} for your actual security
+ * checks. This function can just be used for a quick check to see if an operation has been
+ * disabled for the application, as an early reject of some work.
+ * <p>
+ * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, this
+ * is no longer an unsafe check, and it does the same security check as {@link #noteOp(String,
+ * int, String, String, String)} and {@link #startOp(String, int, String, String, String)}.
+ * However, it's preferred to use {@link #checkOp(String, int, String)}, since the word "unsafe"
+ * in the name of this API is no longer accurate.
+ * <p>
+ * This API does not modify the time stamp or other data about the operation.
*
* @param op The operation to check. One of the OPSTR_* constants.
* @param uid The user id of the application attempting to perform the operation.
@@ -8917,31 +8957,108 @@ public class AppOpsManager {
* {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
* causing the app to crash).
* @throws SecurityException If the app has been configured to crash on this op.
+ *
+ * @deprecated Use {@link #checkOp(String, int, String)}
*/
+ @Deprecated
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
public int unsafeCheckOp(@NonNull String op, int uid, @NonNull String packageName) {
return checkOp(strOpToOp(op), uid, packageName);
}
/**
- * @deprecated Renamed to {@link #unsafeCheckOp(String, int, String)}.
+ * Check whether an application can perform an operation.
+ * <p>
+ * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is
+ * <em>not</em> a security check; you must use {@link #noteOp(String, int, String, String,
+ * String)} or {@link #startOp(String, int, String, String, String)} for your actual security
+ * checks. This function can just be used for a quick check to see if an operation has been
+ * disabled for the application, as an early reject of some work.
+ * <p>
+ * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, it
+ * does the same security check as {@link #noteOp(String, int, String, String, String)} and
+ * {@link #startOp(String, int, String, String, String)}, and should be preferred to use.
+ * <p>
+ * This API does not modify the time stamp or other data about the operation.
+ *
+ * @param op The operation to check. One of the OPSTR_* constants.
+ * @param uid The uid of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
*/
- @Deprecated
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
public int checkOp(@NonNull String op, int uid, @NonNull String packageName) {
return checkOp(strOpToOp(op), uid, packageName);
}
/**
- * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
- * returns {@link #MODE_ERRORED}.
+ * Like {@link #unsafeCheckOp(String, int, String)} but instead of throwing a
+ * {@link SecurityException} it returns {@link #MODE_ERRORED}.
+ *
+ * @deprecated Use {@link #checkOpNoThrow(String, int, String)}
*/
+ @Deprecated
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
public int unsafeCheckOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return checkOpNoThrow(strOpToOp(op), uid, packageName);
}
/**
- * @deprecated Renamed to {@link #unsafeCheckOpNoThrow(String, int, String)}.
+ * Check whether an application can perform an operation. It does the same security check as
+ * {@link #noteOp(String, int, String, String, String)} and {@link #startOp(String, int, String,
+ * String, String)}, but does not modify the time stamp or other data about the operation.
+ *
+ * @param op The operation to check. One of the OPSTR_* constants.
+ * @param uid The uid of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} of the
+ * calling context or {@code null} for default attribution
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
+ * if it is not allowed and should be silently ignored (without causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
*/
- @Deprecated
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
+ public int checkOp(@NonNull String op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag) {
+ int mode = checkOpNoThrow(strOpToOp(op), uid, packageName, attributionTag,
+ Context.DEVICE_ID_DEFAULT);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException(buildSecurityExceptionMsg(strOpToOp(op), uid, packageName));
+ }
+ return mode;
+ }
+
+ /**
+ * Like {@link #checkOp(String, int, String, String)} but instead of throwing a
+ * {@link SecurityException} it returns {@link #MODE_ERRORED}.
+ */
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
+ public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag) {
+ return checkOpNoThrow(strOpToOp(op), uid, packageName, attributionTag,
+ Context.DEVICE_ID_DEFAULT);
+ }
+
+ /**
+ * Like {@link #checkOp(String, int, String, String)} but returns the <em>raw</em> mode
+ * associated with the op. Does not throw a security exception, does not translate
+ * {@link #MODE_FOREGROUND}.
+ */
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
+ public int checkOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag) {
+ return checkOpRawNoThrow(strOpToOp(op), uid, packageName, attributionTag,
+ Context.DEVICE_ID_DEFAULT);
+ }
+
+ /**
+ * Like {@link #checkOp(String, int, String)} but instead of throwing a
+ * {@link SecurityException} it returns {@link #MODE_ERRORED}.
+ */
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return checkOpNoThrow(strOpToOp(op), uid, packageName);
}
@@ -8949,16 +9066,23 @@ public class AppOpsManager {
/**
* Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
* Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
+ *
+ * @deprecated Use {@link #checkOpRawNoThrow(String, int, String, String)} instead
*/
+ @Deprecated
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) {
return unsafeCheckOpRawNoThrow(op, uid, packageName);
}
/**
- * Like {@link #unsafeCheckOpNoThrow(String, int, String)} but returns the <em>raw</em>
- * mode associated with the op. Does not throw a security exception, does not translate
- * {@link #MODE_FOREGROUND}.
+ * Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
+ * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
+ *
+ * @deprecated Use {@link #checkOpRawNoThrow(String, int, String, String)} instead
*/
+ @Deprecated
+ @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return unsafeCheckOpRawNoThrow(strOpToOp(op), uid, packageName);
}
@@ -8969,8 +9093,9 @@ public class AppOpsManager {
* @hide
*/
public int unsafeCheckOpRawNoThrow(int op, @NonNull AttributionSource attributionSource) {
- return unsafeCheckOpRawNoThrow(op, attributionSource.getUid(),
- attributionSource.getPackageName(), attributionSource.getDeviceId());
+ return checkOpRawNoThrow(op, attributionSource.getUid(),
+ attributionSource.getPackageName(), attributionSource.getAttributionTag(),
+ attributionSource.getDeviceId());
}
/**
@@ -8991,20 +9116,20 @@ public class AppOpsManager {
* @hide
*/
public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) {
- return unsafeCheckOpRawNoThrow(op, uid, packageName, Context.DEVICE_ID_DEFAULT);
+ return checkOpRawNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT);
}
- private int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName,
- int virtualDeviceId) {
+ private int checkOpRawNoThrow(int op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, int virtualDeviceId) {
try {
int mode;
if (isAppOpModeCachingEnabled(op)) {
mode = sAppOpModeCache.query(
- new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null,
+ new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag,
"unsafeCheckOpRawNoThrow"));
} else {
mode = mService.checkOperationRawForDevice(
- op, uid, packageName, null, virtualDeviceId);
+ op, uid, packageName, attributionTag, virtualDeviceId);
}
return mode;
} catch (RemoteException e) {
@@ -9403,10 +9528,12 @@ public class AppOpsManager {
}
/**
- * Do a quick check for whether an application might be able to perform an operation.
- * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
- * String, String)} or {@link #startOp(int, int, String, boolean, String, String)} for your
- * actual security checks, which also ensure that the given uid and package name are consistent.
+ * Check whether an application can perform an operation.
+ * <p>
+ * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is
+ * <em>not</em> a security check; you must use {@link #noteOp(String, int, String, String,
+ * String)} or {@link #startOp(int, int, String, boolean, String, String)} for your actual
+ * security checks, which also ensure that the given uid and package name are consistent.
* This function can just be used for a quick check to see if an operation has been disabled for
* the application, as an early reject of some work. This does not modify the time stamp or
* other data about the operation.
@@ -9422,6 +9549,13 @@ public class AppOpsManager {
* as {@link #MODE_ALLOWED}.</li>
* </ul>
*
+ * <p>
+ * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, it
+ * does the same security check as {@link #noteOp(String, int, String, String, String)} and
+ * {@link #startOp(String, int, String, String, String)}.
+ * <p>
+ * This API does not modify the time stamp or other data about the operation.
+ *
* @param op The operation to check. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
@@ -9433,29 +9567,11 @@ public class AppOpsManager {
*/
@UnsupportedAppUsage
public int checkOp(int op, int uid, String packageName) {
- try {
- int mode;
- if (isAppOpModeCachingEnabled(op)) {
- mode = sAppOpModeCache.query(
- new AppOpModeQuery(op, uid, packageName, Context.DEVICE_ID_DEFAULT, null,
- "checkOp"));
- if (mode == MODE_FOREGROUND) {
- // We only cache raw mode. If the mode is FOREGROUND, we need another binder
- // call to fetch translated value based on the process state.
- mode = mService.checkOperationForDevice(op, uid, packageName,
- Context.DEVICE_ID_DEFAULT);
- }
- } else {
- mode = mService.checkOperationForDevice(op, uid, packageName,
- Context.DEVICE_ID_DEFAULT);
- }
- if (mode == MODE_ERRORED) {
- throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
- }
- return mode;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ int mode = checkOpNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
+ return mode;
}
/**
@@ -9468,7 +9584,7 @@ public class AppOpsManager {
*/
public int checkOpNoThrow(int op, AttributionSource attributionSource) {
return checkOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(),
- attributionSource.getDeviceId());
+ attributionSource.getAttributionTag(), attributionSource.getDeviceId());
}
/**
@@ -9481,23 +9597,26 @@ public class AppOpsManager {
*/
@UnsupportedAppUsage
public int checkOpNoThrow(int op, int uid, String packageName) {
- return checkOpNoThrow(op, uid, packageName, Context.DEVICE_ID_DEFAULT);
+ return checkOpNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT);
}
- private int checkOpNoThrow(int op, int uid, String packageName, int virtualDeviceId) {
+ private int checkOpNoThrow(int op, int uid, String packageName, @Nullable String attributionTag,
+ int virtualDeviceId) {
try {
int mode;
if (isAppOpModeCachingEnabled(op)) {
mode = sAppOpModeCache.query(
- new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null,
+ new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag,
"checkOpNoThrow"));
if (mode == MODE_FOREGROUND) {
// We only cache raw mode. If the mode is FOREGROUND, we need another binder
// call to fetch translated value based on the process state.
- mode = mService.checkOperationForDevice(op, uid, packageName, virtualDeviceId);
+ mode = mService.checkOperationForDevice(op, uid, packageName, attributionTag,
+ virtualDeviceId);
}
} else {
- mode = mService.checkOperationForDevice(op, uid, packageName, virtualDeviceId);
+ mode = mService.checkOperationForDevice(op, uid, packageName, attributionTag,
+ virtualDeviceId);
}
return mode;
} catch (RemoteException e) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index fb5a12b49921..7e0a9b69b7bd 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -16,6 +16,7 @@
package android.app;
+import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
import static android.app.PropertyInvalidatedCache.createSystemCacheKey;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED;
@@ -783,43 +784,24 @@ public class ApplicationPackageManager extends PackageManager {
}
/**
+ * The API and cache name for hasSystemFeature.
+ */
+ private static final String HAS_SYSTEM_FEATURE_API = "has_system_feature";
+
+ /**
* Identifies a single hasSystemFeature query.
*/
- @Immutable
- private static final class HasSystemFeatureQuery {
- public final String name;
- public final int version;
- public HasSystemFeatureQuery(String n, int v) {
- name = n;
- version = v;
- }
- @Override
- public String toString() {
- return String.format("HasSystemFeatureQuery(name=\"%s\", version=%d)",
- name, version);
- }
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof HasSystemFeatureQuery) {
- HasSystemFeatureQuery r = (HasSystemFeatureQuery) o;
- return Objects.equals(name, r.name) && version == r.version;
- } else {
- return false;
- }
- }
- @Override
- public int hashCode() {
- return Objects.hashCode(name) * 13 + version;
- }
- }
+ private record HasSystemFeatureQuery(String name, int version) {}
// Make this cache relatively large. There are many system features and
// none are ever invalidated. MPTS tests suggests that the cache should
// hold at least 150 entries.
private final static PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>
- mHasSystemFeatureCache =
- new PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>(
- 256, createSystemCacheKey("has_system_feature")) {
+ mHasSystemFeatureCache = new PropertyInvalidatedCache<>(
+ new PropertyInvalidatedCache.Args(MODULE_SYSTEM)
+ .api(HAS_SYSTEM_FEATURE_API).maxEntries(256).isolateUids(false),
+ HAS_SYSTEM_FEATURE_API, null) {
+
@Override
public Boolean recompute(HasSystemFeatureQuery query) {
try {
@@ -1835,7 +1817,6 @@ public class ApplicationPackageManager extends PackageManager {
if (false) {
RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resId)
+ " from package " + packageName
+ ": app scale=" + r.getCompatibilityInfo().applicationScale
diff --git a/core/java/android/app/BroadcastStickyCache.java b/core/java/android/app/BroadcastStickyCache.java
deleted file mode 100644
index ea8173191a3f..000000000000
--- a/core/java/android/app/BroadcastStickyCache.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.UsbManager;
-import android.media.AudioManager;
-import android.net.ConnectivityManager;
-import android.net.TetheringManager;
-import android.net.nsd.NsdManager;
-import android.net.wifi.WifiManager;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemProperties;
-import android.os.UpdateLock;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-import android.util.IndentingPrintWriter;
-import android.view.WindowManagerPolicyConstants;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
-
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/** @hide */
-public class BroadcastStickyCache {
-
- private static final String[] CACHED_BROADCAST_ACTIONS = {
- AudioManager.ACTION_HDMI_AUDIO_PLUG,
- AudioManager.ACTION_HEADSET_PLUG,
- AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED,
- AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED,
- AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION,
- AudioManager.RINGER_MODE_CHANGED_ACTION,
- ConnectivityManager.CONNECTIVITY_ACTION,
- Intent.ACTION_BATTERY_CHANGED,
- Intent.ACTION_DEVICE_STORAGE_FULL,
- Intent.ACTION_DEVICE_STORAGE_LOW,
- Intent.ACTION_SIM_STATE_CHANGED,
- NsdManager.ACTION_NSD_STATE_CHANGED,
- TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED,
- TetheringManager.ACTION_TETHER_STATE_CHANGED,
- UpdateLock.UPDATE_LOCK_CHANGED,
- UsbManager.ACTION_USB_STATE,
- WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED,
- WifiManager.NETWORK_STATE_CHANGED_ACTION,
- WifiManager.SUPPLICANT_STATE_CHANGED_ACTION,
- WifiManager.WIFI_STATE_CHANGED_ACTION,
- WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
- WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED,
- "android.net.conn.INET_CONDITION_ACTION" // ConnectivityManager.INET_CONDITION_ACTION
- };
-
- @GuardedBy("sCachedStickyBroadcasts")
- private static final ArrayList<CachedStickyBroadcast> sCachedStickyBroadcasts =
- new ArrayList<>();
-
- @GuardedBy("sCachedPropertyHandles")
- private static final ArrayMap<String, SystemProperties.Handle> sCachedPropertyHandles =
- new ArrayMap<>();
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public static boolean useCache(@Nullable IntentFilter filter) {
- if (!shouldCache(filter)) {
- return false;
- }
- synchronized (sCachedStickyBroadcasts) {
- final CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter);
- if (cachedStickyBroadcast == null) {
- return false;
- }
- final long version = cachedStickyBroadcast.propertyHandle.getLong(-1 /* def */);
- return version > 0 && cachedStickyBroadcast.version == version;
- }
- }
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public static void add(@Nullable IntentFilter filter, @Nullable Intent intent) {
- if (!shouldCache(filter)) {
- return;
- }
- synchronized (sCachedStickyBroadcasts) {
- CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter);
- if (cachedStickyBroadcast == null) {
- final String key = getKey(filter.getAction(0));
- final SystemProperties.Handle handle = SystemProperties.find(key);
- final long version = handle == null ? -1 : handle.getLong(-1 /* def */);
- if (version == -1) {
- return;
- }
- cachedStickyBroadcast = new CachedStickyBroadcast(filter, handle);
- sCachedStickyBroadcasts.add(cachedStickyBroadcast);
- cachedStickyBroadcast.intent = intent;
- cachedStickyBroadcast.version = version;
- } else {
- cachedStickyBroadcast.intent = intent;
- cachedStickyBroadcast.version = cachedStickyBroadcast.propertyHandle
- .getLong(-1 /* def */);
- }
- }
- }
-
- private static boolean shouldCache(@Nullable IntentFilter filter) {
- if (!Flags.useStickyBcastCache()) {
- return false;
- }
- if (filter == null || filter.safeCountActions() != 1) {
- return false;
- }
- if (!ArrayUtils.contains(CACHED_BROADCAST_ACTIONS, filter.getAction(0))) {
- return false;
- }
- return true;
- }
-
- @VisibleForTesting
- @NonNull
- public static String getKey(@NonNull String action) {
- return "cache_key.system_server.sticky_bcast." + action;
- }
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- @Nullable
- public static Intent getIntentUnchecked(@NonNull IntentFilter filter) {
- synchronized (sCachedStickyBroadcasts) {
- final CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter);
- return cachedStickyBroadcast.intent;
- }
- }
-
- @GuardedBy("sCachedStickyBroadcasts")
- @Nullable
- private static CachedStickyBroadcast getValueUncheckedLocked(@NonNull IntentFilter filter) {
- for (int i = sCachedStickyBroadcasts.size() - 1; i >= 0; --i) {
- final CachedStickyBroadcast cachedStickyBroadcast = sCachedStickyBroadcasts.get(i);
- if (IntentFilter.filterEquals(filter, cachedStickyBroadcast.filter)) {
- return cachedStickyBroadcast;
- }
- }
- return null;
- }
-
- public static void incrementVersion(@NonNull String action) {
- if (!shouldIncrementVersion(action)) {
- return;
- }
- final String key = getKey(action);
- synchronized (sCachedPropertyHandles) {
- SystemProperties.Handle handle = sCachedPropertyHandles.get(key);
- final long version;
- if (handle == null) {
- handle = SystemProperties.find(key);
- if (handle != null) {
- sCachedPropertyHandles.put(key, handle);
- }
- }
- version = handle == null ? 0 : handle.getLong(0 /* def */);
- SystemProperties.set(key, String.valueOf(version + 1));
- if (handle == null) {
- sCachedPropertyHandles.put(key, SystemProperties.find(key));
- }
- }
- }
-
- public static void incrementVersionIfExists(@NonNull String action) {
- if (!shouldIncrementVersion(action)) {
- return;
- }
- final String key = getKey(action);
- synchronized (sCachedPropertyHandles) {
- final SystemProperties.Handle handle = sCachedPropertyHandles.get(key);
- if (handle == null) {
- return;
- }
- final long version = handle.getLong(0 /* def */);
- SystemProperties.set(key, String.valueOf(version + 1));
- }
- }
-
- private static boolean shouldIncrementVersion(@NonNull String action) {
- if (!Flags.useStickyBcastCache()) {
- return false;
- }
- if (!ArrayUtils.contains(CACHED_BROADCAST_ACTIONS, action)) {
- return false;
- }
- return true;
- }
-
- @VisibleForTesting
- public static void clearForTest() {
- synchronized (sCachedStickyBroadcasts) {
- sCachedStickyBroadcasts.clear();
- }
- synchronized (sCachedPropertyHandles) {
- sCachedPropertyHandles.clear();
- }
- }
-
- public static void dump(@NonNull ParcelFileDescriptor pfd) {
- if (!Flags.useStickyBcastCache()) {
- return;
- }
- final PrintWriter pw = new FastPrintWriter(new FileOutputStream(pfd.getFileDescriptor()));
- synchronized (sCachedStickyBroadcasts) {
- dumpLocked(pw);
- }
- pw.flush();
- }
-
- @GuardedBy("sCachedStickyBroadcasts")
- private static void dumpLocked(@NonNull PrintWriter pw) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(
- pw, " " /* singleIndent */, " " /* prefix */);
- ipw.println("Cached sticky broadcasts:");
- ipw.increaseIndent();
- final int count = sCachedStickyBroadcasts.size();
- if (count == 0) {
- ipw.println("<empty>");
- } else {
- for (int i = 0; i < count; ++i) {
- final CachedStickyBroadcast cachedStickyBroadcast = sCachedStickyBroadcasts.get(i);
- ipw.print("Entry #"); ipw.print(i); ipw.println(":");
- ipw.increaseIndent();
- ipw.print("filter="); ipw.println(cachedStickyBroadcast.filter.toLongString());
- ipw.print("intent="); ipw.println(cachedStickyBroadcast.intent);
- ipw.print("version="); ipw.println(cachedStickyBroadcast.version);
- ipw.print("handle="); ipw.println(cachedStickyBroadcast.propertyHandle);
- ipw.decreaseIndent();
- }
- }
- ipw.decreaseIndent();
- }
-
- private static final class CachedStickyBroadcast {
- @NonNull public final IntentFilter filter;
- @Nullable public Intent intent;
- @IntRange(from = 0) public long version;
- @NonNull public final SystemProperties.Handle propertyHandle;
-
- CachedStickyBroadcast(@NonNull IntentFilter filter,
- @NonNull SystemProperties.Handle propertyHandle) {
- this.filter = filter;
- this.propertyHandle = propertyHandle;
- }
- }
-}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 3ae60d71facd..cd56957ed5d1 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1922,19 +1922,10 @@ class ContextImpl extends Context {
}
}
try {
- final Intent intent;
- if (receiver == null && BroadcastStickyCache.useCache(filter)) {
- intent = BroadcastStickyCache.getIntentUnchecked(filter);
- } else {
- intent = ActivityManager.getService().registerReceiverWithFeature(
- mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
- AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission,
- userId,
- flags);
- if (receiver == null) {
- BroadcastStickyCache.add(filter, intent);
- }
- }
+ final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
+ mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
+ AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
+ flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
// TODO: determine at registration time if caller is
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 16444dc5adde..6efc4ef55180 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -62,6 +62,7 @@ import android.content.pm.ServiceInfo.ForegroundServiceType;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
+import android.health.connect.HealthPermissions;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -484,21 +485,35 @@ public abstract class ForegroundServiceTypePolicy {
*/
public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_HEALTH =
new ForegroundServiceTypePolicyInfo(
- FOREGROUND_SERVICE_TYPE_HEALTH,
- ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
- ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
- new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
- new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_HEALTH)
- }, true),
- new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
- new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION),
- new RegularPermission(Manifest.permission.BODY_SENSORS),
- new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS),
- }, false),
- FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */,
- true /* permissionEnforcementFlagDefaultValue */,
- false /* foregroundOnlyPermission */
- );
+ FOREGROUND_SERVICE_TYPE_HEALTH,
+ ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
+ ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
+ new ForegroundServiceTypePermissions(
+ new ForegroundServiceTypePermission[] {
+ new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_HEALTH)
+ },
+ true),
+ new ForegroundServiceTypePermissions(getAllowedHealthPermissions(), false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */,
+ false /* foregroundOnlyPermission */);
+
+ /** Returns the permissions needed for the policy of the health foreground service type. */
+ private static ForegroundServiceTypePermission[] getAllowedHealthPermissions() {
+ final ArrayList<ForegroundServiceTypePermission> permissions = new ArrayList<>();
+ permissions.add(new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION));
+ permissions.add(new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS));
+
+ if (android.permission.flags.Flags.replaceBodySensorPermissionEnabled()) {
+ permissions.add(new RegularPermission(HealthPermissions.READ_HEART_RATE));
+ permissions.add(new RegularPermission(HealthPermissions.READ_SKIN_TEMPERATURE));
+ permissions.add(new RegularPermission(HealthPermissions.READ_OXYGEN_SATURATION));
+ } else {
+ permissions.add(new RegularPermission(Manifest.permission.BODY_SENSORS));
+ }
+
+ return permissions.toArray(new ForegroundServiceTypePermission[permissions.size()]);
+ }
/**
* The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING}.
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 961501503348..7a329cd541a2 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -112,8 +112,8 @@ interface IActivityClientController {
oneway void requestMultiwindowFullscreen(in IBinder token, in int request,
in IRemoteCallback callback);
- oneway void startLockTaskModeByToken(in IBinder token);
- oneway void stopLockTaskModeByToken(in IBinder token);
+ void startLockTaskModeByToken(in IBinder token);
+ void stopLockTaskModeByToken(in IBinder token);
oneway void showLockTaskEscapeMessage(in IBinder token);
void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 34a3ad19b270..0668958b2d5c 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -358,7 +358,7 @@ interface IActivityManager {
@UnsupportedAppUsage
void resumeAppSwitches();
boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId,
- int backupDestination);
+ int backupDestination, boolean useRestrictedMode);
void backupAgentCreated(in String packageName, in IBinder agent, int userId);
void unbindBackupAgent(in ApplicationInfo appInfo);
int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
@@ -864,7 +864,8 @@ interface IActivityManager {
/**
* Suppress or reenable the rate limit on foreground service notification deferral.
- * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG.
+ * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG
+ * and WRITE_ALLOWLISTED_DEVICE_CONFIG.
*
* @param enable false to suppress rate-limit policy; true to reenable it.
*/
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index ec7b72ec677e..c6f62a21641d 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -242,8 +242,8 @@ interface IActivityTaskManager {
boolean supportsLocalVoiceInteraction();
- // Sets whether system educational dialogs should be limited
- void setLimitSystemEducationDialogs(IBinder appToken, boolean limitSystemEducationDialogs);
+ // Requests the "Open in browser" education to be shown
+ void requestOpenInBrowserEducation(IBinder appToken);
// Get device configuration
ConfigurationInfo getDeviceConfigurationInfo();
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 0654ac2f33ce..a6c1a57a8131 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -124,7 +124,7 @@ interface INotificationManager
boolean onlyHasDefaultChannel(String pkg, int uid);
boolean areChannelsBypassingDnd();
ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid);
- List<String> getPackagesBypassingDnd(int userId, boolean includeConversationChannels);
+ ParceledListSlice getPackagesBypassingDnd(int userId);
boolean isPackagePaused(String pkg);
void deleteNotificationHistoryItem(String pkg, int uid, long postedTime);
boolean isPermissionFixed(String pkg, int userId);
@@ -270,4 +270,6 @@ interface INotificationManager
int[] getAllowedAdjustmentKeyTypes();
void setAssistantAdjustmentKeyTypeState(int type, boolean enabled);
+ String[] getTypeAdjustmentDeniedPackages();
+ void setTypeAdjustmentForPackageState(String pkg, boolean enabled);
}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index f2228f94ff01..4a9a28607796 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -178,6 +178,11 @@ oneway interface ITaskStackListener {
void onRecentTaskListFrozenChanged(boolean frozen);
/**
+ * Called when a task is removed from the recent tasks list as a result of adding a new task.
+ */
+ void onRecentTaskRemovedForAddTask(int taskId);
+
+ /**
* Called when a task gets or loses focus.
*
* @param taskId id of the task.
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 62820ad5a4d6..67f7bee4028e 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -18,6 +18,7 @@ package android.app;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,7 +53,9 @@ import android.view.IOnKeyguardExitResult;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.IDeviceLockedStateListener;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.util.Preconditions;
@@ -253,6 +256,26 @@ public class KeyguardManager {
private final ArrayMap<KeyguardLockedStateListener, Executor>
mKeyguardLockedStateListeners = new ArrayMap<>();
+ private final IDeviceLockedStateListener mIDeviceLockedStateListener =
+ new IDeviceLockedStateListener.Stub() {
+ @Override
+ public void onDeviceLockedStateChanged(boolean isDeviceLocked) {
+ if (!Flags.deviceUnlockListener()) {
+ return;
+ }
+ synchronized (mDeviceLockedStateListeners) {
+ mDeviceLockedStateListeners.forEach((listener, executor) -> {
+ executor.execute(
+ () -> listener.onDeviceLockedStateChanged(isDeviceLocked));
+ });
+ }
+ }
+ };
+
+ @GuardedBy("mDeviceLockedStateListeners")
+ private final ArrayMap<DeviceLockedStateListener, Executor>
+ mDeviceLockedStateListeners = new ArrayMap<>();
+
/**
* Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
* if enrolled) for the current user of the device. The caller is expected to launch this
@@ -1370,4 +1393,77 @@ public class KeyguardManager {
}
}
}
+
+
+ /**
+ * Listener for device locked state changes.
+ */
+ @FunctionalInterface
+ @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER)
+ public interface DeviceLockedStateListener {
+ /**
+ * Callback function that executes when the device locked state changes.
+ */
+ void onDeviceLockedStateChanged(boolean isDeviceLocked);
+ }
+
+
+ /**
+ * Registers a listener to execute when the device locked state changes.
+ *
+ * @param executor The {@link Executor} where the {@code listener} will be invoked
+ * @param listener The listener to add to receive device locked state changes.
+ *
+ * @see #isDeviceLocked()
+ * @see #removeDeviceLockedStateListener(DeviceLockedStateListener)
+ */
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER)
+ public void addDeviceLockedStateListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull DeviceLockedStateListener listener) {
+ if (!Flags.deviceUnlockListener()) {
+ return;
+ }
+
+ synchronized (mDeviceLockedStateListeners) {
+ mDeviceLockedStateListeners.put(listener, executor);
+ if (mDeviceLockedStateListeners.size() > 1) {
+ return;
+ }
+ try {
+ mTrustManager.registerDeviceLockedStateListener(mIDeviceLockedStateListener,
+ mContext.getDeviceId());
+ } catch (RemoteException re) {
+ Log.d(TAG, "TrustManager service died", re);
+ }
+ }
+ }
+
+ /**
+ * Unregisters a listener that executes when the device locked state changes.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see #isDeviceLocked()
+ * @see #addDeviceLockedStateListener(Executor, DeviceLockedStateListener)
+ */
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER)
+ public void removeDeviceLockedStateListener(@NonNull DeviceLockedStateListener listener) {
+ if (!Flags.deviceUnlockListener()) {
+ return;
+ }
+
+ synchronized (mDeviceLockedStateListeners) {
+ mDeviceLockedStateListeners.remove(listener);
+ if (!mDeviceLockedStateListeners.isEmpty()) {
+ return;
+ }
+ try {
+ mTrustManager.unregisterDeviceLockedStateListener(mIDeviceLockedStateListener);
+ } catch (RemoteException re) {
+ Log.d(TAG, "TrustManager service died", re);
+ }
+ }
+ }
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b8233bc498b8..3d85ea6a1fca 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1660,7 +1660,6 @@ public final class LoadedApk {
}
RuntimeException ex = new IllegalArgumentException(
"Originally unregistered here:");
- ex.fillInStackTrace();
rd.setUnregisterLocation(ex);
holder.put(r, rd);
}
@@ -1860,7 +1859,6 @@ public final class LoadedApk {
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
- mLocation.fillInStackTrace();
}
void validate(Context context, Handler activityThread) {
@@ -2000,7 +1998,6 @@ public final class LoadedApk {
}
RuntimeException ex = new IllegalArgumentException(
"Originally unbound here:");
- ex.fillInStackTrace();
sd.setUnbindLocation(ex);
holder.put(c, sd);
}
@@ -2076,7 +2073,6 @@ public final class LoadedApk {
mActivityThread = activityThread;
mActivityExecutor = null;
mLocation = new ServiceConnectionLeaked(null);
- mLocation.fillInStackTrace();
mFlags = flags;
}
@@ -2088,7 +2084,6 @@ public final class LoadedApk {
mActivityThread = null;
mActivityExecutor = activityExecutor;
mLocation = new ServiceConnectionLeaked(null);
- mLocation.fillInStackTrace();
mFlags = flags;
}
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index e2de716d7e74..a70d4937b46c 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -83,7 +83,7 @@ public abstract class LoaderManager {
* transactions while in this call, since it can happen after an
* activity's state is saved. See {@link FragmentManager#beginTransaction()
* FragmentManager.openTransaction()} for further discussion on this.
- *
+ *
* <p>This function is guaranteed to be called prior to the release of
* the last data that was supplied for this Loader. At this point
* you should remove all use of the old data (since it will be released
@@ -127,7 +127,7 @@ public abstract class LoaderManager {
*/
public void onLoaderReset(Loader<D> loader);
}
-
+
/**
* Ensures a loader is initialized and active. If the loader doesn't
* already exist, one is created and (if the activity/fragment is currently
@@ -228,7 +228,7 @@ class LoaderManagerImpl extends LoaderManager {
boolean mStarted;
boolean mRetaining;
boolean mRetainingStarted;
-
+
boolean mCreatingLoader;
private FragmentHostCallback mHost;
@@ -249,13 +249,13 @@ class LoaderManagerImpl extends LoaderManager {
boolean mListenerRegistered;
LoaderInfo mPendingLoader;
-
+
public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
mId = id;
mArgs = args;
mCallbacks = callbacks;
}
-
+
void start() {
if (mRetaining && mRetainingStarted) {
// Our owner is started, but we were being retained from a
@@ -271,7 +271,7 @@ class LoaderManagerImpl extends LoaderManager {
}
mStarted = true;
-
+
if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
@@ -291,7 +291,7 @@ class LoaderManagerImpl extends LoaderManager {
mLoader.startLoading();
}
}
-
+
void retain() {
if (DEBUG) Log.v(TAG, " Retaining: " + this);
mRetaining = true;
@@ -299,7 +299,7 @@ class LoaderManagerImpl extends LoaderManager {
mStarted = false;
mCallbacks = null;
}
-
+
void finishRetain() {
if (mRetaining) {
if (DEBUG) Log.v(TAG, " Finished Retaining: " + this);
@@ -324,7 +324,7 @@ class LoaderManagerImpl extends LoaderManager {
callOnLoadFinished(mLoader, mData);
}
}
-
+
void reportStart() {
if (mStarted) {
if (mReportNextStart) {
@@ -430,7 +430,7 @@ class LoaderManagerImpl extends LoaderManager {
@Override
public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
-
+
if (mDestroyed) {
if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed");
return;
@@ -442,7 +442,7 @@ class LoaderManagerImpl extends LoaderManager {
if (DEBUG) Log.v(TAG, " Ignoring load complete -- not active");
return;
}
-
+
LoaderInfo pending = mPendingLoader;
if (pending != null) {
// There is a new request pending and we were just
@@ -455,7 +455,7 @@ class LoaderManagerImpl extends LoaderManager {
installLoader(pending);
return;
}
-
+
// Notify of the new data so the app can switch out the old data before
// we try to destroy it.
if (mData != data || !mHaveData) {
@@ -503,7 +503,7 @@ class LoaderManagerImpl extends LoaderManager {
mDeliveredData = true;
}
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(64);
@@ -543,13 +543,13 @@ class LoaderManagerImpl extends LoaderManager {
}
}
}
-
+
LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
mWho = who;
mHost = host;
mStarted = started;
}
-
+
void updateHostController(FragmentHostCallback host) {
mHost = host;
}
@@ -557,7 +557,7 @@ class LoaderManagerImpl extends LoaderManager {
public FragmentHostCallback getFragmentHostCallback() {
return mHost;
}
-
+
private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
@@ -565,7 +565,7 @@ class LoaderManagerImpl extends LoaderManager {
info.mLoader = (Loader<Object>)loader;
return info;
}
-
+
private LoaderInfo createAndInstallLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
try {
@@ -577,7 +577,7 @@ class LoaderManagerImpl extends LoaderManager {
mCreatingLoader = false;
}
}
-
+
void installLoader(LoaderInfo info) {
mLoaders.put(info.mId, info);
if (mStarted) {
@@ -587,23 +587,23 @@ class LoaderManagerImpl extends LoaderManager {
info.start();
}
}
-
+
/**
* Call to initialize a particular ID with a Loader. If this ID already
* has a Loader associated with it, it is left unchanged and any previous
* callbacks replaced with the newly provided ones. If there is not currently
* a Loader for the ID, a new one is created and started.
- *
+ *
* <p>This function should generally be used when a component is initializing,
* to ensure that a Loader it relies on is created. This allows it to re-use
* an existing Loader's data if there already is one, so that for example
* when an {@link Activity} is re-created after a configuration change it
* does not need to re-create its loaders.
- *
+ *
* <p>Note that in the case where an existing Loader is re-used, the
* <var>args</var> given here <em>will be ignored</em> because you will
* continue using the previous Loader.
- *
+ *
* @param id A unique (to this LoaderManager instance) identifier under
* which to manage the new Loader.
* @param args Optional arguments that will be propagated to
@@ -617,9 +617,9 @@ class LoaderManagerImpl extends LoaderManager {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
LoaderInfo info = mLoaders.get(id);
-
+
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
if (info == null) {
@@ -630,30 +630,30 @@ class LoaderManagerImpl extends LoaderManager {
if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
-
+
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
-
+
return (Loader<D>)info.mLoader;
}
-
+
/**
* Call to re-create the Loader associated with a particular ID. If there
* is currently a Loader associated with this ID, it will be
* canceled/stopped/destroyed as appropriate. A new Loader with the given
* arguments will be created and its data delivered to you once available.
- *
+ *
* <p>This function does some throttling of Loaders. If too many Loaders
* have been created for the given ID but not yet generated their data,
* new calls to this function will create and return a new Loader but not
* actually start it until some previous loaders have completed.
- *
+ *
* <p>After calling this function, any previous Loaders associated with
* this ID will be considered invalid, and you will receive no further
* data updates from them.
- *
+ *
* @param id A unique (to this LoaderManager instance) identifier under
* which to manage the new Loader.
* @param args Optional arguments that will be propagated to
@@ -667,7 +667,7 @@ class LoaderManagerImpl extends LoaderManager {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
if (info != null) {
@@ -706,7 +706,7 @@ class LoaderManagerImpl extends LoaderManager {
info.mPendingLoader = null;
}
if (DEBUG) Log.v(TAG, " Enqueuing as new pending loader");
- info.mPendingLoader = createLoader(id, args,
+ info.mPendingLoader = createLoader(id, args,
(LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mPendingLoader.mLoader;
}
@@ -719,11 +719,11 @@ class LoaderManagerImpl extends LoaderManager {
mInactiveLoaders.put(id, info);
}
}
-
+
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mLoader;
}
-
+
/**
* Rip down, tear apart, shred to pieces a current Loader ID. After returning
* from this function, any Loader objects associated with this ID are
@@ -735,7 +735,7 @@ class LoaderManagerImpl extends LoaderManager {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
int idx = mLoaders.indexOfKey(id);
if (idx >= 0) {
@@ -763,7 +763,7 @@ class LoaderManagerImpl extends LoaderManager {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
LoaderInfo loaderInfo = mLoaders.get(id);
if (loaderInfo != null) {
if (loaderInfo.mPendingLoader != null) {
@@ -773,16 +773,15 @@ class LoaderManagerImpl extends LoaderManager {
}
return null;
}
-
+
void doStart() {
if (DEBUG) Log.v(TAG, "Starting in " + this);
if (mStarted) {
RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
Log.w(TAG, "Called doStart when already started: " + this, e);
return;
}
-
+
mStarted = true;
// Call out to sub classes so they can start their loaders
@@ -791,12 +790,11 @@ class LoaderManagerImpl extends LoaderManager {
mLoaders.valueAt(i).start();
}
}
-
+
void doStop() {
if (DEBUG) Log.v(TAG, "Stopping in " + this);
if (!mStarted) {
RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
Log.w(TAG, "Called doStop when not started: " + this, e);
return;
}
@@ -806,12 +804,11 @@ class LoaderManagerImpl extends LoaderManager {
}
mStarted = false;
}
-
+
void doRetain() {
if (DEBUG) Log.v(TAG, "Retaining in " + this);
if (!mStarted) {
RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
Log.w(TAG, "Called doRetain when not started: " + this, e);
return;
}
@@ -822,7 +819,7 @@ class LoaderManagerImpl extends LoaderManager {
mLoaders.valueAt(i).retain();
}
}
-
+
void finishRetain() {
if (mRetaining) {
if (DEBUG) Log.v(TAG, "Finished Retaining in " + this);
@@ -833,7 +830,7 @@ class LoaderManagerImpl extends LoaderManager {
}
}
}
-
+
void doReportNextStart() {
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).mReportNextStart = true;
@@ -854,7 +851,7 @@ class LoaderManagerImpl extends LoaderManager {
}
mLoaders.clear();
}
-
+
if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
mInactiveLoaders.valueAt(i).destroy();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0381ee0e25ac..0e68cce7a8f5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -811,6 +811,27 @@ public class Notification implements Parcelable
}
private static boolean isStandardLayout(int layoutId) {
+ if (Flags.notificationsRedesignTemplates()) {
+ return switch (layoutId) {
+ case R.layout.notification_2025_template_collapsed_base,
+ R.layout.notification_2025_template_expanded_base,
+ R.layout.notification_2025_template_heads_up_base,
+ R.layout.notification_2025_template_header,
+ R.layout.notification_template_material_big_picture,
+ R.layout.notification_template_material_big_text,
+ R.layout.notification_template_material_inbox,
+ R.layout.notification_template_material_messaging,
+ R.layout.notification_template_material_big_messaging,
+ R.layout.notification_template_material_conversation,
+ R.layout.notification_template_material_media,
+ R.layout.notification_template_material_big_media,
+ R.layout.notification_template_material_call,
+ R.layout.notification_template_material_big_call,
+ R.layout.notification_template_header -> true;
+ case R.layout.notification_template_material_progress -> Flags.apiRichOngoing();
+ default -> false;
+ };
+ }
if (Flags.apiRichOngoing()) {
if (layoutId == R.layout.notification_template_material_progress) {
return true;
@@ -3139,12 +3160,16 @@ public class Notification implements Parcelable
callPerson.visitUris(visitor);
}
visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class));
- }
- if (Flags.apiRichOngoing()) {
- visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_TRACKER_ICON, Icon.class));
- visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_START_ICON, Icon.class));
- visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_END_ICON, Icon.class));
+
+ if (Flags.apiRichOngoing()) {
+ visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_TRACKER_ICON,
+ Icon.class));
+ visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_START_ICON,
+ Icon.class));
+ visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_END_ICON,
+ Icon.class));
+ }
}
if (mBubbleMetadata != null) {
@@ -3236,8 +3261,9 @@ public class Notification implements Parcelable
*/
@FlaggedApi(Flags.FLAG_UI_RICH_ONGOING)
public boolean hasPromotableCharacteristics() {
- return isColorized()
+ return isColorizedRequested()
&& hasTitle()
+ && !isGroupSummary()
&& !containsCustomViews()
&& hasPromotableStyle();
}
@@ -4062,6 +4088,12 @@ public class Notification implements Parcelable
flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
}
}
+ if (Flags.apiRichOngoing()) {
+ if ((flags & FLAG_PROMOTED_ONGOING) != 0) {
+ flagStrings.add("PROMOTED_ONGOING");
+ flags &= ~FLAG_PROMOTED_ONGOING;
+ }
+ }
if (android.service.notification.Flags.notificationSilentFlag()) {
if ((flags & FLAG_SILENT) != 0) {
@@ -5003,7 +5035,7 @@ public class Notification implements Parcelable
/**
* Sets a very short string summarizing the most critical information contained in the
- * notification. Suggested max length is 5 characters, and there is no guarantee how much or
+ * notification. Suggested max length is 7 characters, and there is no guarantee how much or
* how little of this text will be shown.
*/
@FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
@@ -6718,7 +6750,7 @@ public class Notification implements Parcelable
// Headers on their own are never colorized
p.disallowColorization();
RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
- R.layout.notification_template_header);
+ getHeaderLayoutResource());
resetNotificationHeader(header);
bindNotificationHeader(header, p);
return header;
@@ -7107,7 +7139,9 @@ public class Notification implements Parcelable
*/
public CharSequence ensureColorSpanContrastOrStripStyling(CharSequence cs,
int buttonFillColor) {
- if (Flags.cleanUpSpansAndNewLines()) {
+ // Ongoing promoted notifications are allowed to have styling.
+ final boolean isPromotedOngoing = mN.isPromotedOngoing();
+ if (!isPromotedOngoing && Flags.cleanUpSpansAndNewLines()) {
return stripStyling(cs);
}
@@ -7478,13 +7512,29 @@ public class Notification implements Parcelable
return clone;
}
+ private int getHeaderLayoutResource() {
+ if (Flags.notificationsRedesignTemplates()) {
+ return R.layout.notification_2025_template_header;
+ } else {
+ return R.layout.notification_template_header;
+ }
+ }
+
@UnsupportedAppUsage
private int getBaseLayoutResource() {
- return R.layout.notification_template_material_base;
+ if (Flags.notificationsRedesignTemplates()) {
+ return R.layout.notification_2025_template_collapsed_base;
+ } else {
+ return R.layout.notification_template_material_base;
+ }
}
private int getHeadsUpBaseLayoutResource() {
- return R.layout.notification_template_material_heads_up_base;
+ if (Flags.notificationsRedesignTemplates()) {
+ return R.layout.notification_2025_template_heads_up_base;
+ } else {
+ return R.layout.notification_template_material_heads_up_base;
+ }
}
private int getCompactHeadsUpBaseLayoutResource() {
@@ -7496,7 +7546,11 @@ public class Notification implements Parcelable
}
private int getBigBaseLayoutResource() {
- return R.layout.notification_template_material_big_base;
+ if (Flags.notificationsRedesignTemplates()) {
+ return R.layout.notification_2025_template_expanded_base;
+ } else {
+ return R.layout.notification_template_material_big_base;
+ }
}
private int getBigPictureLayoutResource() {
@@ -7755,8 +7809,16 @@ public class Notification implements Parcelable
* @hide
*/
public boolean isColorized() {
- return extras.getBoolean(EXTRA_COLORIZED)
- && (hasColorizedPermission() || isFgsOrUij());
+ return isColorizedRequested()
+ && (hasColorizedPermission() || isFgsOrUij() || isPromotedOngoing());
+ }
+
+ /**
+ * @return true if this notification has requested to be colorized, regardless of whether it
+ * meets the requirements to be displayed that way.
+ */
+ private boolean isColorizedRequested() {
+ return extras.getBoolean(EXTRA_COLORIZED);
}
/**
@@ -7770,6 +7832,19 @@ public class Notification implements Parcelable
}
/**
+ * Returns whether this notification is a promoted ongoing notification.
+ *
+ * This requires the Notification.FLAG_PROMOTED_ONGOING flag to be set
+ * (which may be true once the api_rich_ongoing feature flag is enabled),
+ * and requires that the ui_rich_ongoing feature flag is enabled.
+ *
+ * @hide
+ */
+ public boolean isPromotedOngoing() {
+ return Flags.uiRichOngoing() && (flags & Notification.FLAG_PROMOTED_ONGOING) != 0;
+ }
+
+ /**
* @return true if this is a media style notification with a media session
*
* @hide
@@ -8622,7 +8697,9 @@ public class Notification implements Parcelable
// Replace the text with the big text, but only if the big text is not empty.
CharSequence bigTextText = mBuilder.processLegacyText(mBigText);
- if (Flags.cleanUpSpansAndNewLines()) {
+ // Ongoing promoted notifications are allowed to have styling.
+ final boolean isPromotedOngoing = mBuilder.mN.isPromotedOngoing();
+ if (!isPromotedOngoing && Flags.cleanUpSpansAndNewLines()) {
bigTextText = normalizeBigText(stripStyling(bigTextText));
}
if (!TextUtils.isEmpty(bigTextText)) {
@@ -9499,7 +9576,6 @@ public class Notification implements Parcelable
contentView.setViewVisibility(R.id.icon, View.GONE);
contentView.setViewVisibility(R.id.conversation_face_pile, View.GONE);
contentView.setViewVisibility(R.id.conversation_icon, View.VISIBLE);
- contentView.setBoolean(R.id.conversation_icon, "setApplyCircularCrop", true);
contentView.setImageViewIcon(R.id.conversation_icon, conversationIcon);
} else if (mIsGroupConversation) {
contentView.setViewVisibility(R.id.icon, View.GONE);
@@ -11527,11 +11603,9 @@ public class Notification implements Parcelable
contentView.setBundle(R.id.progress,
"setProgressModel", model.toBundle());
- if (mTrackerIcon != null) {
- contentView.setIcon(R.id.progress,
- "setProgressTrackerIcon",
- mTrackerIcon);
- }
+ contentView.setIcon(R.id.progress,
+ "setProgressTrackerIcon",
+ mTrackerIcon);
return contentView;
}
@@ -11637,8 +11711,10 @@ public class Notification implements Parcelable
return points;
}
- @NonNull
- private NotificationProgressModel createProgressModel(int defaultProgressColor,
+ /**
+ * @hide
+ */
+ public @NonNull NotificationProgressModel createProgressModel(int defaultProgressColor,
int backgroundColor) {
final NotificationProgressModel model;
if (mIndeterminate) {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c49b02210dd4..87c861912036 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.service.notification.Flags.notificationClassification;
import android.annotation.CallbackExecutor;
@@ -1597,11 +1599,15 @@ public class NotificationManager {
* Returns whether notifications from the calling package are enabled.
*/
public boolean areNotificationsEnabled() {
- INotificationManager service = getService();
- try {
- return service.areNotificationsEnabled(mContext.getPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ if (Flags.nmBinderPerfPermissionCheck()) {
+ return mContext.checkSelfPermission(POST_NOTIFICATIONS) == PERMISSION_GRANTED;
+ } else {
+ INotificationManager service = getService();
+ try {
+ return service.areNotificationsEnabled(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
@@ -1862,6 +1868,19 @@ public class NotificationManager {
/**
* @hide
*/
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) {
+ INotificationManager service = getService();
+ try {
+ service.setTypeAdjustmentForPackageState(pkg, enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
public List<String> getEnabledNotificationListenerPackages() {
INotificationManager service = getService();
try {
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 1dc774285a32..e218418336c5 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -314,6 +314,14 @@ public class PropertyInvalidatedCache<Query, Result> {
@GuardedBy("mLock")
private long mMisses = 0;
+ // This counter tracks the number of times {@link #recompute} returned a null value. Null
+ // results are cached, or not, depending on instantiation arguments. Caching nulls when they
+ // should not be cached is a functional error. Failing to cache nulls that can be cached is a
+ // performance error. A non-zero value here means the cache should be examined to be sure
+ // that nulls are correctly cached, or not.
+ @GuardedBy("mLock")
+ private long mNulls = 0;
+
@GuardedBy("mLock")
private long[] mSkips = new long[MAX_RESERVED_NONCE + 1];
@@ -374,6 +382,11 @@ public class PropertyInvalidatedCache<Query, Result> {
private final String mCacheName;
/**
+ * True if nulls are valid returns from recompute().
+ */
+ private final boolean mCacheNullResults;
+
+ /**
* The function that computes a Result, given a Query. This function is called on a
* cache miss.
*/
@@ -509,6 +522,19 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
+ * Return true if the entry is in the cache.
+ */
+ boolean containsKey(Query query) {
+ final int uid = callerUid();
+ var map = mCache.get(uid);
+ if (map != null) {
+ return map.containsKey(query);
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Remove an entry from the cache.
*/
void remove(Query query) {
@@ -1101,7 +1127,7 @@ public class PropertyInvalidatedCache<Query, Result> {
* @hide
*/
public static record Args(@NonNull String mModule, @Nullable String mApi,
- int mMaxEntries, boolean mIsolateUids, boolean mTestMode) {
+ int mMaxEntries, boolean mIsolateUids, boolean mTestMode, boolean mCacheNulls) {
// Validation: the module must be one of the known module strings and the maxEntries must
// be positive.
@@ -1119,24 +1145,29 @@ public class PropertyInvalidatedCache<Query, Result> {
null, // api
32, // maxEntries
true, // isolateUids
- false // testMode
+ false, // testMode
+ true // allowNulls
);
}
public Args api(@NonNull String api) {
- return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode);
+ return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode, mCacheNulls);
}
public Args maxEntries(int val) {
- return new Args(mModule, mApi, val, mIsolateUids, mTestMode);
+ return new Args(mModule, mApi, val, mIsolateUids, mTestMode, mCacheNulls);
}
public Args isolateUids(boolean val) {
- return new Args(mModule, mApi, mMaxEntries, val, mTestMode);
+ return new Args(mModule, mApi, mMaxEntries, val, mTestMode, mCacheNulls);
}
public Args testMode(boolean val) {
- return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val);
+ return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val, mCacheNulls);
+ }
+
+ public Args cacheNulls(boolean val) {
+ return new Args(mModule, mApi, mMaxEntries, mIsolateUids, mTestMode, val);
}
}
@@ -1153,6 +1184,7 @@ public class PropertyInvalidatedCache<Query, Result> {
@Nullable QueryHandler<Query, Result> computer) {
mPropertyName = createPropertyName(args.mModule, args.mApi);
mCacheName = cacheName;
+ mCacheNullResults = args.mCacheNulls && Flags.picCacheNulls();
mNonce = getNonceHandler(mPropertyName);
mMaxEntries = args.mMaxEntries;
mCache = new CacheMap<>(args.mIsolateUids, args.mTestMode);
@@ -1491,12 +1523,24 @@ public class PropertyInvalidatedCache<Query, Result> {
}
return recompute(query);
}
+
+ final boolean cacheHit;
final Result cachedResult;
synchronized (mLock) {
if (currentNonce == mLastSeenNonce) {
cachedResult = mCache.get(query);
-
- if (cachedResult != null) mHits++;
+ if (cachedResult == null) {
+ if (mCacheNullResults) {
+ cacheHit = mCache.containsKey(query);
+ } else {
+ cacheHit = false;
+ }
+ } else {
+ cacheHit = true;
+ }
+ if (cacheHit) {
+ mHits++;
+ }
} else {
if (DEBUG) {
Log.d(TAG, formatSimple(
@@ -1506,16 +1550,18 @@ public class PropertyInvalidatedCache<Query, Result> {
}
clear();
mLastSeenNonce = currentNonce;
+ cacheHit = false;
cachedResult = null;
}
}
+
// Cache hit --- but we're not quite done yet. A value in the cache might need to
// be augmented in a "refresh" operation. The refresh operation can combine the
// old and the new nonce values. In order to make sure the new parts of the value
// are consistent with the old, possibly-reused parts, we check the property value
// again after the refresh and do the whole fetch again if the property invalidated
// us while we were refreshing.
- if (cachedResult != null) {
+ if (cacheHit) {
final Result refreshedResult = refresh(cachedResult, query);
if (refreshedResult != cachedResult) {
if (DEBUG) {
@@ -1550,6 +1596,7 @@ public class PropertyInvalidatedCache<Query, Result> {
}
return maybeCheckConsistency(query, cachedResult);
}
+
// Cache miss: make the value from scratch.
if (DEBUG) {
Log.d(TAG, "cache miss for " + cacheName() + " " + queryToString(query));
@@ -1558,8 +1605,13 @@ public class PropertyInvalidatedCache<Query, Result> {
synchronized (mLock) {
// If someone else invalidated the cache while we did the recomputation, don't
// update the cache with a potentially stale result.
- if (mLastSeenNonce == currentNonce && result != null) {
- mCache.put(query, result);
+ if (mLastSeenNonce == currentNonce) {
+ if (result != null || mCacheNullResults) {
+ mCache.put(query, result);
+ }
+ if (result == null) {
+ mNulls++;
+ }
}
mMisses++;
}
@@ -1947,10 +1999,12 @@ public class PropertyInvalidatedCache<Query, Result> {
}
// Return true if this cache has had any activity. If the hits, misses, and skips are all
- // zero then the client never tried to use the cache.
- private boolean isActive() {
+ // zero then the client never tried to use the cache. If invalidations and corks are also
+ // zero then the server never tried to use the cache.
+ private boolean isActive(NonceHandler.Stats stats) {
synchronized (mLock) {
- return mHits + mMisses + getSkipsLocked() > 0;
+ return mHits + mMisses + getSkipsLocked()
+ + stats.invalidated + stats.corkedInvalidates > 0;
}
}
@@ -1968,15 +2022,15 @@ public class PropertyInvalidatedCache<Query, Result> {
NonceHandler.Stats stats = mNonce.getStats();
synchronized (mLock) {
- if (brief && !isActive()) {
+ if (brief && !isActive(stats)) {
return;
}
pw.println(formatSimple(" Cache Name: %s", cacheName()));
pw.println(formatSimple(" Property: %s", mPropertyName));
pw.println(formatSimple(
- " Hits: %d, Misses: %d, Skips: %d, Clears: %d, Uids: %d",
- mHits, mMisses, getSkipsLocked(), mClears, mCache.size()));
+ " Hits: %d, Misses: %d, Skips: %d, Clears: %d, Nulls: %d",
+ mHits, mMisses, getSkipsLocked(), mClears, mNulls));
// Print all the skip reasons.
pw.format(" Skip-%s: %d", sNonceName[0], mSkips[0]);
@@ -1986,7 +2040,7 @@ public class PropertyInvalidatedCache<Query, Result> {
pw.println();
pw.println(formatSimple(
- " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d",
+ " Nonce: 0x%016x, Invalidates: %d, Corked: %d",
mLastSeenNonce, stats.invalidated, stats.corkedInvalidates));
pw.println(formatSimple(
" Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index a458b4e45796..3cffca796680 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -174,22 +174,58 @@ public class ResourcesManager {
}
/**
- * Apply the registered library paths to the passed impl object
- * @return the hash code for the current version of the registered paths
+ * Apply the registered library paths to the passed AssetManager. If may create a new
+ * AssetManager if any changes are needed and it isn't allowed to reuse the old one.
+ *
+ * @return new AssetManager and the hash code for the current version of the registered paths
*/
- public int updateResourceImplWithRegisteredLibs(@NonNull ResourcesImpl impl) {
+ public @NonNull Pair<AssetManager, Integer> updateResourceImplAssetsWithRegisteredLibs(
+ @NonNull AssetManager assets, boolean reuseAssets) {
if (!Flags.registerResourcePaths()) {
- return 0;
+ return new Pair<>(assets, 0);
}
- final var collector = new PathCollector(null);
- final int size = mSharedLibAssetsMap.size();
- for (int i = 0; i < size; i++) {
- final var libraryKey = mSharedLibAssetsMap.valueAt(i).getResourcesKey();
- collector.appendKey(libraryKey);
+ final int size;
+ final PathCollector collector;
+
+ synchronized (mLock) {
+ size = mSharedLibAssetsMap.size();
+ if (assets == AssetManager.getSystem()) {
+ return new Pair<>(assets, size);
+ }
+ collector = new PathCollector(resourcesKeyFromAssets(assets));
+ for (int i = 0; i < size; i++) {
+ final var libraryKey = mSharedLibAssetsMap.valueAt(i).getResourcesKey();
+ collector.appendKey(libraryKey);
+ }
}
- impl.getAssets().addPresetApkKeys(extractApkKeys(collector.collectedKey()));
- return size;
+ if (collector.isSameAsOriginal()) {
+ return new Pair<>(assets, size);
+ }
+ if (reuseAssets) {
+ assets.addPresetApkKeys(extractApkKeys(collector.collectedKey()));
+ return new Pair<>(assets, size);
+ }
+ final var newAssetsBuilder = new AssetManager.Builder().setNoInit();
+ for (final var asset : assets.getApkAssets()) {
+ // Skip everything that's either default, or will get added by the collector (builder
+ // doesn't check for duplicates at all).
+ if (asset.isSystem() || asset.isForLoader() || asset.isOverlay()
+ || asset.isSharedLib()) {
+ continue;
+ }
+ newAssetsBuilder.addApkAssets(asset);
+ }
+ for (final var key : extractApkKeys(collector.collectedKey())) {
+ try {
+ final var asset = loadApkAssets(key);
+ newAssetsBuilder.addApkAssets(asset);
+ } catch (IOException e) {
+ Log.e(TAG, "Couldn't load assets for key " + key, e);
+ }
+ }
+ assets.getLoaders().forEach(newAssetsBuilder::addLoader);
+ return new Pair<>(newAssetsBuilder.build(), size);
}
public static class ApkKey {
@@ -624,6 +660,23 @@ public class ResourcesManager {
return apkKeys;
}
+ private ResourcesKey resourcesKeyFromAssets(@NonNull AssetManager assets) {
+ final var libs = new ArrayList<String>();
+ final var overlays = new ArrayList<String>();
+ for (final ApkAssets asset : assets.getApkAssets()) {
+ if (asset.isSystem() || asset.isForLoader()) {
+ continue;
+ }
+ if (asset.isOverlay()) {
+ overlays.add(asset.getAssetPath());
+ } else if (asset.isSharedLib()) {
+ libs.add(asset.getAssetPath());
+ }
+ }
+ return new ResourcesKey(null, null, overlays.toArray(new String[0]),
+ libs.toArray(new String[0]), 0, null, null);
+ }
+
/**
* Creates an AssetManager from the paths within the ResourcesKey.
*
@@ -752,7 +805,7 @@ public class ResourcesManager {
final Configuration config = generateConfig(key);
final DisplayMetrics displayMetrics = getDisplayMetrics(generateDisplayId(key), daj);
- final ResourcesImpl impl = new ResourcesImpl(assets, displayMetrics, config, daj);
+ final ResourcesImpl impl = new ResourcesImpl(assets, displayMetrics, config, daj, true);
if (DEBUG) {
Slog.d(TAG, "- creating impl=" + impl + " with key: " + key);
@@ -1137,7 +1190,6 @@ public class ResourcesManager {
synchronized (mLock) {
if (DEBUG) {
Throwable here = new Throwable();
- here.fillInStackTrace();
Slog.w(TAG, "!! Create resources for key=" + key, here);
}
@@ -1158,7 +1210,6 @@ public class ResourcesManager {
synchronized (mLock) {
if (DEBUG) {
Throwable here = new Throwable();
- here.fillInStackTrace();
Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
}
@@ -1302,7 +1353,6 @@ public class ResourcesManager {
if (DEBUG) {
Throwable here = new Throwable();
- here.fillInStackTrace();
Slog.d(TAG, "updating resources override for activity=" + activityToken
+ " from oldConfig="
+ Configuration.resourceQualifierString(oldConfig)
@@ -1835,31 +1885,32 @@ public class ResourcesManager {
for (int i = 0; i < resourcesCount; i++) {
final WeakReference<Resources> ref = mAllResourceReferences.get(i);
final Resources r = ref != null ? ref.get() : null;
- if (r != null) {
- final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
- if (key != null) {
- final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key);
- if (impl == null) {
- throw new Resources.NotFoundException("failed to redirect ResourcesImpl");
- }
- r.setImpl(impl);
- } else {
- // ResourcesKey is null which means the ResourcesImpl could belong to a
- // Resources created by application through Resources constructor and was not
- // managed by ResourcesManager, so the ResourcesImpl needs to be recreated to
- // have shared library asset paths appended if there are any.
- if (r.getImpl() != null) {
- final ResourcesImpl oldImpl = r.getImpl();
- final AssetManager oldAssets = oldImpl.getAssets();
- // ResourcesImpl constructor will help to append shared library asset paths.
- if (oldAssets != AssetManager.getSystem() && oldAssets.isUpToDate()) {
- final ResourcesImpl newImpl = new ResourcesImpl(oldAssets,
- oldImpl.getMetrics(), oldImpl.getConfiguration(),
- oldImpl.getDisplayAdjustments());
+ if (r == null) {
+ continue;
+ }
+ final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
+ if (key != null) {
+ final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key);
+ if (impl == null) {
+ throw new Resources.NotFoundException("failed to redirect ResourcesImpl");
+ }
+ r.setImpl(impl);
+ } else {
+ // ResourcesKey is null which means the ResourcesImpl could belong to a
+ // Resources created by application through Resources constructor and was not
+ // managed by ResourcesManager, so the ResourcesImpl needs to be recreated to
+ // have shared library asset paths appended if there are any.
+ final ResourcesImpl oldImpl = r.getImpl();
+ if (oldImpl != null) {
+ final AssetManager oldAssets = oldImpl.getAssets();
+ // ResourcesImpl constructor will help to append shared library asset paths.
+ if (oldAssets != AssetManager.getSystem()) {
+ if (oldAssets.isUpToDate()) {
+ final ResourcesImpl newImpl = new ResourcesImpl(oldImpl);
r.setImpl(newImpl);
} else {
- Slog.w(TAG, "Skip appending shared library asset paths for the "
- + "Resource as its assets are not up to date.");
+ Slog.w(TAG, "Skip appending shared library asset paths for "
+ + "the Resources as its assets are not up to date.");
}
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e451116081fa..2bd2d34d54a2 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -17,6 +17,7 @@
package android.app;
import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
+import static android.provider.flags.Flags.stageFlagsForBuild;
import static android.server.Flags.removeGameManagerServiceFromWear;
import android.accounts.AccountManager;
@@ -163,6 +164,7 @@ import android.media.tv.tunerresourcemanager.ITunerResourceManager;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.nearby.NearbyFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializer;
+import android.net.ConnectivityFrameworkInitializerBaklava;
import android.net.ConnectivityFrameworkInitializerTiramisu;
import android.net.INetworkPolicyManager;
import android.net.IPacProxyManager;
@@ -173,7 +175,6 @@ import android.net.NetworkWatchlistManager;
import android.net.PacProxyManager;
import android.net.TetheringManager;
import android.net.VpnManager;
-import android.net.vcn.VcnFrameworkInitializer;
import android.net.wifi.WifiFrameworkInitializer;
import android.net.wifi.nl80211.WifiNl80211Manager;
import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
@@ -190,6 +191,7 @@ import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.IDumpstate;
import android.os.IHardwarePropertiesManager;
+import android.os.IHintManager;
import android.os.IPowerManager;
import android.os.IPowerStatsService;
import android.os.IRecoverySystem;
@@ -215,6 +217,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.os.VibratorManager;
+import android.os.flagging.ConfigInfrastructureFrameworkInitializer;
import android.os.health.SystemHealthManager;
import android.os.image.DynamicSystemManager;
import android.os.image.IDynamicSystemService;
@@ -238,6 +241,10 @@ import android.security.advancedprotection.AdvancedProtectionManager;
import android.security.advancedprotection.IAdvancedProtectionService;
import android.security.attestationverification.AttestationVerificationManager;
import android.security.attestationverification.IAttestationVerificationManagerService;
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.IAuthenticationPolicyService;
+import android.security.intrusiondetection.IIntrusionDetectionService;
+import android.security.intrusiondetection.IntrusionDetectionManager;
import android.security.keystore.KeyStoreManager;
import android.service.oemlock.IOemLockService;
import android.service.oemlock.OemLockManager;
@@ -1020,6 +1027,25 @@ public final class SystemServiceRegistry {
}
});
+ registerService(Context.AUTHENTICATION_POLICY_SERVICE,
+ AuthenticationPolicyManager.class,
+ new CachedServiceFetcher<AuthenticationPolicyManager>() {
+ @Override
+ public AuthenticationPolicyManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ if (!android.security.Flags.secureLockdown()) {
+ throw new ServiceNotFoundException(
+ Context.AUTHENTICATION_POLICY_SERVICE);
+ }
+
+ final IBinder binder = ServiceManager.getServiceOrThrow(
+ Context.AUTHENTICATION_POLICY_SERVICE);
+ final IAuthenticationPolicyService service =
+ IAuthenticationPolicyService.Stub.asInterface(binder);
+ return new AuthenticationPolicyManager(ctx.getOuterContext(), service);
+ }
+ });
+
registerService(Context.TV_INTERACTIVE_APP_SERVICE, TvInteractiveAppManager.class,
new CachedServiceFetcher<TvInteractiveAppManager>() {
@Override
@@ -1195,8 +1221,10 @@ public final class SystemServiceRegistry {
public SystemHealthManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder batteryStats = ServiceManager.getServiceOrThrow(BatteryStats.SERVICE_NAME);
IBinder powerStats = ServiceManager.getService(Context.POWER_STATS_SERVICE);
+ IBinder perfHint = ServiceManager.getService(Context.PERFORMANCE_HINT_SERVICE);
return new SystemHealthManager(IBatteryStats.Stub.asInterface(batteryStats),
- IPowerStatsService.Stub.asInterface(powerStats));
+ IPowerStatsService.Stub.asInterface(powerStats),
+ IHintManager.Stub.asInterface(perfHint));
}});
registerService(Context.CONTEXTHUB_SERVICE, ContextHubManager.class,
@@ -1790,6 +1818,23 @@ public final class SystemServiceRegistry {
}
});
+ registerService(Context.INTRUSION_DETECTION_SERVICE, IntrusionDetectionManager.class,
+ new CachedServiceFetcher<IntrusionDetectionManager>() {
+ @Override
+ public IntrusionDetectionManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ if (!android.security.Flags.aflApi()) {
+ throw new ServiceNotFoundException(
+ "Intrusion Detection is not supported");
+ }
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.INTRUSION_DETECTION_SERVICE);
+ IIntrusionDetectionService service =
+ IIntrusionDetectionService.Stub.asInterface(b);
+ return new IntrusionDetectionManager(service);
+ }
+ });
+
sInitializing = true;
try {
// Note: the following functions need to be @SystemApis, once they become mainline
@@ -1818,7 +1863,11 @@ public final class SystemServiceRegistry {
OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers();
DeviceLockFrameworkInitializer.registerServiceWrappers();
VirtualizationFrameworkInitializer.registerServiceWrappers();
- VcnFrameworkInitializer.registerServiceWrappers();
+ ConnectivityFrameworkInitializerBaklava.registerServiceWrappers();
+
+ if (stageFlagsForBuild()) {
+ ConfigInfrastructureFrameworkInitializer.registerServiceWrappers();
+ }
if (com.android.server.telecom.flags.Flags.telecomMainlineBlockedNumbersManager()) {
ProviderFrameworkInitializer.registerServiceWrappers();
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 637187e01160..5ed1f4e35533 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -177,10 +177,6 @@
{
"file_patterns": ["(/|^)AppOpsManager.java"],
"name": "CtsAppOpsTestCases"
- },
- {
- "file_patterns": ["(/|^)BroadcastStickyCache.java"],
- "name": "BroadcastUnitTests"
}
]
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index aac963ade726..01cc9d82d56d 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -340,10 +340,10 @@ public class TaskInfo {
public int requestedVisibleTypes;
/**
- * Whether the top activity has requested to limit educational dialogs shown by the system.
+ * The timestamp of the top activity's last request to show the "Open in Browser" education.
* @hide
*/
- public boolean isTopActivityLimitSystemEducationDialogs;
+ public long topActivityRequestOpenInBrowserEducationTimestamp;
/**
* Encapsulate specific App Compat information.
@@ -493,8 +493,8 @@ public class TaskInfo {
&& Objects.equals(capturedLink, that.capturedLink)
&& capturedLinkTimestamp == that.capturedLinkTimestamp
&& requestedVisibleTypes == that.requestedVisibleTypes
- && isTopActivityLimitSystemEducationDialogs
- == that.isTopActivityLimitSystemEducationDialogs
+ && topActivityRequestOpenInBrowserEducationTimestamp
+ == that.topActivityRequestOpenInBrowserEducationTimestamp
&& appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo)
&& Objects.equals(topActivityMainWindowFrame, that.topActivityMainWindowFrame);
}
@@ -571,7 +571,7 @@ public class TaskInfo {
capturedLink = source.readTypedObject(Uri.CREATOR);
capturedLinkTimestamp = source.readLong();
requestedVisibleTypes = source.readInt();
- isTopActivityLimitSystemEducationDialogs = source.readBoolean();
+ topActivityRequestOpenInBrowserEducationTimestamp = source.readLong();
appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR);
topActivityMainWindowFrame = source.readTypedObject(Rect.CREATOR);
}
@@ -627,7 +627,7 @@ public class TaskInfo {
dest.writeTypedObject(capturedLink, flags);
dest.writeLong(capturedLinkTimestamp);
dest.writeInt(requestedVisibleTypes);
- dest.writeBoolean(isTopActivityLimitSystemEducationDialogs);
+ dest.writeLong(topActivityRequestOpenInBrowserEducationTimestamp);
dest.writeTypedObject(appCompatTaskInfo, flags);
dest.writeTypedObject(topActivityMainWindowFrame, flags);
}
@@ -672,8 +672,8 @@ public class TaskInfo {
+ " capturedLink=" + capturedLink
+ " capturedLinkTimestamp=" + capturedLinkTimestamp
+ " requestedVisibleTypes=" + requestedVisibleTypes
- + " isTopActivityLimitSystemEducationDialogs="
- + isTopActivityLimitSystemEducationDialogs
+ + " topActivityRequestOpenInBrowserEducationTimestamp="
+ + topActivityRequestOpenInBrowserEducationTimestamp
+ " appCompatTaskInfo=" + appCompatTaskInfo
+ " topActivityMainWindowFrame=" + topActivityMainWindowFrame
+ "}";
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 36f61fd3ef59..b9b582a7d660 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -198,6 +198,10 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
}
@Override
+ public void onRecentTaskRemovedForAddTask(int taskId) {
+ }
+
+ @Override
public void onTaskFocusChanged(int taskId, boolean focused) {
}
diff --git a/core/java/android/app/ZenBypassingApp.java b/core/java/android/app/ZenBypassingApp.java
new file mode 100644
index 000000000000..89bcfa2d2e7d
--- /dev/null
+++ b/core/java/android/app/ZenBypassingApp.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public final class ZenBypassingApp implements Parcelable {
+
+ @NonNull private String mPkg;
+ private boolean mAllChannelsBypass;
+
+
+ public ZenBypassingApp(@NonNull String pkg, boolean allChannelsBypass) {
+ mPkg = pkg;
+ mAllChannelsBypass = allChannelsBypass;
+ }
+
+ public ZenBypassingApp(Parcel source) {
+ mPkg = source.readString();
+ mAllChannelsBypass = source.readBoolean();
+ }
+
+ @NonNull
+ public String getPkg() {
+ return mPkg;
+ }
+
+ public boolean doAllChannelsBypass() {
+ return mAllChannelsBypass;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mPkg);
+ dest.writeBoolean(mAllChannelsBypass);
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<ZenBypassingApp> CREATOR
+ = new Parcelable.Creator<ZenBypassingApp>() {
+ @Override
+ public ZenBypassingApp createFromParcel(Parcel source) {
+ return new ZenBypassingApp(source);
+ }
+ @Override
+ public ZenBypassingApp[] newArray(int size) {
+ return new ZenBypassingApp[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ZenBypassingApp)) return false;
+ ZenBypassingApp that = (ZenBypassingApp) o;
+ return mAllChannelsBypass == that.mAllChannelsBypass && Objects.equals(mPkg,
+ that.mPkg);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPkg, mAllChannelsBypass);
+ }
+
+ @Override
+ public String toString() {
+ return "ZenBypassingApp{" +
+ "mPkg='" + mPkg + '\'' +
+ ", mAllChannelsBypass=" + mAllChannelsBypass +
+ '}';
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 707ba347faab..42fa9e7d7994 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,7 @@
package android.app.admin;
+import static android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.LOCK_DEVICE;
@@ -58,6 +59,7 @@ import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;
import static android.app.admin.flags.Flags.FLAG_REMOVE_MANAGED_PROFILE_ENABLED;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
import static android.app.admin.flags.Flags.onboardingConsentlessBugreports;
+import static android.app.admin.flags.Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED;
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
@@ -8919,12 +8921,9 @@ public class DevicePolicyManager {
/**
* Called by a device owner, a profile owner for the primary user or a profile
* owner of an organization-owned managed profile to turn auto time on and off.
- * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
- * to prevent the user from changing this setting.
* <p>
- * If user restriction {@link UserManager#DISALLOW_CONFIG_DATE_TIME} is used,
- * no user will be able set the date and time. Instead, the network date
- * and time will be used.
+ * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the
+ * user from changing this setting, that way no user will be able set the date and time zone.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
* caller is not a device admin.
@@ -8937,7 +8936,13 @@ public class DevicePolicyManager {
throwIfParentInstance("setAutoTimeEnabled");
if (mService != null) {
try {
- mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled);
+ if (Flags.setAutoTimeEnabledCoexistence()) {
+ mService.setAutoTimePolicy(mContext.getPackageName(),
+ enabled ? DevicePolicyManager.AUTO_TIME_ENABLED
+ : DevicePolicyManager.AUTO_TIME_DISABLED);
+ } else {
+ mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled);
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8967,14 +8972,102 @@ public class DevicePolicyManager {
}
/**
+ * Specifies that the auto time state is not controlled by device policy.
+ *
+ * @see #setAutoTimePolicy(ComponentName, int)
+ */
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+ public static final int AUTO_TIME_NOT_CONTROLLED_BY_POLICY = 0;
+
+ /**
+ * Specifies the "disabled" auto time state.
+ *
+ * @see #setAutoTimePolicy(ComponentName, int)
+ */
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+ public static final int AUTO_TIME_DISABLED = 1;
+
+ /**
+ * Specifies the "enabled" auto time state.
+ *
+ * @see #setAutoTimePolicy(ComponentName, int)
+ */
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+ public static final int AUTO_TIME_ENABLED = 2;
+
+ /**
+ * Flags supplied to {@link #setAutoTimePolicy}(ComponentName, int)}.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "AUTO_TIME_" }, value = {
+ AUTO_TIME_NOT_CONTROLLED_BY_POLICY,
+ AUTO_TIME_DISABLED,
+ AUTO_TIME_ENABLED
+ })
+ public @interface AutoTimePolicy {}
+
+ /**
+ * Called by a device owner, a profile owner for the primary user or a profile owner of an
+ * organization-owned managed profile to turn auto time on and off i.e. Whether time should be
+ * obtained automatically from the network or not.
+ * <p>
+ * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the
+ * user from changing this setting, that way no user will be able set the date and time zone.
+ *
+ * @param policy The desired state among {@link #AUTO_TIME_ENABLED} to enable,
+ * {@link #AUTO_TIME_DISABLED} to disable and
+ * {@link #AUTO_TIME_NOT_CONTROLLED_BY_POLICY} to unset the policy.
+ * @throws SecurityException if caller is not a device owner, a profile owner for the
+ * primary user, or a profile owner of an organization-owned managed profile, or if the caller
+ * does not hold the required permission.
+ */
+ @SupportsCoexistence
+ @RequiresPermission(value = SET_TIME, conditional = true)
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+ public void setAutoTimePolicy(@AutoTimePolicy int policy) {
+ throwIfParentInstance("setAutoTimePolicy");
+ if (mService != null) {
+ try {
+ mService.setAutoTimePolicy(mContext.getPackageName(), policy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns current auto time policy's state.
+ *
+ * @return One of {@link #AUTO_TIME_ENABLED} if enabled, {@link #AUTO_TIME_DISABLED} if disabled
+ * and {@link #AUTO_TIME_NOT_CONTROLLED_BY_POLICY} if it's not controlled by
+ * policy.
+ * @throws SecurityException if caller is not a device owner, a profile owner for the
+ * primary user, or a profile owner of an organization-owned managed profile, or if the caller
+ * does not hold the required permission.
+ */
+ @SupportsCoexistence
+ @RequiresPermission(anyOf = {SET_TIME, QUERY_ADMIN_POLICY}, conditional = true)
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+ public @AutoTimePolicy int getAutoTimePolicy() {
+ throwIfParentInstance("getAutoTimePolicy");
+ if (mService != null) {
+ try {
+ return mService.getAutoTimePolicy(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY;
+ }
+
+ /**
* Called by a device owner, a profile owner for the primary user or a profile
* owner of an organization-owned managed profile to turn auto time zone on and off.
- * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
- * to prevent the user from changing this setting.
* <p>
- * If user restriction {@link UserManager#DISALLOW_CONFIG_DATE_TIME} is used,
- * no user will be able set the date and time zone. Instead, the network date
- * and time zone will be used.
+ * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the
+ * user from changing this setting, that way no user will be able set the date and time zone.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with or Null if the
* caller is not a device admin.
@@ -8982,13 +9075,17 @@ public class DevicePolicyManager {
* @throws SecurityException if caller is not a device owner, a profile owner for the
* primary user, or a profile owner of an organization-owned managed profile.
*/
- @SupportsCoexistence
@RequiresPermission(value = SET_TIME_ZONE, conditional = true)
public void setAutoTimeZoneEnabled(@Nullable ComponentName admin, boolean enabled) {
throwIfParentInstance("setAutoTimeZone");
if (mService != null) {
try {
- mService.setAutoTimeZoneEnabled(admin, mContext.getPackageName(), enabled);
+ if (Flags.setAutoTimeZoneEnabledCoexistence()) {
+ mService.setAutoTimeZonePolicy(mContext.getPackageName(),
+ enabled ? AUTO_TIME_ZONE_ENABLED : AUTO_TIME_ZONE_DISABLED );
+ } else {
+ mService.setAutoTimeZoneEnabled(admin, mContext.getPackageName(), enabled);
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9018,6 +9115,96 @@ public class DevicePolicyManager {
}
/**
+ * Specifies that the auto time zone state is not controlled by device policy.
+ *
+ * @see #setAutoTimeZonePolicy(int)
+ */
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ZONE_ENABLED_COEXISTENCE)
+ public static final int AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY = 0;
+
+ /**
+ * Specifies the "disabled" auto time zone state.
+ *
+ * @see #setAutoTimeZonePolicy(int)
+ */
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ZONE_ENABLED_COEXISTENCE)
+ public static final int AUTO_TIME_ZONE_DISABLED = 1;
+
+ /**
+ * Specifies the "enabled" auto time zone state.
+ *
+ * @see #setAutoTimeZonePolicy(int)
+ */
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ZONE_ENABLED_COEXISTENCE)
+ public static final int AUTO_TIME_ZONE_ENABLED = 2;
+
+ /**
+ * Flags supplied to {@link #setAutoTimeZonePolicy}(int)}.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "AUTO_TIME_ZONE_" }, value = {
+ AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY,
+ AUTO_TIME_ZONE_DISABLED,
+ AUTO_TIME_ZONE_ENABLED
+ })
+ public @interface AutoTimeZonePolicy {}
+
+ /**
+ * Called by a device owner, a profile owner for the primary user or a profile owner of an
+ * organization-owned managed profile to turn auto time zone on and off.
+ * <p>
+ * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the
+ * user from changing this setting, that way no user will be able set the date and time zone.
+ *
+ * @param policy The desired state among {@link #AUTO_TIME_ZONE_ENABLED} to enable it,
+ * {@link #AUTO_TIME_ZONE_DISABLED} to disable it or
+ * {@link #AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY} to unset the policy.
+ * @throws SecurityException if caller is not a device owner, a profile owner for the primary
+ * user, or a profile owner of an organization-owned managed profile, or if the caller does not
+ * hold the required permission.
+ */
+ @SupportsCoexistence
+ @RequiresPermission(value = SET_TIME_ZONE, conditional = true)
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ZONE_ENABLED_COEXISTENCE)
+ public void setAutoTimeZonePolicy(@AutoTimeZonePolicy int policy) {
+ throwIfParentInstance("setAutoTimeZonePolicy");
+ if (mService != null) {
+ try {
+ mService.setAutoTimeZonePolicy(mContext.getPackageName(), policy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns auto time zone policy's current state.
+ *
+ * @return One of {@link #AUTO_TIME_ZONE_ENABLED} if enabled, {@link #AUTO_TIME_ZONE_DISABLED}
+ * if disabled and {@link #AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY} if the state is not
+ * controlled by policy.
+ * @throws SecurityException if caller is not a device owner, a profile owner for the
+ * primary user, or a profile owner of an organization-owned managed profile, or if the caller
+ * does not hold the required permission.
+ */
+ @SupportsCoexistence
+ @RequiresPermission(anyOf = {SET_TIME_ZONE, QUERY_ADMIN_POLICY}, conditional = true)
+ @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ZONE_ENABLED_COEXISTENCE)
+ public @AutoTimeZonePolicy int getAutoTimeZonePolicy() {
+ throwIfParentInstance("getAutoTimeZonePolicy");
+ if (mService != null) {
+ try {
+ return mService.getAutoTimeZonePolicy(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return DevicePolicyManager.AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY;
+ }
+
+ /**
* TODO (b/137101239): remove this method in follow-up CL
* since it's only used for split system user.
* Called by a device owner to set whether all users created on the device should be ephemeral.
@@ -12010,6 +12197,33 @@ public class DevicePolicyManager {
}
/**
+ * Adds a user restriction globally, specified by the {@code key}.
+ *
+ * <p>Called by a system service only, meaning that the caller's UID must be equal to
+ * {@link Process#SYSTEM_UID}.
+ *
+ * @param systemEntity The service entity that adds the restriction. A user restriction set by
+ * a service entity can only be cleared by the same entity. This can be
+ * just the calling package name, or any string of the caller's choice
+ * can be used.
+ * @param key The key of the restriction.
+ * @throws SecurityException if the caller is not a system service.
+ *
+ * @hide
+ */
+ public void addUserRestrictionGlobally(@NonNull String systemEntity,
+ @NonNull @UserManager.UserRestrictionKey String key) {
+ if (mService != null) {
+ try {
+ mService.setUserRestrictionGloballyFromSystem(systemEntity, key,
+ /* enable= */ true);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Called by a profile owner, device owner or a holder of any permission that is associated with
* a user restriction to clear a user restriction specified by the key.
* <p>
@@ -12095,6 +12309,33 @@ public class DevicePolicyManager {
}
/**
+ * Clears a user restriction globally, specified by the {@code key}.
+ *
+ * <p>Called by a system service only, meaning that the caller's UID must be equal to
+ * {@link Process#SYSTEM_UID}.
+ *
+ * @param systemEntity The system entity that clears the restriction. A user restriction
+ * set by a system entity can only be cleared by the same entity. This
+ * can be just the calling package name, or any string of the caller's
+ * choice can be used.
+ * @param key The key of the restriction.
+ * @throws SecurityException if the caller is not a system service.
+ *
+ * @hide
+ */
+ public void clearUserRestrictionGlobally(@NonNull String systemEntity,
+ @NonNull @UserManager.UserRestrictionKey String key) {
+ if (mService != null) {
+ try {
+ mService.setUserRestrictionGloballyFromSystem(systemEntity, key,
+ /* enable= */ false);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Called by an admin to get user restrictions set by themselves with
* {@link #addUserRestriction(ComponentName, String)}.
* <p>
@@ -12551,28 +12792,43 @@ public class DevicePolicyManager {
* @param enabled Whether or not the lockscreen needs to be shown.
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @see #isSecondaryLockscreenEnabled
+ * @deprecated Use {@link #setSecondaryLockscreenEnabled(boolean,PersistableBundle)} instead.
* @hide
- **/
+ */
+ @Deprecated
@SystemApi
+ @FlaggedApi(FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
public void setSecondaryLockscreenEnabled(@NonNull ComponentName admin, boolean enabled) {
- setSecondaryLockscreenEnabled(admin, enabled, null);
+ throwIfParentInstance("setSecondaryLockscreenEnabled");
+ if (mService != null) {
+ try {
+ mService.setSecondaryLockscreenEnabled(admin, enabled, null);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
* Called by the system supervision app to set whether a secondary lockscreen needs to be shown.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
- * caller is not a device admin.
+ * <p>The secondary lockscreen will by displayed after the primary keyguard security screen
+ * requirements are met.
+ *
+ * <p>This API, and associated APIs, can only be called by the default supervision app.
+ *
* @param enabled Whether or not the lockscreen needs to be shown.
* @param options A {@link PersistableBundle} to supply options to the lock screen.
* @hide
*/
- public void setSecondaryLockscreenEnabled(@Nullable ComponentName admin, boolean enabled,
+ @SystemApi
+ @FlaggedApi(FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
+ public void setSecondaryLockscreenEnabled(boolean enabled,
@Nullable PersistableBundle options) {
throwIfParentInstance("setSecondaryLockscreenEnabled");
if (mService != null) {
try {
- mService.setSecondaryLockscreenEnabled(admin, enabled, options);
+ mService.setSecondaryLockscreenEnabled(null, enabled, options);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -14197,7 +14453,7 @@ public class DevicePolicyManager {
* </ul>
* <p>
* The following methods are supported for the parent instance but can only be called by the
- * profile owner of a managed profile that was created during the device provisioning flow:
+ * profile owner on an <a href="#organization-owned">organization owned</a> managed profile:
* <ul>
* <li>{@link #getPasswordComplexity}</li>
* <li>{@link #setCameraDisabled}</li>
@@ -14205,11 +14461,6 @@ public class DevicePolicyManager {
* <li>{@link #setAccountManagementDisabled(ComponentName, String, boolean)}</li>
* <li>{@link #setPermittedInputMethods}</li>
* <li>{@link #getPermittedInputMethods}</li>
- * </ul>
- *
- * <p>The following methods can be called by the profile owner of a managed profile
- * on an organization-owned device:
- * <ul>
* <li>{@link #wipeData}</li>
* </ul>
*
@@ -16941,11 +17192,14 @@ public class DevicePolicyManager {
* @throws SecurityException if the caller does not hold
* {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
* @throws ProvisioningException if an error occurred during provisioning.
+ * @deprecated Use {@link #createManagedProfile} and {@link #finalizeCreateManagedProfile}
* @hide
*/
@Nullable
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
public UserHandle createAndProvisionManagedProfile(
@NonNull ManagedProfileProvisioningParams provisioningParams)
throws ProvisioningException {
@@ -16963,6 +17217,69 @@ public class DevicePolicyManager {
}
/**
+ * Creates a managed profile and sets the
+ * {@link ManagedProfileProvisioningParams#getProfileAdminComponentName()} as the profile
+ * owner. The method {@link #finalizeCreateManagedProfile} must be called after to finalize the
+ * creation of the managed profile.
+ *
+ * <p>The method {@link #checkProvisioningPrecondition} must return {@link #STATUS_OK}
+ * before calling this method. If it doesn't, a ProvisioningException will be thrown.
+ *
+ * @param provisioningParams Params required to provision a managed profile,
+ * see {@link ManagedProfileProvisioningParams}.
+ * @return The {@link UserHandle} of the created profile or {@code null} if the service is
+ * not available.
+ * @throws ProvisioningException if an error occurred during provisioning.
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+ public UserHandle createManagedProfile(
+ @NonNull ManagedProfileProvisioningParams provisioningParams)
+ throws ProvisioningException {
+ if (mService == null) {
+ return null;
+ }
+ try {
+ return mService.createManagedProfile(provisioningParams, mContext.getPackageName());
+ } catch (ServiceSpecificException e) {
+ throw new ProvisioningException(e, e.errorCode, getErrorMessage(e));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Finalizes the creation of a managed profile by informing the necessary components that
+ * the managed profile is ready.
+ *
+ * @param provisioningParams Params required to provision a managed profile,
+ * see {@link ManagedProfileProvisioningParams}.
+ * @param managedProfileUser The recently created managed profile.
+ * @throws ProvisioningException if an error occurred during provisioning.
+ * @hide
+ */
+ @SuppressLint("UserHandle")
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+ public void finalizeCreateManagedProfile(
+ @NonNull ManagedProfileProvisioningParams provisioningParams,
+ @NonNull UserHandle managedProfileUser)
+ throws ProvisioningException {
+ if (mService == null) {
+ return;
+ }
+ try {
+ mService.finalizeCreateManagedProfile(provisioningParams, managedProfileUser);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Removes a manged profile from the device only when called from a managed profile's context
*
* @param user UserHandle of the profile to be removed
@@ -17855,4 +18172,4 @@ public class DevicePolicyManager {
}
return HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index ba97edb98549..d048b5371fc4 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -257,6 +257,7 @@ interface IDevicePolicyManager {
void setUserRestriction(in ComponentName who, in String callerPackage, in String key, boolean enable, boolean parent);
void setUserRestrictionForUser(in String systemEntity, in String key, boolean enable, int targetUser);
void setUserRestrictionGlobally(in String callerPackage, in String key);
+ void setUserRestrictionGloballyFromSystem(in String systemEntity, in String key, boolean enable);
Bundle getUserRestrictions(in ComponentName who, in String callerPackage, boolean parent);
Bundle getUserRestrictionsGlobally(in String callerPackage);
@@ -375,9 +376,15 @@ interface IDevicePolicyManager {
void setAutoTimeEnabled(in ComponentName who, String callerPackageName, boolean enabled);
boolean getAutoTimeEnabled(in ComponentName who, String callerPackageName);
+ void setAutoTimePolicy(String callerPackageName, int policy);
+ int getAutoTimePolicy(String callerPackageName);
+
void setAutoTimeZoneEnabled(in ComponentName who, String callerPackageName, boolean enabled);
boolean getAutoTimeZoneEnabled(in ComponentName who, String callerPackageName);
+ void setAutoTimeZonePolicy(String callerPackageName, int policy);
+ int getAutoTimeZonePolicy(String callerPackageName);
+
void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
boolean getForceEphemeralUsers(in ComponentName who);
@@ -563,6 +570,8 @@ interface IDevicePolicyManager {
void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId);
UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
+ UserHandle createManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
+ void finalizeCreateManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in UserHandle managedProfileUser);
void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount);
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 5f868befa368..581efa5d2efa 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -343,6 +343,16 @@ flag {
}
flag {
+ name: "active_admin_cleanup"
+ namespace: "enterprise"
+ description: "Remove ActiveAdmin from EnforcingAdmin and related cleanups"
+ bug: "335663055"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "user_provisioning_same_state"
namespace: "enterprise"
description: "Handle exceptions while setting same provisioning state."
@@ -372,7 +382,7 @@ flag {
is_exported: true
namespace: "enterprise"
description: "Allows DPMS to enable or disable SupervisionService based on whether the device is being managed by the supervision role holder."
- bug: "376213673"
+ bug: "358134581"
}
flag {
@@ -381,3 +391,11 @@ flag {
description: "Split up existing create and provision managed profile API."
bug: "375382324"
}
+
+flag {
+ name: "secondary_lockscreen_api_enabled"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Add new API for secondary lockscreen"
+ bug: "336297680"
+}
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
index d29c5b58092d..39f10dc0647f 100644
--- a/core/java/android/app/background_install_control_manager.aconfig
+++ b/core/java/android/app/background_install_control_manager.aconfig
@@ -9,3 +9,10 @@ flag {
is_fixed_read_only: true
bug: "287507984"
}
+
+flag {
+ name: "background_install_control_callback_api"
+ namespace: "preload_safety"
+ description: "Feature flag to enable the use of push API in background install control service"
+ bug: "369382811"
+} \ No newline at end of file
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index dcac59c19df4..5004c02194ea 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -16,6 +16,8 @@
package android.app.backup;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Intent;
@@ -27,6 +29,7 @@ import android.os.RemoteException;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.backup.ITransportStatusCallback;
import com.android.internal.infra.AndroidFuture;
+import com.android.server.backup.Flags;
import java.util.Arrays;
import java.util.List;
@@ -671,6 +674,22 @@ public class BackupTransport {
}
/**
+ * Ask the transport whether packages that are about to be backed up or restored should not be
+ * put into a restricted mode by the framework and started normally instead.
+ *
+ * @param operationType 0 for backup, 1 for restore.
+ * @return a subset of the {@code packageNames} passed in, indicating
+ * which packages should NOT be put into restricted mode for the given operation type.
+ */
+ @NonNull
+ @FlaggedApi(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public List<String> getPackagesThatShouldNotUseRestrictedMode(
+ @NonNull List<String> packageNames,
+ @BackupAnnotations.OperationType int operationType) {
+ return List.of();
+ }
+
+ /**
* Bridge between the actual IBackupTransport implementation and the stable API. If the
* binder interface needs to change, we use this layer to translate so that we can
* (if appropriate) decouple those framework-side changes from the BackupTransport
@@ -977,5 +996,19 @@ public class BackupTransport {
resultFuture.cancel(/* mayInterruptIfRunning */ true);
}
}
+
+ @Override
+ @FlaggedApi(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public void getPackagesThatShouldNotUseRestrictedMode(List<String> packageNames,
+ int operationType, AndroidFuture<List<String>> resultFuture) {
+ try {
+ List<String> result =
+ BackupTransport.this.getPackagesThatShouldNotUseRestrictedMode(packageNames,
+ operationType);
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
+ }
}
}
diff --git a/core/java/android/app/jank/FrameOverrunHistogram.java b/core/java/android/app/jank/FrameOverrunHistogram.java
index e28ac126a90a..3ad6531a46bf 100644
--- a/core/java/android/app/jank/FrameOverrunHistogram.java
+++ b/core/java/android/app/jank/FrameOverrunHistogram.java
@@ -39,7 +39,7 @@ public class FrameOverrunHistogram {
* Create a new instance of FrameOverrunHistogram.
*/
public FrameOverrunHistogram() {
- mBucketCounts = new int[sBucketEndpoints.length - 1];
+ mBucketCounts = new int[sBucketEndpoints.length];
}
/**
diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java
index 3783a5f9e829..7ceaeb3fb070 100644
--- a/core/java/android/app/jank/JankDataProcessor.java
+++ b/core/java/android/app/jank/JankDataProcessor.java
@@ -59,7 +59,6 @@ public class JankDataProcessor {
* @param appUid the uid of the app.
*/
public void processJankData(List<JankData> jankData, String activityName, int appUid) {
- mCurrentBatchCount++;
// add all the previous and active states to the pending states list.
mStateTracker.retrieveAllStates(mPendingStates);
@@ -70,8 +69,8 @@ public class JankDataProcessor {
for (int j = 0; j < mPendingStates.size(); j++) {
StateData pendingState = mPendingStates.get(j);
// This state was active during the frame
- if (frame.frameVsyncId >= pendingState.mVsyncIdStart
- && frame.frameVsyncId <= pendingState.mVsyncIdEnd) {
+ if (frame.getVsyncId() >= pendingState.mVsyncIdStart
+ && frame.getVsyncId() <= pendingState.mVsyncIdEnd) {
recordFrameCount(frame, pendingState, activityName, appUid);
pendingState.mProcessed = true;
@@ -79,9 +78,8 @@ public class JankDataProcessor {
}
}
// At this point we have attributed all frames to a state.
- if (mCurrentBatchCount >= LOG_BATCH_FREQUENCY) {
- logMetricCounts();
- }
+ incrementBatchCountAndMaybeLogStats();
+
// return the StatData object back to the pool to be reused.
jankDataProcessingComplete();
}
@@ -91,7 +89,73 @@ public class JankDataProcessor {
* stats
*/
public void mergeJankStats(AppJankStats jankStats, String activityName) {
- // TODO b/377572463 Add Merging Logic
+ // Each state has a key which is a combination of widget category, widget id and widget
+ // state, this key is also used to identify pending stats, a pending stat is essentially a
+ // state with frames associated with it.
+ String stateKey = mStateTracker.getStateKey(jankStats.getWidgetCategory(),
+ jankStats.getWidgetId(), jankStats.getWidgetState());
+
+ if (mPendingJankStats.containsKey(stateKey)) {
+ mergeExistingStat(stateKey, jankStats);
+ } else {
+ mergeNewStat(stateKey, activityName, jankStats);
+ }
+
+ incrementBatchCountAndMaybeLogStats();
+ }
+
+ private void mergeExistingStat(String stateKey, AppJankStats jankStat) {
+ PendingJankStat pendingStat = mPendingJankStats.get(stateKey);
+
+ pendingStat.mJankyFrames += jankStat.getJankyFrameCount();
+ pendingStat.mTotalFrames += jankStat.getTotalFrameCount();
+
+ mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets,
+ jankStat.getFrameOverrunHistogram().getBucketCounters());
+ }
+
+ private void mergeNewStat(String stateKey, String activityName, AppJankStats jankStats) {
+ // Check if we have space for a new stat
+ if (mPendingJankStats.size() > MAX_IN_MEMORY_STATS) {
+ return;
+ }
+
+ PendingJankStat pendingStat = mPendingJankStatsPool.acquire();
+ if (pendingStat == null) {
+ pendingStat = new PendingJankStat();
+
+ }
+ pendingStat.clearStats();
+
+ pendingStat.mActivityName = activityName;
+ pendingStat.mUid = jankStats.getUid();
+ pendingStat.mWidgetId = jankStats.getWidgetId();
+ pendingStat.mWidgetCategory = jankStats.getWidgetCategory();
+ pendingStat.mWidgetState = jankStats.getWidgetState();
+ pendingStat.mTotalFrames = jankStats.getTotalFrameCount();
+ pendingStat.mJankyFrames = jankStats.getJankyFrameCount();
+
+ mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets,
+ jankStats.getFrameOverrunHistogram().getBucketCounters());
+
+ mPendingJankStats.put(stateKey, pendingStat);
+ }
+
+ private void mergeOverrunHistograms(int[] mergeTarget, int[] mergeSource) {
+ // The length of each histogram should be identical, if they are not then its possible the
+ // buckets are not in sync, these records should not be recorded.
+ if (mergeTarget.length != mergeSource.length) return;
+
+ for (int i = 0; i < mergeTarget.length; i++) {
+ mergeTarget[i] += mergeSource[i];
+ }
+ }
+
+ private void incrementBatchCountAndMaybeLogStats() {
+ mCurrentBatchCount++;
+ if (mCurrentBatchCount >= LOG_BATCH_FREQUENCY) {
+ logMetricCounts();
+ }
}
/**
@@ -131,14 +195,14 @@ public class JankDataProcessor {
mPendingJankStats.put(stateData.mStateDataKey, jankStats);
}
// This state has already been accounted for
- if (jankStats.processedVsyncId == frameData.frameVsyncId) return;
+ if (jankStats.processedVsyncId == frameData.getVsyncId()) return;
jankStats.mTotalFrames += 1;
- if (frameData.jankType == JankData.JANK_APPLICATION) {
+ if ((frameData.getJankType() & JankData.JANK_APPLICATION) != 0) {
jankStats.mJankyFrames += 1;
}
- jankStats.recordFrameOverrun(frameData.actualAppFrameTimeNs);
- jankStats.processedVsyncId = frameData.frameVsyncId;
+ jankStats.recordFrameOverrun(frameData.getActualAppFrameTimeNanos());
+ jankStats.processedVsyncId = frameData.getVsyncId();
}
diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java
index 202281f98c97..469521668d25 100644
--- a/core/java/android/app/jank/JankTracker.java
+++ b/core/java/android/app/jank/JankTracker.java
@@ -89,7 +89,12 @@ public class JankTracker {
* stats
*/
public void mergeAppJankStats(AppJankStats appJankStats) {
- mJankDataProcessor.mergeJankStats(appJankStats, mActivityName);
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mJankDataProcessor.mergeJankStats(appJankStats, mActivityName);
+ }
+ });
}
public void setActivityName(@NonNull String activityName) {
diff --git a/core/java/android/app/jank/StateTracker.java b/core/java/android/app/jank/StateTracker.java
index c86d5a5cff20..21bb5e8280ee 100644
--- a/core/java/android/app/jank/StateTracker.java
+++ b/core/java/android/app/jank/StateTracker.java
@@ -180,7 +180,11 @@ public class StateTracker {
}
}
- private String getStateKey(String widgetCategory, String widgetId, String widgetState) {
+ /**
+ * Returns a concatenated string of the inputs. This key can be used to retrieve both pending
+ * stats and the state that was used to create the pending stat.
+ */
+ public String getStateKey(String widgetCategory, String widgetId, String widgetState) {
return widgetCategory + widgetId + widgetState;
}
diff --git a/core/java/android/app/keyguard.aconfig b/core/java/android/app/keyguard.aconfig
new file mode 100644
index 000000000000..9cd1c1579416
--- /dev/null
+++ b/core/java/android/app/keyguard.aconfig
@@ -0,0 +1,10 @@
+package: "android.app"
+container: "system"
+
+flag {
+ namespace: "wallet_integration"
+ name: "device_unlock_listener"
+ is_exported: true
+ description: "Enable listener API for device unlock."
+ bug: "296195355"
+} \ No newline at end of file
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 6934e9883840..8b6840c1b552 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -13,6 +13,13 @@ flag {
}
flag {
+ name: "notifications_redesign_templates"
+ namespace: "systemui"
+ description: "Notifications Redesign: Update notification templates"
+ bug: "378660052"
+}
+
+flag {
name: "modes_api"
is_exported: true
namespace: "systemui"
@@ -268,3 +275,17 @@ flag {
description: "Adds UI for NAS classification of notifications"
bug: "367996732"
}
+
+flag {
+ name: "nm_binder_perf_permission_check"
+ namespace: "systemui"
+ description: "Use PermissionManager for areNotificationsEnabled() instead of NMS"
+ bug: "362981561"
+}
+
+flag {
+ name: "no_sbnholder"
+ namespace: "systemui"
+ description: "removes sbnholder from NLS"
+ bug: "362981561"
+}
diff --git a/core/java/android/app/ondeviceintelligence/InferenceInfo.java b/core/java/android/app/ondeviceintelligence/InferenceInfo.java
index 5557a81cbe40..cae8db27a435 100644
--- a/core/java/android/app/ondeviceintelligence/InferenceInfo.java
+++ b/core/java/android/app/ondeviceintelligence/InferenceInfo.java
@@ -16,6 +16,12 @@
package android.app.ondeviceintelligence;
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,7 +31,9 @@ import android.os.Parcelable;
*
* @hide
*/
-public class InferenceInfo implements Parcelable {
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE)
+public final class InferenceInfo implements Parcelable {
/**
* Uid for the caller app.
@@ -55,7 +63,7 @@ public class InferenceInfo implements Parcelable {
* @param endTimeMs Inference end time (milliseconds from the epoch time).
* @param suspendedTimeMs Suspended time in milliseconds.
*/
- public InferenceInfo(int uid, long startTimeMs, long endTimeMs,
+ InferenceInfo(int uid, long startTimeMs, long endTimeMs,
long suspendedTimeMs) {
this.uid = uid;
this.startTimeMs = startTimeMs;
@@ -68,7 +76,7 @@ public class InferenceInfo implements Parcelable {
*
* @param in The Parcel to read the object's data from.
*/
- protected InferenceInfo(Parcel in) {
+ private InferenceInfo(@NonNull Parcel in) {
uid = in.readInt();
startTimeMs = in.readLong();
endTimeMs = in.readLong();
@@ -79,11 +87,11 @@ public class InferenceInfo implements Parcelable {
/**
* Writes the object's data to the provided Parcel.
*
- * @param dest The Parcel to write the object's data to.
+ * @param dest The Parcel to write the object's data to.
* @param flags Additional flags about how the object should be written.
*/
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(uid);
dest.writeLong(startTimeMs);
dest.writeLong(endTimeMs);
@@ -104,7 +112,8 @@ public class InferenceInfo implements Parcelable {
*
* @return the inference start time in milliseconds from the epoch time.
*/
- public long getStartTimeMs() {
+ @CurrentTimeMillisLong
+ public long getStartTimeMillis() {
return startTimeMs;
}
@@ -113,7 +122,8 @@ public class InferenceInfo implements Parcelable {
*
* @return the inference end time in milliseconds from the epoch time.
*/
- public long getEndTimeMs() {
+ @CurrentTimeMillisLong
+ public long getEndTimeMillis() {
return endTimeMs;
}
@@ -122,7 +132,8 @@ public class InferenceInfo implements Parcelable {
*
* @return the suspended time in milliseconds.
*/
- public long getSuspendedTimeMs() {
+ @CurrentTimeMillisLong
+ public long getSuspendedTimeMillis() {
return suspendedTimeMs;
}
@@ -148,21 +159,19 @@ public class InferenceInfo implements Parcelable {
/**
* Builder class for creating instances of {@link InferenceInfo}.
*/
- public static class Builder {
- private int uid;
+ public static final class Builder {
+ private final int uid;
private long startTimeMs;
private long endTimeMs;
private long suspendedTimeMs;
/**
- * Sets the UID for the caller app.
+ * Provides a builder instance to create a InferenceInfo for given caller uid.
*
- * @param uid the UID for the caller app.
- * @return the Builder instance.
+ * @param uid the caller uid associated with the inference info.
*/
- public Builder setUid(int uid) {
+ public Builder(int uid) {
this.uid = uid;
- return this;
}
/**
@@ -171,7 +180,7 @@ public class InferenceInfo implements Parcelable {
* @param startTimeMs the inference start time in milliseconds from the epoch time.
* @return the Builder instance.
*/
- public Builder setStartTimeMs(long startTimeMs) {
+ public @NonNull Builder setStartTimeMillis(@CurrentTimeMillisLong long startTimeMs) {
this.startTimeMs = startTimeMs;
return this;
}
@@ -182,7 +191,7 @@ public class InferenceInfo implements Parcelable {
* @param endTimeMs the inference end time in milliseconds from the epoch time.
* @return the Builder instance.
*/
- public Builder setEndTimeMs(long endTimeMs) {
+ public @NonNull Builder setEndTimeMillis(@CurrentTimeMillisLong long endTimeMs) {
this.endTimeMs = endTimeMs;
return this;
}
@@ -193,7 +202,7 @@ public class InferenceInfo implements Parcelable {
* @param suspendedTimeMs the suspended time in milliseconds.
* @return the Builder instance.
*/
- public Builder setSuspendedTimeMs(long suspendedTimeMs) {
+ public @NonNull Builder setSuspendedTimeMillis(@CurrentTimeMillisLong long suspendedTimeMs) {
this.suspendedTimeMs = suspendedTimeMs;
return this;
}
@@ -203,7 +212,7 @@ public class InferenceInfo implements Parcelable {
*
* @return an instance of {@link InferenceInfo}.
*/
- public InferenceInfo build() {
+ public @NonNull InferenceInfo build() {
return new InferenceInfo(uid, startTimeMs, endTimeMs,
suspendedTimeMs);
}
diff --git a/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
index 937a9cde1097..91651e317b18 100644
--- a/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
+++ b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
@@ -17,9 +17,11 @@
package android.app.ondeviceintelligence;
import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -502,11 +504,10 @@ public final class OnDeviceIntelligenceManager {
*
* @param startTimeEpochMillis epoch millis used to filter the InferenceInfo events.
* @return InferenceInfo events since the passed in startTimeEpochMillis.
- *
- * @hide
*/
@RequiresPermission(Manifest.permission.DUMP)
- public List<InferenceInfo> getLatestInferenceInfo(long startTimeEpochMillis) {
+ @FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE)
+ public @NonNull List<InferenceInfo> getLatestInferenceInfo(@CurrentTimeMillisLong long startTimeEpochMillis) {
try {
return mService.getLatestInferenceInfo(startTimeEpochMillis);
} catch (RemoteException e) {
diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
index 8b6441ae5a7c..74a96c864167 100644
--- a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
+++ b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
@@ -8,3 +8,10 @@ flag {
description: "Make methods on OnDeviceIntelligenceManager available for local inference."
bug: "304755128"
}
+flag {
+ name: "enable_on_device_intelligence_module"
+ is_exported: true
+ namespace: "ondeviceintelligence"
+ description: "Enable migration to mainline module and related changes."
+ bug: "376427781"
+} \ No newline at end of file
diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig
index 61b53f97fea1..359c84eeb559 100644
--- a/core/java/android/app/performance.aconfig
+++ b/core/java/android/app/performance.aconfig
@@ -35,3 +35,10 @@ flag {
bug: "373752556"
}
+flag {
+ namespace: "system_performance"
+ name: "pic_cache_nulls"
+ is_fixed_read_only: true
+ description: "Cache null returns from binder calls"
+ bug: "372923336"
+}
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java b/core/java/android/app/supervision/SupervisionManagerInternal.java
index 5df9dd521092..d571e14ff5fa 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java
+++ b/core/java/android/app/supervision/SupervisionManagerInternal.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.server.supervision;
+package android.app.supervision;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.os.Bundle;
+import android.os.PersistableBundle;
/**
* Local system service interface for {@link SupervisionService}.
@@ -35,6 +35,11 @@ public abstract class SupervisionManagerInternal {
public abstract boolean isSupervisionEnabledForUser(@UserIdInt int userId);
/**
+ * Returns whether the supervision lock screen needs to be shown.
+ */
+ public abstract boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId);
+
+ /**
* Set whether supervision is enabled for the specified user.
*
* @param userId The user to set the supervision state for
@@ -50,5 +55,5 @@ public abstract class SupervisionManagerInternal {
* @param options Optional configuration parameters for the supervision lock screen
*/
public abstract void setSupervisionLockscreenEnabledForUser(
- @UserIdInt int userId, boolean enabled, @Nullable Bundle options);
+ @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options);
}
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 730bb73da3bb..ffa54881cb9d 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -18,6 +18,7 @@ package android.app.trust;
import android.app.trust.ITrustListener;
import android.hardware.biometrics.BiometricSourceType;
+import com.android.internal.policy.IDeviceLockedStateListener;
/**
* System private API to comunicate with trust service.
@@ -43,4 +44,8 @@ interface ITrustManager {
boolean isActiveUnlockRunning(int userId);
@EnforcePermission("ACCESS_FINE_LOCATION")
boolean isInSignificantPlace();
+ @EnforcePermission("SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE")
+ void registerDeviceLockedStateListener(in IDeviceLockedStateListener listener, int deviceId);
+ @EnforcePermission("SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE")
+ void unregisterDeviceLockedStateListener(in IDeviceLockedStateListener listener);
}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 1ef83cdf3f85..8c8970ea5834 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -31,6 +31,8 @@ import android.os.Message;
import android.os.RemoteException;
import android.util.ArrayMap;
+import com.android.internal.policy.IDeviceLockedStateListener;
+
import java.util.ArrayList;
import java.util.List;
@@ -259,6 +261,35 @@ public class TrustManager {
}
/**
+ * Registers a listener for device lock state events.
+ *
+ * Requires the {@link android.Manifest.permission#SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE}
+ * permission.
+ */
+ public void registerDeviceLockedStateListener(final IDeviceLockedStateListener listener,
+ int deviceId) {
+ try {
+ mService.registerDeviceLockedStateListener(listener, deviceId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters a listener for device lock state events.
+ *
+ * Requires the {@link android.Manifest.permission#SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE}
+ * permission.
+ */
+ public void unregisterDeviceLockedStateListener(final IDeviceLockedStateListener listener) {
+ try {
+ mService.unregisterDeviceLockedStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @return whether {@param userId} has enabled and configured trust agents. Ignores short-term
* unavailability of trust due to {@link LockPatternUtils.StrongAuthTracker}.
*/
diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java
index f0763752e054..5b14b038f130 100644
--- a/core/java/android/app/wearable/WearableSensingManager.java
+++ b/core/java/android/app/wearable/WearableSensingManager.java
@@ -55,6 +55,7 @@ import java.io.OutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -248,7 +249,11 @@ public class WearableSensingManager {
* @param executor Executor on which to run the consumer callback
* @param statusConsumer A consumer that handles the status codes for providing the connection
* and errors in the encrypted channel.
+ * @deprecated Use {@link #provideConnection(WearableConnection, Executor)} instead to provide a
+ * remote wearable device connection to the WearableSensingService
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
+ @Deprecated
@RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
public void provideConnection(
@NonNull ParcelFileDescriptor wearableConnection,
@@ -348,9 +353,7 @@ public class WearableSensingManager {
wearableConnection.getMetadata(),
createWearableSensingCallback(executor),
statusCallback);
- if (connectionId != CONNECTION_ID_INVALID) {
- mWearableConnectionIdMap.put(wearableConnection, connectionId);
- }
+ mWearableConnectionIdMap.put(wearableConnection, connectionId);
// For invalid connection IDs, the status callback will remove the connection from
// mWearableConnectionIdMap
} catch (RemoteException e) {
@@ -367,36 +370,37 @@ public class WearableSensingManager {
* <p>After this method returns, there will be no new invocation to callback methods in the
* removed {@link WearableConnection}. Ongoing invocations will continue to run.
*
- * <p>This method does nothing if the provided {@code wearableConnection} does not match any
- * open connection.
+ * <p>This method throws a {@link NoSuchElementException} if the provided {@code
+ * wearableConnection} does not match any open connection.
*
* <p>This method should not be called before the corresponding {@link
* #provideConnection(WearableConnection, Executor)} invocation returns. Otherwise, the
- * connection may not be removed.
+ * connection may not be removed, and an {@link IllegalStateException} may be thrown.
*
* @param wearableConnection The WearableConnection instance previously provided to {@link
* #provideConnection(WearableConnection, Executor)}.
- * @return true if a concurrent connection quota has been freed due to this method invocation.
- * Returns false otherwise.
+ * @throws NoSuchElementException if the connection was never provided or was already removed.
+ * @throws IllegalStateException if the {@link #provideConnection(WearableConnection, Executor)}
+ * invocation for the given connection has not returned.
*/
@RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
@FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
- public boolean removeConnection(@NonNull WearableConnection wearableConnection) {
- int connectionId =
- mWearableConnectionIdMap.getOrDefault(wearableConnection, CONNECTION_ID_INVALID);
- if (connectionId == CONNECTION_ID_INVALID) {
- return false;
+ public void removeConnection(@NonNull WearableConnection wearableConnection) {
+ Integer connectionId = mWearableConnectionIdMap.remove(wearableConnection);
+ if (connectionId == null || connectionId == CONNECTION_ID_INVALID) {
+ throw new NoSuchElementException(
+ "The provided connection was never provided or was already removed.");
}
if (connectionId == CONNECTION_ID_PLACEHOLDER) {
- Slog.w(
- TAG,
+ throw new IllegalStateException(
"Attempt to remove connection before provideConnection returns. The connection"
+ " will not be removed.");
- return false;
}
- mWearableConnectionIdMap.remove(wearableConnection);
try {
- return mService.removeConnection(connectionId);
+ if (!mService.removeConnection(connectionId)) {
+ throw new NoSuchElementException(
+ "The provided connection was never provided or was already removed.");
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 8f20ea034cf6..40de2985f68a 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -31,6 +31,7 @@ import android.annotation.UiThread;
import android.annotation.UserIdInt;
import android.app.IServiceConnection;
import android.app.PendingIntent;
+import android.app.usage.UsageStatsManager;
import android.appwidget.flags.Flags;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -41,12 +42,14 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
+import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -485,6 +488,67 @@ public class AppWidgetManager {
public static final String ACTION_APPWIDGET_HOST_RESTORED
= "android.appwidget.action.APPWIDGET_HOST_RESTORED";
+ /**
+ * This is the value of {@link UsageStatsManager.EXTRA_EVENT_ACTION} in the event bundle for
+ * widget user interaction events.
+ *
+ * A single widget interaction event describes what user interactions happened during a single
+ * impression of the widget.
+ */
+ @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+ public static final String EVENT_TYPE_WIDGET_INTERACTION = "widget_interaction";
+
+ /**
+ * This is the value of {@link UsageStatsManager.EXTRA_EVENT_CATEGORY} in the event bundle for
+ * widget user interaction events.
+ */
+ @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+ public static final String EVENT_CATEGORY_APPWIDGET = "android.appwidget";
+
+ /**
+ * This bundle extra describes which views have been clicked during a single impression of the
+ * widget. It is an integer array of view IDs of the clicked views.
+ *
+ * Widget providers may set a different ID for event purposes by setting the
+ * {@link android.R.id.remoteViewsMetricsId} int tag on the view.
+ *
+ * @see android.views.RemoteViews.setIntTag
+ */
+ @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+ public static final String EXTRA_EVENT_CLICKED_VIEWS =
+ "android.appwidget.extra.EVENT_CLICKED_VIEWS";
+
+ /**
+ * This bundle extra describes which views have been scrolled during a single impression of the
+ * widget. It is an integer array of view IDs of the scrolled views.
+ *
+ * Widget providers may set a different ID for event purposes by setting the
+ * {@link android.R.id.remoteViewsMetricsId} int tag on the view.
+ *
+ * @see android.views.RemoteViews.setIntTag
+ */
+ @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+ public static final String EXTRA_EVENT_SCROLLED_VIEWS =
+ "android.appwidget.extra.EVENT_SCROLLED_VIEWS";
+
+ /**
+ * This bundle extra contains a long that represents the duration of time in milliseconds
+ * during which the widget was visible.
+ */
+ @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+ public static final String EXTRA_EVENT_DURATION_MS =
+ "android.appwidget.extra.EVENT_DURATION_MS";
+
+ /**
+ * This bundle extra contains an integer array with 4 elements that describe the left, top,
+ * right, and bottom coordinates of the widget at the end of the interaction event.
+ *
+ * This Rect indicates the current position and size of the widget.
+ */
+ @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+ public static final String EXTRA_EVENT_POSITION_RECT =
+ "android.appwidget.extra.EVENT_POSITION_RECT";
+
private static final String TAG = "AppWidgetManager";
private static Executor sUpdateExecutor;
@@ -1516,6 +1580,39 @@ public class AppWidgetManager {
}
}
+ /**
+ * Create a {@link PersistableBundle} that represents a single widget interaction event.
+ *
+ * @param appWidgetId App Widget ID of the widget.
+ * @param durationMs Duration of the impression in milliseconds
+ * @param position Current position of the widget.
+ * @param clickedIds IDs of views clicked during this event.
+ * @param scrolledIds IDs of views scrolled during this event.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+ @NonNull
+ public static PersistableBundle createWidgetInteractionEvent(int appWidgetId, long durationMs,
+ @Nullable Rect position, @Nullable int[] clickedIds, @Nullable int[] scrolledIds) {
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, EVENT_TYPE_WIDGET_INTERACTION);
+ extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, EVENT_CATEGORY_APPWIDGET);
+ extras.putInt(EXTRA_APPWIDGET_ID, appWidgetId);
+ extras.putLong(EXTRA_EVENT_DURATION_MS, durationMs);
+ if (position != null) {
+ extras.putIntArray(EXTRA_EVENT_POSITION_RECT,
+ new int[]{position.left, position.top, position.right, position.bottom});
+ }
+ if (clickedIds != null && clickedIds.length > 0) {
+ extras.putIntArray(EXTRA_EVENT_CLICKED_VIEWS, clickedIds);
+ }
+ if (scrolledIds != null && scrolledIds.length > 0) {
+ extras.putIntArray(EXTRA_EVENT_SCROLLED_VIEWS, scrolledIds);
+ }
+ return extras;
+ }
+
@UiThread
private static @NonNull Executor createUpdateExecutorIfNull() {
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index ce515761551c..17bcdb013673 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -76,12 +76,15 @@ flag {
}
flag {
- name: "use_smaller_app_widget_radius"
+ name: "use_smaller_app_widget_system_radius"
namespace: "app_widgets"
description: "Updates system corner radius for app widgets to 24.dp instead of 28.dp"
bug: "373351337"
is_exported: true
is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -92,3 +95,20 @@ flag {
is_exported: true
is_fixed_read_only: true
}
+
+flag {
+ name: "check_remote_views_uri_permission"
+ namespace: "app_widgets"
+ description: "Check that the widget provider has permissions to access any URIs within its RemoteViews"
+ bug: "369137473"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "engagement_metrics"
+ namespace: "app_widgets"
+ description: "Enable collection of widget engagement metrics"
+ bug: "364655296"
+}
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index d3a1c25b74d5..367f1afc912b 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -90,11 +90,6 @@ interface IVirtualDevice {
*/
boolean hasCustomAudioInputSupport();
- /**
- * Returns whether this device is allowed to create mirror displays.
- */
- boolean canCreateMirrorDisplays();
-
/*
* Turns off all trusted non-mirror displays of the virtual device.
*/
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 3e6919bac5fa..46da4a3d99bc 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -81,14 +81,3 @@ flag {
description: "Enable virtual stylus input"
bug: "304829446"
}
-
-flag {
- name: "impulse_velocity_strategy_for_touch_navigation"
- is_exported: true
- namespace: "virtual_devices"
- description: "Use impulse velocity strategy during conversion of touch navigation flings into Dpad events"
- bug: "338426241"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-} \ No newline at end of file
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index c47fe236faf0..de01280f293f 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -148,6 +148,14 @@ flag {
flag {
namespace: "virtual_devices"
+ name: "notifications_for_device_streaming"
+ description: "Add notifications permissions to device streaming role"
+ bug: "375240276"
+ is_exported: true
+}
+
+flag {
+ namespace: "virtual_devices"
name: "default_device_camera_access_policy"
description: "API for default device camera access policy"
bug: "371173368"
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 964a8be0f153..a81629445263 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -356,7 +356,6 @@ public abstract class BroadcastReceiver {
}
RuntimeException e = new RuntimeException(
"BroadcastReceiver trying to return result during a non-ordered broadcast");
- e.fillInStackTrace();
Log.e("BroadcastReceiver", e.getMessage(), e);
}
}
@@ -768,7 +767,6 @@ public abstract class BroadcastReceiver {
}
RuntimeException e = new RuntimeException(
"BroadcastReceiver trying to return result during a non-ordered broadcast");
- e.fillInStackTrace();
Log.e("BroadcastReceiver", e.getMessage(), e);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6086f2455a31..acad92c90c59 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -18,6 +18,7 @@ package android.content;
import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS;
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
import android.annotation.AttrRes;
import android.annotation.CallbackExecutor;
@@ -4256,6 +4257,7 @@ public abstract class Context {
FINGERPRINT_SERVICE,
//@hide: FACE_SERVICE,
BIOMETRIC_SERVICE,
+ AUTHENTICATION_POLICY_SERVICE,
MEDIA_ROUTER_SERVICE,
TELEPHONY_SERVICE,
TELEPHONY_SUBSCRIPTION_SERVICE,
@@ -4437,6 +4439,9 @@ public abstract class Context {
* web domain approval state.
* <dt> {@link #DISPLAY_HASH_SERVICE} ("display_hash")
* <dd> A {@link android.view.displayhash.DisplayHashManager} for management of display hashes.
+ * <dt> {@link #AUTHENTICATION_POLICY_SERVICE} ("authentication_policy")
+ * <dd> A {@link android.security.authenticationpolicy.AuthenticationPolicyManager}
+ * for managing authentication related policies on the device.
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -4521,8 +4526,9 @@ public abstract class Context {
* @see android.content.pm.verify.domain.DomainVerificationManager
* @see #DISPLAY_HASH_SERVICE
* @see android.view.displayhash.DisplayHashManager
+ * @see #AUTHENTICATION_POLICY_SERVICE
+ * @see android.security.authenticationpolicy.AuthenticationPolicyManager
*/
- // TODO(b/347269120): Re-add @Nullable
public abstract Object getSystemService(@ServiceName @NonNull String name);
/**
@@ -4543,7 +4549,8 @@ public abstract class Context {
* {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
* {@link android.app.usage.NetworkStatsManager},
* {@link android.content.pm.verify.domain.DomainVerificationManager},
- * {@link android.view.displayhash.DisplayHashManager}.
+ * {@link android.view.displayhash.DisplayHashManager}
+ * {@link android.security.authenticationpolicy.AuthenticationPolicyManager}.
* </p>
*
* <p>
@@ -4568,7 +4575,6 @@ public abstract class Context {
*/
@SuppressWarnings("unchecked")
@RavenwoodKeep
- // TODO(b/347269120): Re-add @Nullable
public final <T> T getSystemService(@NonNull Class<T> serviceClass) {
// Because subclasses may override getSystemService(String) we cannot
// perform a lookup by class alone. We must first map the class to its
@@ -5183,6 +5189,18 @@ public abstract class Context {
public static final String AUTH_SERVICE = "auth";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an {@link
+ * android.security.authenticationpolicy.AuthenticationPolicyManager}.
+ * @see #getSystemService
+ * @see android.security.authenticationpolicy.AuthenticationPolicyManager
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.hardware.fingerprint.FingerprintManager} for handling management
* of fingerprints.
@@ -5695,12 +5713,12 @@ public abstract class Context {
public static final String BINARY_TRANSPARENCY_SERVICE = "transparency";
/**
- * System service name for ForensicService.
- * The service manages the forensic info on device.
+ * System service name for IntrusionDetectionService.
+ * The service manages the intrusion detection info on device.
* @hide
*/
@FlaggedApi(android.security.Flags.FLAG_AFL_API)
- public static final String FORENSIC_SERVICE = "forensic";
+ public static final String INTRUSION_DETECTION_SERVICE = "intrusion_detection";
/**
* System service name for the DeviceIdleManager.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 23d17cb5ce50..413eb9886392 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -960,7 +960,6 @@ public class ContextWrapper extends Context {
}
@Override
- // TODO(b/347269120): Re-add @Nullable
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b776b59f11c2..02eed1a7553f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -87,7 +87,6 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import com.android.modules.expresslog.Counter;
@@ -1212,8 +1211,8 @@ public class Intent implements Parcelable, Cloneable {
* {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls rather than
* relying on this intent.
*
- * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M}
- * and above and declares as using the {@link android.Manifest.permission#CALL_PHONE}
+ * <p>Note: If your app targets {@link android.os.Build.VERSION_CODES#M M}
+ * or higher and declares as using the {@link android.Manifest.permission#CALL_PHONE}
* permission which is not granted, then attempting to use this action will
* result in a {@link java.lang.SecurityException}.
*/
@@ -7721,6 +7720,7 @@ public class Intent implements Parcelable, Cloneable {
@IntDef(flag = true, prefix = { "EXTENDED_FLAG_" }, value = {
EXTENDED_FLAG_FILTER_MISMATCH,
EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN,
+ EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ExtendedFlags {}
@@ -7741,6 +7741,13 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final int EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN = 1 << 1;
+ /**
+ * This flag indicates this intent called {@link #collectExtraIntentKeys()}.
+ *
+ * @hide
+ */
+ public static final int EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED = 1 << 2;
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// toUri() and parseUri() options.
@@ -12304,7 +12311,6 @@ public class Intent implements Parcelable, Cloneable {
}
/** @hide */
- @VisibleForTesting
public Set<NestedIntentKey> getExtraIntentKeys() {
return mCreatorTokenInfo == null ? null : mCreatorTokenInfo.mNestedIntentKeys;
}
@@ -12330,7 +12336,8 @@ public class Intent implements Parcelable, Cloneable {
}
private void collectNestedIntentKeysRecur(Set<Intent> visited) {
- if (mExtras != null && !mExtras.isParcelled() && !mExtras.isEmpty()) {
+ addExtendedFlags(EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED);
+ if (mExtras != null && !mExtras.isEmpty()) {
for (String key : mExtras.keySet()) {
Object value = mExtras.get(key);
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index ed965b3d1777..6db7dfe4f705 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -78,7 +78,8 @@ public class OverlayManager {
/**
* Applications can use OverlayManager to create overlays to overlay on itself resources. The
- * overlay target is itself and the work range is only in caller application.
+ * overlay target is itself, or the Android package, and the work range is only in caller
+ * application.
*
* <p>In {@link android.content.Context#getSystemService(String)}, it crashes because of {@link
* java.lang.NullPointerException} if the parameter is OverlayManager. if the self-targeting is
@@ -401,7 +402,7 @@ public class OverlayManager {
}
/**
- * Get the related information of overlays for {@code targetPackageName}.
+ * Get the related information of self-targeting overlays for {@code targetPackageName}.
*
* @param targetPackageName the target package name
* @return a list of overlay information
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
index becd0ea285af..87b2e9350aa1 100644
--- a/core/java/android/content/om/OverlayManagerTransaction.java
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -209,6 +209,7 @@ public final class OverlayManagerTransaction implements Parcelable {
*/
public static final class Builder {
private final List<Request> mRequests = new ArrayList<>();
+ private boolean mSelfTargeting = false;
/**
* Request that an overlay package be enabled and change its loading
@@ -246,6 +247,18 @@ public final class OverlayManagerTransaction implements Parcelable {
}
/**
+ * Request that an overlay package be self-targeting. Self-targeting overlays enable
+ * applications to overlay on itself resources. The overlay target is itself, or the Android
+ * package, and the work range is only in caller application.
+ * @param selfTargeting whether the overlay is self-targeting, the default is false.
+ * @hide
+ */
+ public Builder setSelfTargeting(boolean selfTargeting) {
+ mSelfTargeting = selfTargeting;
+ return this;
+ }
+
+ /**
* Registers the fabricated overlay with the overlay manager so it can be enabled and
* disabled for any user.
*
@@ -286,7 +299,7 @@ public final class OverlayManagerTransaction implements Parcelable {
*/
@NonNull
public OverlayManagerTransaction build() {
- return new OverlayManagerTransaction(mRequests, false /* selfTargeting */);
+ return new OverlayManagerTransaction(mRequests, mSelfTargeting);
}
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index ce52825ddb73..37f3f17ebe42 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -453,6 +453,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* Value of {@link #colorMode} indicating that the activity should use a
* high dynamic range if the presentation display supports it.
*
+ * <p>Note: This does not impact SurfaceViews or SurfaceControls, as those have their own
+ * independent HDR support.</p>
+ *
+ * <p><b>Important:</b> Although this value was added in API 26, it is strongly recommended
+ * to avoid using it until API 34 which is when HDR support for the UI toolkit was officially
+ * added.</p>
+ *
* @see android.R.attr#colorMode
*/
public static final int COLOR_MODE_HDR = 2;
@@ -1320,23 +1327,23 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
264301586L; // buganizer id
/**
- * Excludes the packages the override is applied to from the camera compatibility treatment
- * in free-form windowing mode for fixed-orientation apps.
+ * Includes the packages the override is applied to in the camera compatibility treatment in
+ * free-form windowing mode for fixed-orientation apps.
*
* <p>In free-form windowing mode, the compatibility treatment emulates running on a portrait
* device by letterboxing the app window and changing the camera characteristics to what apps
* commonly expect in a portrait device: 90 and 270 degree sensor rotation for back and front
* cameras, respectively, and setting display rotation to 0.
*
- * <p>Use this flag to disable the compatibility treatment for apps that do not respond well to
- * the treatment.
+ * <p>Use this flag to enable the compatibility treatment for apps in which camera doesn't work
+ * well in freeform windowing.
*
* @hide
*/
@ChangeId
@Overridable
@Disabled
- public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT =
+ public static final long OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT =
314961188L;
/**
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 4fdbf1e9e622..451c0e5e079a 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -93,10 +93,4 @@ interface IPackageInstaller {
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})")
void reportUnarchivalStatus(int unarchiveId, int status, long requiredStorageBytes, in PendingIntent userActionIntent, in UserHandle userHandle);
-
- @EnforcePermission("VERIFICATION_AGENT")
- int getVerificationPolicy(int userId);
-
- @EnforcePermission("VERIFICATION_AGENT")
- boolean setVerificationPolicy(int policy, int userId);
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 63279af8480d..cd62573f6e4e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -62,8 +62,6 @@ import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.pm.verify.domain.DomainSet;
-import android.content.pm.verify.pkg.VerificationSession;
-import android.content.pm.verify.pkg.VerificationStatus;
import android.graphics.Bitmap;
import android.icu.util.ULocale;
import android.net.Uri;
@@ -220,6 +218,17 @@ public class PackageInstaller {
"android.content.pm.action.CONFIRM_PRE_APPROVAL";
/**
+ * Intent action to be sent to the implementer of
+ * {@link android.content.pm.dependencyinstaller.DependencyInstallerService}.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+ @SystemApi
+ public static final String ACTION_INSTALL_DEPENDENCY =
+ "android.content.pm.action.INSTALL_DEPENDENCY";
+
+ /**
* An integer session ID that an operation is working with.
*
* @see Intent#getIntExtra(String, int)
@@ -420,21 +429,6 @@ public class PackageInstaller {
public static final String EXTRA_WARNINGS = "android.content.pm.extra.WARNINGS";
/**
- * When verification is blocked as part of the installation, additional reason for the block
- * will be provided to the installer with a {@link VerificationFailedReason} as part of the
- * installation result returned via the {@link IntentSender} in
- * {@link Session#commit(IntentSender)}. This extra is provided only when the installation has
- * failed. Installers can use this extra to check if the installation failure was caused by a
- * verification failure.
- *
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final String EXTRA_VERIFICATION_FAILURE_REASON =
- "android.content.pm.extra.VERIFICATION_FAILURE_REASON";
-
- /**
* Streaming installation pending.
* Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
*
@@ -777,90 +771,6 @@ public class PackageInstaller {
@Retention(RetentionPolicy.SOURCE)
public @interface UnarchivalStatus {}
- /**
- * Verification failed because of unknown reasons, such as when the verifier times out or cannot
- * be connected. It can also corresponds to the status of
- * {@link VerificationSession#VERIFICATION_INCOMPLETE_UNKNOWN} reported by the verifier via
- * {@link VerificationSession#reportVerificationIncomplete(int)}.
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final int VERIFICATION_FAILED_REASON_UNKNOWN = 0;
-
- /**
- * Verification failed because the network is unavailable. This corresponds to the status of
- * {@link VerificationSession#VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE} reported by the
- * verifier via {@link VerificationSession#reportVerificationIncomplete(int)}.
- *
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final int VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE = 1;
-
- /**
- * Verification failed because the package is blocked, as reported by the verifier via
- * {@link VerificationSession#reportVerificationComplete(VerificationStatus)} or
- * {@link VerificationSession#reportVerificationComplete(VerificationStatus, PersistableBundle)}
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final int VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED = 2;
-
- /**
- * @hide
- */
- @IntDef(value = {
- VERIFICATION_FAILED_REASON_UNKNOWN,
- VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE,
- VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED,
- })
- public @interface VerificationFailedReason {
- }
-
- /**
- * Do not block installs, regardless of verification status.
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final int VERIFICATION_POLICY_NONE = 0; // platform default
- /**
- * Only block installations on {@link #VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED}.
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final int VERIFICATION_POLICY_BLOCK_FAIL_OPEN = 1;
- /**
- * Only block installations on {@link #VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED} and ask the
- * user if they'd like to install anyway when the verification is blocked for other reason.
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final int VERIFICATION_POLICY_BLOCK_FAIL_WARN = 2;
- /**
- * Block installations whose verification status is blocked for any reason.
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- public static final int VERIFICATION_POLICY_BLOCK_FAIL_CLOSED = 3;
- /**
- * @hide
- */
- @IntDef(value = {
- VERIFICATION_POLICY_NONE,
- VERIFICATION_POLICY_BLOCK_FAIL_OPEN,
- VERIFICATION_POLICY_BLOCK_FAIL_WARN,
- VERIFICATION_POLICY_BLOCK_FAIL_CLOSED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface VerificationPolicy {
- }
/** Default set of checksums - includes all available checksums.
* @see Session#requestChecksums */
@@ -1604,40 +1514,6 @@ public class PackageInstaller {
}
/**
- * Return the current verification enforcement policy. This may only be called by the
- * package currently set by the system as the verifier agent.
- * @hide
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)
- public final @VerificationPolicy int getVerificationPolicy() {
- try {
- return mInstaller.getVerificationPolicy(mUserId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Set the current verification enforcement policy which will be applied to all the future
- * installation sessions. This may only be called by the package currently set by the system as
- * the verifier agent.
- * @hide
- * @return whether the new policy was successfully set.
- */
- @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
- @SystemApi
- @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)
- public final boolean setVerificationPolicy(@VerificationPolicy int policy) {
- try {
- return mInstaller.setVerificationPolicy(policy, mUserId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* An installation that is being actively staged. For an install to succeed,
* all existing and new packages must have identical package names, version
* codes, and signing certificates.
@@ -2935,8 +2811,6 @@ public class PackageInstaller {
/** {@hide} */
public @Nullable String dexoptCompilerFilter = null;
/** {@hide} */
- public boolean forceVerification;
- /** {@hide} */
public boolean isAutoInstallDependenciesEnabled = true;
private final ArrayMap<String, Integer> mPermissionStates;
@@ -2992,7 +2866,6 @@ public class PackageInstaller {
developmentInstallFlags = source.readInt();
unarchiveId = source.readInt();
dexoptCompilerFilter = source.readString();
- forceVerification = source.readBoolean();
isAutoInstallDependenciesEnabled = source.readBoolean();
}
@@ -3030,7 +2903,6 @@ public class PackageInstaller {
ret.developmentInstallFlags = developmentInstallFlags;
ret.unarchiveId = unarchiveId;
ret.dexoptCompilerFilter = dexoptCompilerFilter;
- ret.forceVerification = forceVerification;
ret.isAutoInstallDependenciesEnabled = isAutoInstallDependenciesEnabled;
return ret;
}
@@ -3741,14 +3613,6 @@ public class PackageInstaller {
}
/**
- * Used by adb installations to force enable the verification for this install.
- * {@hide}
- */
- public void setForceVerification() {
- this.forceVerification = true;
- }
-
- /**
* Optionally indicate whether missing SDK or static shared library dependencies should be
* automatically fetched and installed when installing an app that wants to use these
* dependencies.
@@ -3761,7 +3625,7 @@ public class PackageInstaller {
* dependencies aren't already installed.
*/
@FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
- public void setEnableAutoInstallDependencies(boolean enableAutoInstallDependencies) {
+ public void setAutoInstallDependenciesEnabled(boolean enableAutoInstallDependencies) {
isAutoInstallDependenciesEnabled = enableAutoInstallDependencies;
}
@@ -3800,7 +3664,6 @@ public class PackageInstaller {
pw.printHexPair("developmentInstallFlags", developmentInstallFlags);
pw.printPair("unarchiveId", unarchiveId);
pw.printPair("dexoptCompilerFilter", dexoptCompilerFilter);
- pw.printPair("forceVerification", forceVerification);
pw.printPair("isAutoInstallDependenciesEnabled", isAutoInstallDependenciesEnabled);
pw.println();
}
@@ -3848,7 +3711,6 @@ public class PackageInstaller {
dest.writeInt(developmentInstallFlags);
dest.writeInt(unarchiveId);
dest.writeString(dexoptCompilerFilter);
- dest.writeBoolean(forceVerification);
dest.writeBoolean(isAutoInstallDependenciesEnabled);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3152ff4564fe..d2b43b9bd2b4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -193,6 +193,42 @@ public abstract class PackageManager {
"android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES";
/**
+ * &lt;application&gt; level {@link android.content.pm.PackageManager.Property} tag
+ * specifying whether the app should be put into the "restricted" backup mode when it's started
+ * for backup and restore operations.
+ *
+ * <p> See <a
+ * href="https://developer.android.com/identity/data/autobackup#ImplementingBackupAgent"> for
+ * information about restricted mode</a>.
+ *
+ * <p> Starting with Android 16 apps may not be started in restricted mode based on this
+ * property.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * &lt;application&gt;
+ * &lt;property
+ * android:name="android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE"
+ * android:value="true|false"/&gt;
+ * &lt;/application&gt;
+ * </pre>
+ *
+ * <p>If this property is set, the operating system will respect it for now (see Note below).
+ * If it's not set, the behavior depends on the SDK level that the app is targeting. For apps
+ * targeting SDK level {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or lower, the
+ * property defaults to {@code true}. For apps targeting SDK level
+ * {@link android.os.Build.VERSION_CODES#BAKLAVA} or higher, the operating system will make a
+ * decision dynamically.
+ *
+ * <p>Note: It's not recommended to set this property to {@code true} unless absolutely
+ * necessary. In a future Android version, this property may be deprecated in favor of removing
+ * restricted mode completely.
+ */
+ @FlaggedApi(com.android.server.backup.Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public static final String PROPERTY_USE_RESTRICTED_BACKUP_MODE =
+ "android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE";
+
+ /**
* Application level property that an app can specify to opt-out from having private data
* directories both on the internal and external storages.
*
@@ -292,6 +328,10 @@ public abstract class PackageManager {
* <p>
* The value of a property will only have a single type, as defined by
* the property itself.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * In android version {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and earlier,
+ * the {@code equals} and {@code hashCode} methods for this class may not function as expected.
*/
public static final class Property implements Parcelable {
private static final int TYPE_BOOLEAN = 1;
@@ -523,6 +563,40 @@ public abstract class PackageManager {
return new Property[size];
}
};
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Property)) {
+ return false;
+ }
+ final Property property = (Property) obj;
+ return mType == property.mType &&
+ Objects.equals(mName, property.mName) &&
+ Objects.equals(mClassName, property.mClassName) &&
+ Objects.equals(mPackageName, property.mPackageName) &&
+ (mType == TYPE_BOOLEAN ? mBooleanValue == property.mBooleanValue :
+ mType == TYPE_FLOAT ? Float.compare(mFloatValue, property.mFloatValue) == 0 :
+ mType == TYPE_INTEGER ? mIntegerValue == property.mIntegerValue :
+ mType == TYPE_RESOURCE ? mIntegerValue == property.mIntegerValue :
+ mStringValue.equals(property.mStringValue));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mName, mType, mClassName, mPackageName);
+ if (mType == TYPE_BOOLEAN) {
+ result = 31 * result + (mBooleanValue ? 1 : 0);
+ } else if (mType == TYPE_FLOAT) {
+ result = 31 * result + Float.floatToIntBits(mFloatValue);
+ } else if (mType == TYPE_INTEGER) {
+ result = 31 * result + mIntegerValue;
+ } else if (mType == TYPE_RESOURCE) {
+ result = 31 * result + mIntegerValue;
+ } else if (mType == TYPE_STRING) {
+ result = 31 * result + mStringValue.hashCode();
+ }
+ return result;
+ }
}
/**
@@ -3126,6 +3200,16 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device is capable of ranging with
+ * other devices using channel sounding via Bluetooth Low Energy radio.
+ */
+ @FlaggedApi(com.android.ranging.flags.Flags.FLAG_RANGING_CS_ENABLED)
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING =
+ "android.hardware.bluetooth_le.channel_sounding";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device has a camera facing away
* from the screen.
*/
@@ -5098,25 +5182,6 @@ public abstract class PackageManager {
"android.content.pm.action.REQUEST_PERMISSIONS_FOR_OTHER";
/**
- * Used by the system to query a {@link android.content.pm.verify.pkg.VerifierService} provider,
- * which registers itself via an intent-filter handling this action.
- *
- * <p class="note">Only the system can bind to such a verifier service. This is protected by the
- * {@link android.Manifest.permission#BIND_VERIFICATION_AGENT} permission. The verifier service
- * app should protect the service by adding this permission in the service declaration in its
- * manifest.
- * <p>
- * A verifier service must be a privileged app and hold the
- * {@link android.Manifest.permission#VERIFICATION_AGENT} permission.
- *
- * @hide
- */
- @SystemApi
- @FlaggedApi(android.content.pm.Flags.FLAG_VERIFICATION_SERVICE)
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String ACTION_VERIFY_PACKAGE = "android.content.pm.action.VERIFY_PACKAGE";
-
- /**
* The names of the requested permissions.
* <p>
* <strong>Type:</strong> String[]
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 4285b0a2b91a..8243d88e6260 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -20,6 +20,7 @@ import android.Manifest;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
+import android.health.connect.HealthPermissions;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Printer;
@@ -361,8 +362,10 @@ public class ServiceInfo extends ComponentInfo
* {@link android.Manifest.permission#FOREGROUND_SERVICE_HEALTH} and one of the following
* permissions:
* {@link android.Manifest.permission#ACTIVITY_RECOGNITION},
- * {@link android.Manifest.permission#BODY_SENSORS},
* {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}.
+ * {@link android.health.connect.HealthPermissions#READ_HEART_RATE},
+ * {@link android.health.connect.HealthPermissions#READ_SKIN_TEMPERATURE},
+ * {@link android.health.connect.HealthPermissions#READ_OXYGEN_SATURATION},
*/
@RequiresPermission(
allOf = {
@@ -370,10 +373,13 @@ public class ServiceInfo extends ComponentInfo
},
anyOf = {
Manifest.permission.ACTIVITY_RECOGNITION,
- Manifest.permission.BODY_SENSORS,
Manifest.permission.HIGH_SAMPLING_RATE_SENSORS,
+ HealthPermissions.READ_HEART_RATE,
+ HealthPermissions.READ_SKIN_TEMPERATURE,
+ HealthPermissions.READ_OXYGEN_SATURATION,
}
)
+ @FlaggedApi(android.permission.flags.Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED)
public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 1 << 8;
/**
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index f7191e605fb8..5dfec9809f6e 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -105,6 +105,8 @@ public final class SharedLibraryInfo implements Parcelable {
private final List<VersionedPackage> mOptionalDependentPackages;
private List<SharedLibraryInfo> mDependencies;
+ private final List<String> mCertDigests;
+
/**
* Creates a new instance.
*
@@ -134,6 +136,7 @@ public final class SharedLibraryInfo implements Parcelable {
mDependencies = dependencies;
mIsNative = isNative;
mOptionalDependentPackages = null;
+ mCertDigests = null;
}
/**
@@ -165,6 +168,7 @@ public final class SharedLibraryInfo implements Parcelable {
mDeclaringPackage = declaringPackage;
mDependencies = dependencies;
mIsNative = isNative;
+ mCertDigests = null;
var allDependents = allDependentPackages.first;
var usesLibOptional = allDependentPackages.second;
@@ -206,6 +210,7 @@ public final class SharedLibraryInfo implements Parcelable {
mIsNative = parcel.readBoolean();
mOptionalDependentPackages = parcel.readParcelableList(new ArrayList<>(),
VersionedPackage.class.getClassLoader(), VersionedPackage.class);
+ mCertDigests = parcel.createStringArrayList();
}
/**
@@ -214,6 +219,29 @@ public final class SharedLibraryInfo implements Parcelable {
* @param versionMajor
*/
public SharedLibraryInfo(String name, long versionMajor, int type) {
+ //TODO: change to this(name, versionMajor, type, /* certDigest= */null); after flag removal
+ mPath = null;
+ mPackageName = null;
+ mName = name;
+ mVersion = versionMajor;
+ mType = type;
+ mDeclaringPackage = null;
+ mDependentPackages = null;
+ mDependencies = null;
+ mIsNative = false;
+ mOptionalDependentPackages = null;
+ mCertDigests = null;
+ }
+
+ /**
+ * @hide
+ * @param name The lib name.
+ * @param versionMajor The lib major version.
+ * @param type The type of shared library.
+ * @param certDigests The list of certificate digests for this shared library.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+ public SharedLibraryInfo(String name, long versionMajor, int type, List<String> certDigests) {
mPath = null;
mPackageName = null;
mName = name;
@@ -224,6 +252,7 @@ public final class SharedLibraryInfo implements Parcelable {
mDependencies = null;
mIsNative = false;
mOptionalDependentPackages = null;
+ mCertDigests = certDigests;
}
/**
@@ -433,6 +462,19 @@ public final class SharedLibraryInfo implements Parcelable {
return mOptionalDependentPackages;
}
+ /**
+ * Gets the list of certificate digests for the shared library.
+ *
+ * @return The list of certificate digests
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+ public @NonNull List<String> getCertDigests() {
+ if (mCertDigests == null) {
+ return Collections.emptyList();
+ }
+ return mCertDigests;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -463,6 +505,7 @@ public final class SharedLibraryInfo implements Parcelable {
parcel.writeTypedList(mDependencies);
parcel.writeBoolean(mIsNative);
parcel.writeParcelableList(mOptionalDependentPackages, flags);
+ parcel.writeStringList(mCertDigests);
}
private static String typeToString(int type) {
diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl
new file mode 100644
index 000000000000..06fcabcf55e9
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (C) 2024 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.content.pm.dependencyinstaller;
+
+parcelable DependencyInstallerCallback; \ No newline at end of file
diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java
new file mode 100644
index 000000000000..ba089f7fd33e
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (C) 2024 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.content.pm.dependencyinstaller;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.pm.Flags;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+/**
+ * Callbacks for {@link DependencyInstallerService}. The implementation of
+ * DependencyInstallerService uses this interface to indicate completion of the session creation
+ * request given by the system server.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+public final class DependencyInstallerCallback implements Parcelable {
+ private final IBinder mBinder;
+ private final IDependencyInstallerCallback mCallback;
+
+ /** @hide */
+ public DependencyInstallerCallback(IBinder binder) {
+ mBinder = binder;
+ mCallback = IDependencyInstallerCallback.Stub.asInterface(binder);
+ }
+
+ private DependencyInstallerCallback(Parcel in) {
+ mBinder = in.readStrongBinder();
+ mCallback = IDependencyInstallerCallback.Stub.asInterface(mBinder);
+ }
+
+ /**
+ * Callback to indicate that all the requested dependencies have been resolved and their
+ * sessions created. See {@link DependencyInstallerService#onDependenciesRequired}.
+ *
+ * @param sessionIds the install session IDs for all requested dependencies
+ */
+ public void onAllDependenciesResolved(@NonNull int[] sessionIds) {
+ try {
+ mCallback.onAllDependenciesResolved(sessionIds);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Callback to indicate that at least one of the required dependencies could not be resolved
+ * and any associated sessions have been abandoned.
+ */
+ public void onFailureToResolveAllDependencies() {
+ try {
+ mCallback.onFailureToResolveAllDependencies();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeStrongBinder(mBinder);
+ }
+
+ public static final @NonNull Creator<DependencyInstallerCallback> CREATOR =
+ new Creator<>() {
+ @Override
+ public DependencyInstallerCallback createFromParcel(Parcel in) {
+ return new DependencyInstallerCallback(in);
+ }
+
+ @Override
+ public DependencyInstallerCallback[] newArray(int size) {
+ return new DependencyInstallerCallback[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java
new file mode 100644
index 000000000000..11864150e072
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2024 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.content.pm.dependencyinstaller;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.Flags;
+import android.content.pm.SharedLibraryInfo;
+import android.os.IBinder;
+
+import java.util.List;
+
+/**
+ * Service that needs to be implemented by the holder of the DependencyInstaller role. This service
+ * will be invoked by the system during application installations if it depends on
+ * {@link android.content.pm.SharedLibraryInfo#TYPE_STATIC} or
+ * {@link android.content.pm.SharedLibraryInfo#TYPE_SDK_PACKAGE} and those dependencies aren't
+ * already installed.
+ * <p>
+ * Below is an example manifest registration for a {@code DependencyInstallerService}.
+ * <pre>
+ * {@code
+ * <service android:name=".ExampleDependencyInstallerService"
+ * android:permission="android.permission.BIND_DEPENDENCY_INSTALLER" >
+ * ...
+ * <intent-filter>
+ * <action android:name="android.content.pm.action.INSTALL_DEPENDENCY" />
+ * </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+public abstract class DependencyInstallerService extends Service {
+
+ private IDependencyInstallerService mBinder;
+
+ @Override
+ public final @NonNull IBinder onBind(@Nullable Intent intent) {
+ if (mBinder == null) {
+ mBinder = new IDependencyInstallerService.Stub() {
+ @Override
+ public void onDependenciesRequired(List<SharedLibraryInfo> neededLibraries,
+ DependencyInstallerCallback callback) {
+ DependencyInstallerService.this.onDependenciesRequired(neededLibraries,
+ callback);
+ }
+ };
+ }
+ return mBinder.asBinder();
+ }
+
+ /**
+ * Notify the holder of the DependencyInstaller role of the missing dependencies required for
+ * the completion of an active install session.
+ *
+ * @param neededLibraries the list of shared library dependencies needed to be obtained and
+ * installed.
+ */
+ public abstract void onDependenciesRequired(@NonNull List<SharedLibraryInfo> neededLibraries,
+ @NonNull DependencyInstallerCallback callback);
+}
diff --git a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl
new file mode 100644
index 000000000000..92d1d9e118e6
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2024 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.content.pm.dependencyinstaller;
+
+import java.util.List;
+
+/**
+* Callbacks for Dependency Installer. The app side invokes on this interface to indicate
+* completion of the async dependency install request given by the system server.
+*
+* {@hide}
+*/
+oneway interface IDependencyInstallerCallback {
+ /**
+ * Callback to indicate that all the requested dependencies have been resolved and have been
+ * committed for installation. See {@link DependencyInstallerService#onDependenciesRequired}.
+ *
+ * @param sessionIds the install session IDs for all requested dependencies
+ */
+ void onAllDependenciesResolved(in int[] sessionIds);
+
+ /**
+ * Callback to indicate that at least one of the required dependencies could not be resolved
+ * and any associated sessions have been abandoned.
+ */
+ void onFailureToResolveAllDependencies();
+} \ No newline at end of file
diff --git a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl
new file mode 100644
index 000000000000..94f5bf45ca9c
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2024 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.content.pm.dependencyinstaller;
+
+import android.content.pm.dependencyinstaller.DependencyInstallerCallback;
+import android.content.pm.SharedLibraryInfo;
+import java.util.List;
+
+/**
+* Interface used to communicate with the application code that holds the Dependency Installer role.
+* {@hide}
+*/
+oneway interface IDependencyInstallerService {
+ /**
+ * Notify dependency installer of the required dependencies to complete the current install
+ * session.
+ *
+ * @param neededLibraries the list of shared library dependencies needed to be obtained and
+ * installed.
+ */
+ void onDependenciesRequired(in List<SharedLibraryInfo> neededLibraries,
+ in DependencyInstallerCallback callback);
+ } \ No newline at end of file
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 9ba5a352358b..fbe581c5d524 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -312,14 +312,6 @@ flag {
}
flag {
- name: "verification_service"
- namespace: "package_manager_service"
- description: "Feature flag to enable the new verification service."
- bug: "360129103"
- is_fixed_read_only: true
-}
-
-flag {
name: "sdk_dependency_installer"
is_exported: true
namespace: "package_manager_service"
@@ -364,5 +356,15 @@ flag {
name: "support_minor_versions_in_minsdkversion"
namespace: "package_manager_service"
description: "Block app installations that specify an incompatible minor SDK version"
- bug: "377474232"
+ bug: "377302905"
}
+
+flag {
+ name: "app_compat_option_16kb"
+ is_exported: true
+ namespace: "devoptions_settings"
+ description: "Feature flag to enable page size app compat mode from manifest, package manager and settings level."
+ bug: "371049373"
+ is_fixed_read_only: true
+}
+
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 3d89ce12dec4..813208d7ff38 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -330,6 +330,17 @@ flag {
is_fixed_read_only: true
}
+flag {
+ name: "cache_user_info_read_only"
+ namespace: "multiuser"
+ description: "Cache UserInfo to avoid unnecessary binder calls"
+ bug: "161915546"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+}
+
# This flag guards the private space feature and all its implementations excluding the APIs. APIs are guarded by android.os.Flags.allow_private_profile.
flag {
name: "enable_private_space_features"
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index c83cf9601cd7..1d8209da6559 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -142,6 +142,11 @@ public class ApkLite {
private final boolean mIsSdkLibrary;
/**
+ * Indicates if this apk is a static library.
+ */
+ private final boolean mIsStaticLibrary;
+
+ /**
* List of SDK names used by this apk.
*/
private final @NonNull List<String> mUsesSdkLibraries;
@@ -191,7 +196,7 @@ public class ApkLite {
Set<String> requiredSplitTypes, Set<String> splitTypes,
boolean hasDeviceAdminReceiver, boolean isSdkLibrary,
List<String> usesSdkLibraries, long[] usesSdkLibrariesVersionsMajor,
- String[][] usesSdkLibrariesCertDigests,
+ String[][] usesSdkLibrariesCertDigests, boolean isStaticLibrary,
List<String> usesStaticLibraries, long[] usesStaticLibrariesVersionsMajor,
String[][] usesStaticLibrariesCertDigests,
boolean updatableSystem,
@@ -229,6 +234,7 @@ public class ApkLite {
mRollbackDataPolicy = rollbackDataPolicy;
mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
mIsSdkLibrary = isSdkLibrary;
+ mIsStaticLibrary = isStaticLibrary;
mUsesSdkLibraries = usesSdkLibraries;
mUsesSdkLibrariesVersionsMajor = usesSdkLibrariesVersionsMajor;
mUsesSdkLibrariesCertDigests = usesSdkLibrariesCertDigests;
@@ -275,6 +281,7 @@ public class ApkLite {
mRollbackDataPolicy = 0;
mHasDeviceAdminReceiver = false;
mIsSdkLibrary = false;
+ mIsStaticLibrary = false;
mUsesSdkLibraries = Collections.emptyList();
mUsesSdkLibrariesVersionsMajor = null;
mUsesSdkLibrariesCertDigests = null;
@@ -594,6 +601,14 @@ public class ApkLite {
}
/**
+ * Indicates if this apk is a static library.
+ */
+ @DataClass.Generated.Member
+ public boolean isIsStaticLibrary() {
+ return mIsStaticLibrary;
+ }
+
+ /**
* List of SDK names used by this apk.
*/
@DataClass.Generated.Member
@@ -662,10 +677,10 @@ public class ApkLite {
}
@DataClass.Generated(
- time = 1730202160705L,
+ time = 1731589363302L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final boolean mUpdatableSystem\nprivate final @android.annotation.Nullable java.lang.String mEmergencyInstaller\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final boolean mIsStaticLibrary\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final boolean mUpdatableSystem\nprivate final @android.annotation.Nullable java.lang.String mEmergencyInstaller\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index e9e8578af787..18a45d8d442e 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -44,6 +44,7 @@ import android.util.Slog;
import com.android.internal.pm.pkg.component.flags.Flags;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
import libcore.util.HexEncoding;
@@ -465,6 +466,7 @@ public class ApkLiteParseUtils {
boolean hasDeviceAdminReceiver = false;
boolean isSdkLibrary = false;
+ boolean isStaticLibrary = false;
List<String> usesSdkLibraries = new ArrayList<>();
long[] usesSdkLibrariesVersionsMajor = new long[0];
String[][] usesSdkLibrariesCertDigests = new String[0][0];
@@ -537,10 +539,18 @@ public class ApkLiteParseUtils {
hasBindDeviceAdminPermission);
break;
case TAG_USES_SDK_LIBRARY:
+ if (!android.content.pm.Flags.sdkDependencyInstaller()) {
+ break;
+ }
String usesSdkLibName = parser.getAttributeValue(
ANDROID_RES_NAMESPACE, "name");
- long usesSdkLibVersionMajor = parser.getAttributeIntValue(
- ANDROID_RES_NAMESPACE, "versionMajor", -1);
+ // TODO(b/379219371): Due to a bug in bundletool, some apps can use
+ // versionMajor as string. Until it is resolved, we are adding a
+ // workaround here.
+ String usesSdkLibVersionMajorString = parser.getAttributeValue(
+ ANDROID_RES_NAMESPACE, "versionMajor");
+ long usesSdkLibVersionMajor = XmlUtils.convertValueToInt(
+ usesSdkLibVersionMajorString, -1);
String usesSdkCertDigest = parser.getAttributeValue(
ANDROID_RES_NAMESPACE, "certDigest");
@@ -653,6 +663,7 @@ public class ApkLiteParseUtils {
SharedLibraryInfo.TYPE_SDK_PACKAGE));
break;
case TAG_STATIC_LIBRARY:
+ isStaticLibrary = true;
// Mirrors ParsingPackageUtils#parseStaticLibrary until lite and full
// parsing are combined
String staticLibName = parser.getAttributeValue(
@@ -806,7 +817,7 @@ public class ApkLiteParseUtils {
requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second,
hasDeviceAdminReceiver, isSdkLibrary, usesSdkLibraries,
- usesSdkLibrariesVersionsMajor, usesSdkLibrariesCertDigests,
+ usesSdkLibrariesVersionsMajor, usesSdkLibrariesCertDigests, isStaticLibrary,
usesStaticLibraries, usesStaticLibrariesVersions,
usesStaticLibrariesCertDigests, updatableSystem, emergencyInstaller,
declaredLibraries));
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 76b25fed2ac2..0e11eecfc7ec 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -114,6 +114,10 @@ public class PackageLite {
* Indicates if this package is a sdk.
*/
private final boolean mIsSdkLibrary;
+ /**
+ * Indicates if this package is a static library.
+ */
+ private final boolean mIsStaticLibrary;
private final @NonNull List<String> mUsesSdkLibraries;
@@ -164,6 +168,7 @@ public class PackageLite {
mUsesSdkLibraries = baseApk.getUsesSdkLibraries();
mUsesSdkLibrariesVersionsMajor = baseApk.getUsesSdkLibrariesVersionsMajor();
mUsesSdkLibrariesCertDigests = baseApk.getUsesSdkLibrariesCertDigests();
+ mIsStaticLibrary = baseApk.isIsStaticLibrary();
mUsesStaticLibraries = baseApk.getUsesStaticLibraries();
mUsesStaticLibrariesVersions = baseApk.getUsesStaticLibrariesVersions();
mUsesStaticLibrariesCertDigests = baseApk.getUsesStaticLibrariesCertDigests();
@@ -455,6 +460,14 @@ public class PackageLite {
return mIsSdkLibrary;
}
+ /**
+ * Indicates if this package is a static library.
+ */
+ @DataClass.Generated.Member
+ public boolean isIsStaticLibrary() {
+ return mIsStaticLibrary;
+ }
+
@DataClass.Generated.Member
public @NonNull List<String> getUsesSdkLibraries() {
return mUsesSdkLibraries;
@@ -499,10 +512,10 @@ public class PackageLite {
}
@DataClass.Generated(
- time = 1730203707341L,
+ time = 1731591578587L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\nprivate final boolean mIsStaticLibrary\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl b/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl
deleted file mode 100644
index 2ab745205193..000000000000
--- a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2024 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.content.pm.verify.pkg;
-
-import android.content.pm.verify.pkg.VerificationStatus;
-import android.os.PersistableBundle;
-
-/**
- * Non-oneway interface that allows the verifier to communicate with the system.
- * @hide
- */
-interface IVerificationSessionInterface {
- long getTimeoutTime(int verificationId);
- long extendTimeRemaining(int verificationId, long additionalMs);
- boolean setVerificationPolicy(int verificationId, int policy);
- void reportVerificationIncomplete(int verificationId, int reason);
- void reportVerificationComplete(int verificationId, in VerificationStatus status, in @nullable PersistableBundle extensionResponse);
-} \ No newline at end of file
diff --git a/core/java/android/content/pm/verify/pkg/VerificationSession.java b/core/java/android/content/pm/verify/pkg/VerificationSession.java
deleted file mode 100644
index 97f78e0978fa..000000000000
--- a/core/java/android/content/pm/verify/pkg/VerificationSession.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) 2024 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.content.pm.verify.pkg;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.content.pm.Flags;
-import android.content.pm.PackageInstaller;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningInfo;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This class is used by the system to describe the details about a verification request sent to the
- * verification agent, aka the verifier. It includes the interfaces for the verifier to communicate
- * back to the system.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
-@SystemApi
-public final class VerificationSession implements Parcelable {
- /**
- * The verification cannot be completed because of unknown reasons.
- */
- public static final int VERIFICATION_INCOMPLETE_UNKNOWN = 0;
- /**
- * The verification cannot be completed because the network is unavailable.
- */
- public static final int VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE = 1;
-
- /**
- * @hide
- */
- @IntDef(prefix = {"VERIFICATION_INCOMPLETE_"}, value = {
- VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE,
- VERIFICATION_INCOMPLETE_UNKNOWN,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface VerificationIncompleteReason {
- }
-
- private final int mId;
- private final int mInstallSessionId;
- @NonNull
- private final String mPackageName;
- @NonNull
- private final Uri mStagedPackageUri;
- @NonNull
- private final SigningInfo mSigningInfo;
- @NonNull
- private final List<SharedLibraryInfo> mDeclaredLibraries;
- @NonNull
- private final PersistableBundle mExtensionParams;
- @NonNull
- private final IVerificationSessionInterface mSession;
- /**
- * The current policy that is active for the session. It might not be
- * the same as the original policy that was initially assigned for this verification session,
- * because the active policy can be overridden by {@link #setVerificationPolicy(int)}.
- * <p>To improve the latency, store the original policy value and any changes made to it,
- * so that {@link #getVerificationPolicy()} does not need to make a binder call to retrieve the
- * currently active policy.</p>
- */
- private volatile @PackageInstaller.VerificationPolicy int mVerificationPolicy;
-
- /**
- * Constructor used by the system to describe the details of a verification session.
- * @hide
- */
- public VerificationSession(int id, int installSessionId, @NonNull String packageName,
- @NonNull Uri stagedPackageUri, @NonNull SigningInfo signingInfo,
- @NonNull List<SharedLibraryInfo> declaredLibraries,
- @NonNull PersistableBundle extensionParams,
- @PackageInstaller.VerificationPolicy int defaultPolicy,
- @NonNull IVerificationSessionInterface session) {
- mId = id;
- mInstallSessionId = installSessionId;
- mPackageName = packageName;
- mStagedPackageUri = stagedPackageUri;
- mSigningInfo = signingInfo;
- mDeclaredLibraries = declaredLibraries;
- mExtensionParams = extensionParams;
- mVerificationPolicy = defaultPolicy;
- mSession = session;
- }
-
- /**
- * A unique identifier tied to this specific verification session.
- */
- public int getId() {
- return mId;
- }
-
- /**
- * The package name of the app that is to be verified.
- */
- public @NonNull String getPackageName() {
- return mPackageName;
- }
-
- /**
- * The id of the installation session associated with the verification.
- */
- public int getInstallSessionId() {
- return mInstallSessionId;
- }
-
- /**
- * The Uri of the path where the package's code files are located.
- */
- public @NonNull Uri getStagedPackageUri() {
- return mStagedPackageUri;
- }
-
- /**
- * Signing info of the package to be verified.
- */
- public @NonNull SigningInfo getSigningInfo() {
- return mSigningInfo;
- }
-
- /**
- * Returns a mapping of any shared libraries declared in the manifest
- * to the {@link SharedLibraryInfo.Type} that is declared. This will be an empty
- * map if no shared libraries are declared by the package.
- */
- @NonNull
- public List<SharedLibraryInfo> getDeclaredLibraries() {
- return Collections.unmodifiableList(mDeclaredLibraries);
- }
-
- /**
- * Returns any extension params associated with the verification request.
- */
- @NonNull
- public PersistableBundle getExtensionParams() {
- return mExtensionParams;
- }
-
- /**
- * Get the value of Clock.elapsedRealtime() at which time this verification
- * will timeout as incomplete if no other verification response is provided.
- * @throws SecurityException if the caller is not the current verifier bound by the system.
- */
- public long getTimeoutTime() {
- try {
- return mSession.getTimeoutTime(mId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Return the current policy that is active for this session.
- * <p>If the policy for this session has been changed by {@link #setVerificationPolicy},
- * the return value of this method is the current policy that is active for this session.
- * Otherwise, the return value is the same as the initial policy that was assigned to the
- * session when it was first created.</p>
- */
- public @PackageInstaller.VerificationPolicy int getVerificationPolicy() {
- return mVerificationPolicy;
- }
-
- /**
- * Override the verification policy for this session.
- * @return True if the override was successful, False otherwise.
- * @throws SecurityException if the caller is not the current verifier bound by the system.
- */
- public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) {
- if (mVerificationPolicy == policy) {
- // No effective policy change
- return true;
- }
- try {
- if (mSession.setVerificationPolicy(mId, policy)) {
- mVerificationPolicy = policy;
- return true;
- } else {
- return false;
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Extend the timeout for this session by the provided additionalMs to
- * fetch relevant information over the network or wait for the network.
- * This may be called multiple times. If the request would bypass any max
- * duration by the system, the method will return a lower value than the
- * requested amount that indicates how much the time was extended.
- * @throws SecurityException if the caller is not the current verifier bound by the system.
- */
- public long extendTimeRemaining(long additionalMs) {
- try {
- return mSession.extendTimeRemaining(mId, additionalMs);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Report to the system that verification could not be completed along
- * with an approximate reason to pass on to the installer.]
- * @throws SecurityException if the caller is not the current verifier bound by the system.
- */
- public void reportVerificationIncomplete(@VerificationIncompleteReason int reason) {
- try {
- mSession.reportVerificationIncomplete(mId, reason);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Report to the system that the verification has completed and the
- * install process may act on that status to either block in the case
- * of failure or continue to process the install in the case of success.
- * @throws SecurityException if the caller is not the current verifier bound by the system.
- */
- public void reportVerificationComplete(@NonNull VerificationStatus status) {
- try {
- mSession.reportVerificationComplete(mId, status, /* extensionResponse= */ null);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Same as {@link #reportVerificationComplete(VerificationStatus)}, but also provide
- * a result to the extension params provided in the request, which will be passed to the
- * installer in the installation result.
- * @throws SecurityException if the caller is not the current verifier bound by the system.
- */
- public void reportVerificationComplete(@NonNull VerificationStatus status,
- @NonNull PersistableBundle extensionResponse) {
- try {
- mSession.reportVerificationComplete(mId, status, extensionResponse);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- private VerificationSession(@NonNull Parcel in) {
- mId = in.readInt();
- mInstallSessionId = in.readInt();
- mPackageName = in.readString8();
- mStagedPackageUri = Uri.CREATOR.createFromParcel(in);
- mSigningInfo = SigningInfo.CREATOR.createFromParcel(in);
- mDeclaredLibraries = in.createTypedArrayList(SharedLibraryInfo.CREATOR);
- mExtensionParams = in.readPersistableBundle(getClass().getClassLoader());
- mVerificationPolicy = in.readInt();
- mSession = IVerificationSessionInterface.Stub.asInterface(in.readStrongBinder());
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mId);
- dest.writeInt(mInstallSessionId);
- dest.writeString8(mPackageName);
- Uri.writeToParcel(dest, mStagedPackageUri);
- mSigningInfo.writeToParcel(dest, flags);
- dest.writeTypedList(mDeclaredLibraries);
- dest.writePersistableBundle(mExtensionParams);
- dest.writeInt(mVerificationPolicy);
- dest.writeStrongBinder(mSession.asBinder());
- }
-
- @NonNull
- public static final Creator<VerificationSession> CREATOR = new Creator<>() {
- @Override
- public VerificationSession createFromParcel(@NonNull Parcel in) {
- return new VerificationSession(in);
- }
-
- @Override
- public VerificationSession[] newArray(int size) {
- return new VerificationSession[size];
- }
- };
-}
diff --git a/core/java/android/content/pm/verify/pkg/VerificationStatus.java b/core/java/android/content/pm/verify/pkg/VerificationStatus.java
deleted file mode 100644
index 4d0379d79773..000000000000
--- a/core/java/android/content/pm/verify/pkg/VerificationStatus.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2024 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.content.pm.verify.pkg;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.content.pm.Flags;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * This class is used by the verifier to describe the status of the verification request, whether
- * it's successful or it has failed along with any relevant details.
- * @hide
- */
-@SystemApi
-@FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
-public final class VerificationStatus implements Parcelable {
- /**
- * The ASL status has not been determined. This happens in situations where the verification
- * service is not monitoring ASLs, and means the ASL data in the app is not necessarily bad but
- * can't be trusted.
- */
- public static final int VERIFIER_STATUS_ASL_UNDEFINED = 0;
-
- /**
- * The app's ASL data is considered to be in a good state.
- */
- public static final int VERIFIER_STATUS_ASL_GOOD = 1;
-
- /**
- * There is something bad in the app's ASL data; the user should be warned about this when shown
- * the ASL data and/or appropriate decisions made about the use of this data by the platform.
- */
- public static final int VERIFIER_STATUS_ASL_BAD = 2;
-
- /** @hide */
- @IntDef(prefix = {"VERIFIER_STATUS_ASL_"}, value = {
- VERIFIER_STATUS_ASL_UNDEFINED,
- VERIFIER_STATUS_ASL_GOOD,
- VERIFIER_STATUS_ASL_BAD,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface VerifierStatusAsl {}
-
- private boolean mIsVerified;
- private @VerifierStatusAsl int mAslStatus;
- @NonNull
- private String mFailuresMessage = "";
-
- private VerificationStatus() {}
-
- /**
- * @return whether the status is set to verified or not.
- */
- public boolean isVerified() {
- return mIsVerified;
- }
-
- /**
- * @return the failure message associated with the failure status.
- */
- @NonNull
- public String getFailureMessage() {
- return mFailuresMessage;
- }
-
- /**
- * @return the asl status.
- */
- public @VerifierStatusAsl int getAslStatus() {
- return mAslStatus;
- }
-
- /**
- * Builder to construct a {@link VerificationStatus} object.
- */
- public static final class Builder {
- final VerificationStatus mStatus = new VerificationStatus();
-
- /**
- * Set in the status whether the verification has succeeded or failed.
- */
- @NonNull
- public Builder setVerified(boolean verified) {
- mStatus.mIsVerified = verified;
- return this;
- }
-
- /**
- * Set a developer-facing failure message to include in the verification failure status.
- */
- @NonNull
- public Builder setFailureMessage(@NonNull String failureMessage) {
- mStatus.mFailuresMessage = failureMessage;
- return this;
- }
-
- /**
- * Set the ASL status, as defined in {@link VerifierStatusAsl}.
- */
- @NonNull
- public Builder setAslStatus(@VerifierStatusAsl int aslStatus) {
- mStatus.mAslStatus = aslStatus;
- return this;
- }
-
- /**
- * Build the status object.
- */
- @NonNull
- public VerificationStatus build() {
- return mStatus;
- }
- }
-
- private VerificationStatus(Parcel in) {
- mIsVerified = in.readBoolean();
- mAslStatus = in.readInt();
- mFailuresMessage = in.readString8();
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeBoolean(mIsVerified);
- dest.writeInt(mAslStatus);
- dest.writeString8(mFailuresMessage);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @NonNull
- public static final Creator<VerificationStatus> CREATOR = new Creator<>() {
- @Override
- public VerificationStatus createFromParcel(@NonNull Parcel in) {
- return new VerificationStatus(in);
- }
-
- @Override
- public VerificationStatus[] newArray(int size) {
- return new VerificationStatus[size];
- }
- };
-}
diff --git a/core/java/android/content/pm/verify/pkg/VerifierService.java b/core/java/android/content/pm/verify/pkg/VerifierService.java
deleted file mode 100644
index ccf211915326..000000000000
--- a/core/java/android/content/pm/verify/pkg/VerifierService.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2024 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.content.pm.verify.pkg;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.Flags;
-import android.content.pm.PackageManager;
-import android.os.IBinder;
-
-/**
- * A base service implementation for the verifier agent to implement.
- *
- * @hide
- */
-@SystemApi
-@FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
-public abstract class VerifierService extends Service {
- /**
- * Called when a package name is available for a pending verification,
- * giving the verifier opportunity to pre-fetch any relevant information
- * that may be needed should a verification for the package be required.
- */
- public abstract void onPackageNameAvailable(@NonNull String packageName);
-
- /**
- * Called when a package recently provided via {@link #onPackageNameAvailable}
- * is no longer expected to be installed. This is a hint that any pre-fetch or
- * cache created as a result of the previous call may be be cleared.
- * <p>This method will never be called after {@link #onVerificationRequired} is called for the
- * same package. Once a verification is officially requested by
- * {@link #onVerificationRequired}, it cannot be cancelled.
- * </p>
- */
- public abstract void onVerificationCancelled(@NonNull String packageName);
-
- /**
- * Called when an application needs to be verified. Details about the
- * verification and actions that can be taken on it will be encapsulated in
- * the provided {@link VerificationSession} parameter.
- */
- public abstract void onVerificationRequired(@NonNull VerificationSession session);
-
- /**
- * Called when a verification needs to be retried. This can be encountered
- * when a prior verification was marked incomplete and the user has indicated
- * that they've resolved the issue, or when a timeout is reached, but the
- * the system is attempting to retry. Details about the
- * verification and actions that can be taken on it will be encapsulated in
- * the provided {@link VerificationSession} parameter.
- */
- public abstract void onVerificationRetry(@NonNull VerificationSession session);
-
- /**
- * Called in the case that an active verification has failed. Any APIs called
- * on the {@link VerificationSession} instance associated with this {@code verificationId} will
- * throw an {@link IllegalStateException}.
- */
- public abstract void onVerificationTimeout(int verificationId);
-
- /**
- * Called when the verifier service is bound to the system.
- */
- public @Nullable IBinder onBind(@Nullable Intent intent) {
- if (intent == null || !PackageManager.ACTION_VERIFY_PACKAGE.equals(intent.getAction())) {
- return null;
- }
- return new IVerifierService.Stub() {
- @Override
- public void onPackageNameAvailable(@NonNull String packageName) {
- VerifierService.this.onPackageNameAvailable(packageName);
- }
-
- @Override
- public void onVerificationCancelled(@NonNull String packageName) {
- VerifierService.this.onVerificationCancelled(packageName);
- }
-
- @Override
- public void onVerificationRequired(@NonNull VerificationSession session) {
- VerifierService.this.onVerificationRequired(session);
- }
-
- @Override
- public void onVerificationRetry(@NonNull VerificationSession session) {
- VerifierService.this.onVerificationRetry(session);
- }
-
- @Override
- public void onVerificationTimeout(int verificationId) {
- VerifierService.this.onVerificationTimeout(verificationId);
- }
- };
- }
-}
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index 68b5d782bfbf..908999b64961 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -124,11 +124,13 @@ public final class ApkAssets {
@Nullable
@GuardedBy("this")
- private final StringBlock mStringBlock; // null or closed if mNativePtr = 0.
+ private StringBlock mStringBlock; // null or closed if mNativePtr = 0.
@PropertyFlags
private final int mFlags;
+ private final boolean mIsOverlay;
+
@Nullable
private final AssetsProvider mAssets;
@@ -302,40 +304,43 @@ public final class ApkAssets {
private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags,
@Nullable AssetsProvider assets) throws IOException {
+ this(format, flags, assets);
Objects.requireNonNull(path, "path");
- mFlags = flags;
mNativePtr = nativeLoad(format, path, flags, assets);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
- mAssets = assets;
}
private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd,
@NonNull String friendlyName, @PropertyFlags int flags, @Nullable AssetsProvider assets)
throws IOException {
+ this(format, flags, assets);
Objects.requireNonNull(fd, "fd");
Objects.requireNonNull(friendlyName, "friendlyName");
- mFlags = flags;
mNativePtr = nativeLoadFd(format, fd, friendlyName, flags, assets);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
- mAssets = assets;
}
private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd,
@NonNull String friendlyName, long offset, long length, @PropertyFlags int flags,
@Nullable AssetsProvider assets) throws IOException {
+ this(format, flags, assets);
Objects.requireNonNull(fd, "fd");
Objects.requireNonNull(friendlyName, "friendlyName");
- mFlags = flags;
mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags, assets);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
- mAssets = assets;
}
private ApkAssets(@PropertyFlags int flags, @Nullable AssetsProvider assets) {
- mFlags = flags;
+ this(FORMAT_APK, flags, assets);
mNativePtr = nativeLoadEmpty(flags, assets);
mStringBlock = null;
+ }
+
+ private ApkAssets(@FormatType int format, @PropertyFlags int flags,
+ @Nullable AssetsProvider assets) {
+ mFlags = flags;
mAssets = assets;
+ mIsOverlay = format == FORMAT_IDMAP;
}
@UnsupportedAppUsage
@@ -425,6 +430,18 @@ public final class ApkAssets {
}
}
+ public boolean isSystem() {
+ return (mFlags & PROPERTY_SYSTEM) != 0;
+ }
+
+ public boolean isSharedLib() {
+ return (mFlags & PROPERTY_DYNAMIC) != 0;
+ }
+
+ public boolean isOverlay() {
+ return mIsOverlay;
+ }
+
@Override
public String toString() {
return "ApkAssets{path=" + getDebugName() + "}";
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 6fd4d0141977..bbfae8117b16 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -75,7 +75,10 @@ public final class AssetManager implements AutoCloseable {
private static final String TAG = "AssetManager";
private static final boolean DEBUG_REFS = false;
- private static final String FRAMEWORK_APK_PATH = getFrameworkApkPath();
+ /**
+ * @hide
+ */
+ public static final String FRAMEWORK_APK_PATH = getFrameworkApkPath();
private static final String FRAMEWORK_APK_PATH_DEVICE = "/system/framework/framework-res.apk";
private static final String FRAMEWORK_APK_PATH_RAVENWOOD = "ravenwood-data/framework-res.apk";
@@ -973,9 +976,9 @@ public final class AssetManager implements AutoCloseable {
* Open an asset using ACCESS_STREAMING mode. This provides access to
* files that have been bundled with an application as assets -- that is,
* files placed in to the "assets" directory.
- *
+ *
* @param fileName The name of the asset to open. This name can be hierarchical.
- *
+ *
* @see #open(String, int)
* @see #list
*/
@@ -988,10 +991,10 @@ public final class AssetManager implements AutoCloseable {
* read its contents. This provides access to files that have been bundled
* with an application as assets -- that is, files placed in to the
* "assets" directory.
- *
+ *
* @param fileName The name of the asset to open. This name can be hierarchical.
* @param accessMode Desired access mode for retrieving the data.
- *
+ *
* @see #ACCESS_UNKNOWN
* @see #ACCESS_STREAMING
* @see #ACCESS_RANDOM
@@ -1037,14 +1040,14 @@ public final class AssetManager implements AutoCloseable {
/**
* Return a String array of all the assets at the given path.
- *
+ *
* @param path A relative path within the assets, i.e., "docs/home.html".
- *
+ *
* @return String[] Array of strings, one for each asset. These file
* names are relative to 'path'. You can open the file by
* concatenating 'path' and a name in the returned string (via
* File) and passing that to open().
- *
+ *
* @see #open
*/
public @Nullable String[] list(@NonNull String path) throws IOException {
@@ -1167,20 +1170,20 @@ public final class AssetManager implements AutoCloseable {
return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
}
-
+
/**
* Retrieve a parser for a compiled XML file.
- *
+ *
* @param fileName The name of the file to retrieve.
*/
public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName)
throws IOException {
return openXmlResourceParser(0, fileName);
}
-
+
/**
* Retrieve a parser for a compiled XML file.
- *
+ *
* @param cookie Identifier of the package to be opened.
* @param fileName The name of the file to retrieve.
*/
@@ -1200,7 +1203,7 @@ public final class AssetManager implements AutoCloseable {
/**
* Retrieve a non-asset as a compiled XML file. Not for use by applications.
- *
+ *
* @param fileName The name of the file to retrieve.
* @hide
*/
@@ -1211,7 +1214,7 @@ public final class AssetManager implements AutoCloseable {
/**
* Retrieve a non-asset as a compiled XML file. Not for use by
* applications.
- *
+ *
* @param cookie Identifier of the package to be opened.
* @param fileName Name of the asset to retrieve.
* @hide
@@ -1675,7 +1678,6 @@ public final class AssetManager implements AutoCloseable {
mRefStacks = new HashMap<>();
}
RuntimeException ex = new RuntimeException();
- ex.fillInStackTrace();
mRefStacks.put(id, ex);
}
mNumRefs++;
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index e6b93427f413..bcaceb24d767 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -203,9 +203,25 @@ public class ResourcesImpl {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
@Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) {
- mAssets = assets;
- mAppliedSharedLibsHash =
- ResourcesManager.getInstance().updateResourceImplWithRegisteredLibs(this);
+ // Don't reuse assets by default as we have no control over whether they're already
+ // inside some other ResourcesImpl.
+ this(assets, metrics, config, displayAdjustments, false);
+ }
+
+ public ResourcesImpl(@NonNull ResourcesImpl orig) {
+ // We know for sure that the other assets are in use, so can't reuse the object here.
+ this(orig.getAssets(), orig.getMetrics(), orig.getConfiguration(),
+ orig.getDisplayAdjustments(), false);
+ }
+
+ public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
+ @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments,
+ boolean reuseAssets) {
+ final var assetsAndHash =
+ ResourcesManager.getInstance().updateResourceImplAssetsWithRegisteredLibs(assets,
+ reuseAssets);
+ mAssets = assetsAndHash.first;
+ mAppliedSharedLibsHash = assetsAndHash.second;
mMetrics.setToDefaults();
mDisplayAdjustments = displayAdjustments;
mConfiguration.setToDefaults();
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index f23c193e2da0..6fc7d90a8237 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -105,3 +105,12 @@ flag {
# This flag is used to control aapt2 behavior.
is_fixed_read_only: true
}
+
+flag {
+ name: "resources_minor_version_support"
+ is_exported: true
+ namespace: "resource_manager"
+ description: "Feature flag for supporting minor version in Resources"
+ bug: "373535266"
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/content/res/loader/ResourcesProvider.java b/core/java/android/content/res/loader/ResourcesProvider.java
index b097bc0dcd8c..830b7e0fa2d0 100644
--- a/core/java/android/content/res/loader/ResourcesProvider.java
+++ b/core/java/android/content/res/loader/ResourcesProvider.java
@@ -90,8 +90,6 @@ public class ResourcesProvider implements AutoCloseable, Closeable {
throws IOException {
Objects.requireNonNull(overlayInfo);
Preconditions.checkArgument(overlayInfo.isFabricated(), "Not accepted overlay");
- Preconditions.checkStringNotEmpty(
- overlayInfo.getTargetOverlayableName(), "Without overlayable name");
final String overlayName =
OverlayManagerImpl.checkOverlayNameValid(overlayInfo.getOverlayName());
final String path =
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index d2435757756c..6c35d106bfb7 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -3,6 +3,16 @@ container: "system"
flag {
namespace: "credential_manager"
+ name: "ttl_fix_enabled"
+ description: "Enable fix for transaction too large issue"
+ bug: "371052524"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "credential_manager"
name: "settings_activity_enabled"
is_exported: true
description: "Enable the Credential Manager Settings Activity APIs"
diff --git a/core/java/android/hardware/DisplayLuts.java b/core/java/android/hardware/DisplayLuts.java
index b162ad6e2d15..0abb30f8c24d 100644
--- a/core/java/android/hardware/DisplayLuts.java
+++ b/core/java/android/hardware/DisplayLuts.java
@@ -16,116 +16,296 @@
package android.hardware;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.hardware.flags.Flags;
import android.util.IntArray;
import java.util.ArrayList;
-import java.util.List;
/**
- * @hide
+ * DisplayLuts provides the developers to apply Lookup Tables (Luts) to a
+ * {@link android.view.SurfaceControl}. Luts provides ways to control tonemapping
+ * for specific content.
+ *
+ * The general flow is as follows:
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/DisplayLuts.png" />
+ * <figcaption style="text-align: center;">DisplayLuts flow</figcaption>
+ * </p>
+ *
+ * @see LutProperties
*/
+@FlaggedApi(Flags.FLAG_LUTS_API)
public final class DisplayLuts {
+ private ArrayList<Entry> mEntries;
private IntArray mOffsets;
private int mTotalLength;
- private List<float[]> mLutBuffers;
- private IntArray mLutDimensions;
- private IntArray mLutSizes;
- private IntArray mLutSamplingKeys;
- private static final int LUT_LENGTH_LIMIT = 100000;
-
+ /**
+ * Create a {@link DisplayLuts} instance.
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public DisplayLuts() {
+ mEntries = new ArrayList<>();
mOffsets = new IntArray();
mTotalLength = 0;
-
- mLutBuffers = new ArrayList<>();
- mLutDimensions = new IntArray();
- mLutSizes = new IntArray();
- mLutSamplingKeys = new IntArray();
}
- /**
- * Add the lut to be applied.
- *
- * @param buffer
- * @param dimension either 1D or 3D
- * @param size
- * @param samplingKey
- */
- public void addLut(@NonNull float[] buffer, @LutProperties.Dimension int dimension,
- int size, @LutProperties.SamplingKey int samplingKey) {
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public static class Entry {
+ private float[] mBuffer;
+ private @LutProperties.Dimension int mDimension;
+ private int mSize;
+ private @LutProperties.SamplingKey int mSamplingKey;
+
+ private static final int LUT_LENGTH_LIMIT = 100000;
+
+ /**
+ * Create a Lut entry.
+ *
+ * <p>
+ * Noted that 1D Lut(s) are treated as gain curves.
+ * For 3D Lut(s), 3D Lut(s) are used for direct color manipulations.
+ * The values of 3D Lut(s) data should be normalized to the range {@code 0.0}
+ * to {@code 1.0}, inclusive. And 3D Lut(s) data is organized in the order of
+ * R, G, B channels.
+ *
+ * @param buffer The raw lut data
+ * @param dimension Either 1D or 3D
+ * @param samplingKey The sampling kay used for the Lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public Entry(@NonNull float[] buffer,
+ @LutProperties.Dimension int dimension,
+ @LutProperties.SamplingKey int samplingKey) {
+ if (buffer == null || buffer.length < 1) {
+ throw new IllegalArgumentException("The buffer cannot be empty!");
+ }
+
+ if (buffer.length >= LUT_LENGTH_LIMIT) {
+ throw new IllegalArgumentException("The lut length is too big to handle!");
+ }
+
+ if (dimension != LutProperties.ONE_DIMENSION
+ && dimension != LutProperties.THREE_DIMENSION) {
+ throw new IllegalArgumentException("The dimension should be either 1D or 3D!");
+ }
+
+ if (dimension == LutProperties.THREE_DIMENSION) {
+ if (buffer.length <= 3) {
+ throw new IllegalArgumentException(
+ "The 3d lut size of each dimension should be over 1!");
+ }
+ int lengthPerChannel = buffer.length;
+ if (lengthPerChannel % 3 != 0) {
+ throw new IllegalArgumentException(
+ "The lut buffer of 3dlut should have 3 channels!");
+ }
+ lengthPerChannel /= 3;
- int lutLength = 0;
- if (dimension == LutProperties.ONE_DIMENSION) {
- lutLength = size;
- } else if (dimension == LutProperties.THREE_DIMENSION) {
- lutLength = size * size * size;
- } else {
- clear();
- throw new IllegalArgumentException("The dimension is either 1D or 3D!");
+ double size = Math.cbrt(lengthPerChannel);
+ if (size == (int) size) {
+ mSize = (int) size;
+ } else {
+ throw new IllegalArgumentException(
+ "Cannot get the cube root of the 3d lut buffer!");
+ }
+ } else {
+ mSize = buffer.length;
+ }
+
+ mBuffer = buffer;
+ mDimension = dimension;
+ mSamplingKey = samplingKey;
}
- if (lutLength >= LUT_LENGTH_LIMIT) {
- clear();
- throw new IllegalArgumentException("The lut length is too big to handle!");
+ /**
+ * @return the dimension of the lut entry
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public int getDimension() {
+ return mDimension;
}
- mOffsets.add(mTotalLength);
- mTotalLength += lutLength;
+ /**
+ * @return the size of the lut for each dimension
+ * @hide
+ */
+ public int getSize() {
+ return mSize;
+ }
+
+ /**
+ * @return the lut raw data of the lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public @NonNull float[] getBuffer() {
+ return mBuffer;
+ }
+
+ /**
+ * @return the sampling key used by the lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public int getSamplingKey() {
+ return mSamplingKey;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{"
+ + "dimension=" + DisplayLuts.Entry.dimensionToString(getDimension())
+ + ", size(each dimension)=" + getSize()
+ + ", samplingKey=" + samplingKeyToString(getSamplingKey()) + "}";
+ }
+
+ private static String dimensionToString(int dimension) {
+ switch(dimension) {
+ case LutProperties.ONE_DIMENSION:
+ return "ONE_DIMENSION";
+ case LutProperties.THREE_DIMENSION:
+ return "THREE_DIMENSION";
+ default:
+ return "";
+ }
+ }
+
+ private static String samplingKeyToString(int key) {
+ switch(key) {
+ case LutProperties.SAMPLING_KEY_RGB:
+ return "SAMPLING_KEY_RGB";
+ case LutProperties.SAMPLING_KEY_MAX_RGB:
+ return "SAMPLING_KEY_MAX_RGB";
+ case LutProperties.SAMPLING_KEY_CIE_Y:
+ return "SAMPLING_KEY_CIE_Y";
+ default:
+ return "";
+ }
+ }
+ }
- mLutBuffers.add(buffer);
- mLutDimensions.add(dimension);
- mLutSizes.add(size);
- mLutSamplingKeys.add(samplingKey);
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("DisplayLuts{");
+ sb.append("\n");
+ for (DisplayLuts.Entry entry: mEntries) {
+ sb.append(entry.toString());
+ sb.append("\n");
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private void addEntry(Entry entry) {
+ mEntries.add(entry);
+ mOffsets.add(mTotalLength);
+ mTotalLength += entry.getBuffer().length;
}
private void clear() {
- mTotalLength = 0;
mOffsets.clear();
- mLutBuffers.clear();
- mLutDimensions.clear();
- mLutSamplingKeys.clear();
+ mTotalLength = 0;
+ mEntries.clear();
+ }
+
+ /**
+ * Set a Lut to be applied.
+ *
+ * <p>Use either this or {@link #set(Entry, Entry)}. The function will
+ * replace any previously set lut(s).</p>
+ *
+ * @param entry Either an 1D Lut or a 3D Lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public void set(@NonNull Entry entry) {
+ if (entry == null) {
+ throw new IllegalArgumentException("The entry is null!");
+ }
+ clear();
+ addEntry(entry);
+ }
+
+ /**
+ * Set Luts in order to be applied.
+ *
+ * <p> An 1D Lut and 3D Lut will be applied in order. Use either this or
+ * {@link #set(Entry)}. The function will replace any previously set lut(s)</p>
+ *
+ * @param first An 1D Lut
+ * @param second A 3D Lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public void set(@NonNull Entry first, @NonNull Entry second) {
+ if (first == null || second == null) {
+ throw new IllegalArgumentException("The entry is null!");
+ }
+ if (first.getDimension() != LutProperties.ONE_DIMENSION
+ || second.getDimension() != LutProperties.THREE_DIMENSION) {
+ throw new IllegalArgumentException("The entries should be 1D and 3D in order!");
+ }
+ clear();
+ addEntry(first);
+ addEntry(second);
}
/**
- * @return the array of Lut buffers
+ * @hide
+ */
+ public boolean valid() {
+ return mEntries.size() > 0;
+ }
+
+ /**
+ * @hide
*/
public float[] getLutBuffers() {
float[] buffer = new float[mTotalLength];
- for (int i = 0; i < mLutBuffers.size(); i++) {
- float[] lutBuffer = mLutBuffers.get(i);
+ for (int i = 0; i < mEntries.size(); i++) {
+ float[] lutBuffer = mEntries.get(i).getBuffer();
System.arraycopy(lutBuffer, 0, buffer, mOffsets.get(i), lutBuffer.length);
}
return buffer;
}
/**
- * @return the starting point of each lut memory region of the lut buffer
+ * @hide
*/
public int[] getOffsets() {
return mOffsets.toArray();
}
/**
- * @return the array of Lut size
+ * @hide
*/
public int[] getLutSizes() {
- return mLutSizes.toArray();
+ int[] sizes = new int[mEntries.size()];
+ for (int i = 0; i < mEntries.size(); i++) {
+ sizes[i] = mEntries.get(i).getSize();
+ }
+ return sizes;
}
/**
- * @return the array of Lut dimension
+ * @hide
*/
public int[] getLutDimensions() {
- return mLutDimensions.toArray();
+ int[] dimensions = new int[mEntries.size()];
+ for (int i = 0; i < mEntries.size(); i++) {
+ dimensions[i] = mEntries.get(i).getDimension();
+ }
+ return dimensions;
}
/**
- * @return the array of sampling key
+ * @hide
*/
public int[] getLutSamplingKeys() {
- return mLutSamplingKeys.toArray();
+ int[] samplingKeys = new int[mEntries.size()];
+ for (int i = 0; i < mEntries.size(); i++) {
+ samplingKeys[i] = mEntries.get(i).getSamplingKey();
+ }
+ return samplingKeys;
}
}
diff --git a/core/java/android/hardware/LutProperties.java b/core/java/android/hardware/LutProperties.java
index c9c6d6d08ed2..abb303adac15 100644
--- a/core/java/android/hardware/LutProperties.java
+++ b/core/java/android/hardware/LutProperties.java
@@ -16,37 +16,53 @@
package android.hardware;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Lut properties class.
+ * Provides Lut properties of the device.
*
- * A Lut (Look-Up Table) is a pre-calculated table for color transformation.
- *
- * @hide
+ * <p>
+ * A Lut (Look-Up Table) is a pre-calculated table for color correction.
+ * Applications may be interested in the Lut properties exposed by
+ * this class to determine if the Lut(s) they select using
+ * {@link android.view.SurfaceControl.Transaction#setLuts} are by the HWC.
+ * </p>
*/
+@FlaggedApi(Flags.FLAG_LUTS_API)
public final class LutProperties {
private final @Dimension int mDimension;
private final int mSize;
private final @SamplingKey int[] mSamplingKeys;
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"SAMPLING_KEY_"}, value = {
SAMPLING_KEY_RGB,
- SAMPLING_KEY_MAX_RGB
+ SAMPLING_KEY_MAX_RGB,
+ SAMPLING_KEY_CIE_Y
})
public @interface SamplingKey {
}
/** use r,g,b channel as the gain value of a Lut */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int SAMPLING_KEY_RGB = 0;
/** use max of r,g,b channel as the gain value of a Lut */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int SAMPLING_KEY_MAX_RGB = 1;
+ /** use y of CIE XYZ as the gain value of a lut */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public static final int SAMPLING_KEY_CIE_Y = 2;
+
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
ONE_DIMENSION,
@@ -56,18 +72,22 @@ public final class LutProperties {
}
/** The Lut is one dimensional */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int ONE_DIMENSION = 1;
/** The Lut is three dimensional */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int THREE_DIMENSION = 3;
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public @Dimension int getDimension() {
return mDimension;
}
/**
- * @return the size of the Lut.
+ * @return the size of the Lut for each dimension
*/
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public int getSize() {
return mSize;
}
@@ -75,6 +95,8 @@ public final class LutProperties {
/**
* @return the list of sampling keys
*/
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ @NonNull
public @SamplingKey int[] getSamplingKeys() {
if (mSamplingKeys.length == 0) {
throw new IllegalStateException("no sampling key!");
diff --git a/core/java/android/hardware/OverlayProperties.java b/core/java/android/hardware/OverlayProperties.java
index 24cfc1b53e00..d42bfae23d2b 100644
--- a/core/java/android/hardware/OverlayProperties.java
+++ b/core/java/android/hardware/OverlayProperties.java
@@ -18,6 +18,7 @@ package android.hardware;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.hardware.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -72,9 +73,11 @@ public final class OverlayProperties implements Parcelable {
}
/**
- * Gets the lut properties of the display.
- * @hide
+ * Returns the lut properties of the device.
*/
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ @SuppressLint("ArrayReturn")
+ @NonNull
public LutProperties[] getLutProperties() {
if (mNativeObject == 0) {
return null;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 58e524e741b3..5533a640b9d8 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -19,9 +19,9 @@ package android.hardware.camera2;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.impl.ExtensionKey;
import android.hardware.camera2.impl.PublicKey;
import android.hardware.camera2.impl.SyntheticKey;
import android.hardware.camera2.params.DeviceStateSensorOrientationMap;
@@ -6172,6 +6172,66 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION =
new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.jpegr.availableJpegRStallDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+ /**
+ * <p>Color space used for shared session configuration for all the output targets
+ * when camera is opened in shared mode. This should be one of the values specified in
+ * availableColorSpaceProfilesMap.</p>
+ * <p><b>Possible values:</b></p>
+ * <ul>
+ * <li>{@link #SHARED_SESSION_COLOR_SPACE_UNSPECIFIED UNSPECIFIED}</li>
+ * <li>{@link #SHARED_SESSION_COLOR_SPACE_SRGB SRGB}</li>
+ * <li>{@link #SHARED_SESSION_COLOR_SPACE_DISPLAY_P3 DISPLAY_P3}</li>
+ * <li>{@link #SHARED_SESSION_COLOR_SPACE_BT2020_HLG BT2020_HLG}</li>
+ * </ul>
+ *
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * @see #SHARED_SESSION_COLOR_SPACE_UNSPECIFIED
+ * @see #SHARED_SESSION_COLOR_SPACE_SRGB
+ * @see #SHARED_SESSION_COLOR_SPACE_DISPLAY_P3
+ * @see #SHARED_SESSION_COLOR_SPACE_BT2020_HLG
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final Key<Integer> SHARED_SESSION_COLOR_SPACE =
+ new Key<Integer>("android.sharedSession.colorSpace", int.class);
+
+ /**
+ * <p>List of shared output configurations that this camera device supports when
+ * camera is opened in shared mode. Array contains following entries for each supported
+ * shared configuration:
+ * 1) surface type
+ * 2) width
+ * 3) height
+ * 4) format
+ * 5) mirrorMode
+ * 6) useReadoutTimestamp
+ * 7) timestampBase
+ * 8) dataspace
+ * 9) usage
+ * 10) streamUsecase
+ * 11) physical camera id len
+ * 12) physical camera id as UTF-8 null terminated string.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final Key<long[]> SHARED_SESSION_OUTPUT_CONFIGURATIONS =
+ new Key<long[]>("android.sharedSession.outputConfigurations", long[].class);
+
+ /**
+ * <p>The available stream configurations that this camera device supports for
+ * shared capture session when camera is opened in shared mode. Android camera framework
+ * will generate this tag if the camera device can be opened in shared mode.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @SyntheticKey
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final Key<android.hardware.camera2.params.SharedSessionConfiguration> SHARED_SESSION_CONFIGURATION =
+ new Key<android.hardware.camera2.params.SharedSessionConfiguration>("android.sharedSession.configuration", android.hardware.camera2.params.SharedSessionConfiguration.class);
+
/**
* Mapping from INFO_SESSION_CONFIGURATION_QUERY_VERSION to session characteristics key.
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index fb381d97adc3..852f04793f15 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -446,6 +446,17 @@ public abstract class CameraDevice implements AutoCloseable {
public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED =
1; // ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE;
+ /**
+ * Shared camera operation mode.
+ *
+ * @see #CameraSharedCaptureSession
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final int SESSION_OPERATION_MODE_SHARED =
+ 2; // ICameraDeviceUser.SHARED_MODE;
+
/**
* First vendor-specific operating mode
*
@@ -461,6 +472,7 @@ public abstract class CameraDevice implements AutoCloseable {
@IntDef(prefix = {"SESSION_OPERATION_MODE"}, value =
{SESSION_OPERATION_MODE_NORMAL,
SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED,
+ SESSION_OPERATION_MODE_SHARED,
SESSION_OPERATION_MODE_VENDOR_START})
public @interface SessionOperatingMode {};
@@ -1240,7 +1252,6 @@ public abstract class CameraDevice implements AutoCloseable {
*
* </ul>
*
- *
* @param config A session configuration (see {@link SessionConfiguration}).
*
* @throws IllegalArgumentException In case the session configuration is invalid; or the output
@@ -1559,6 +1570,48 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract void onOpened(@NonNull CameraDevice camera); // Must implement
/**
+ * The method called when a camera device has finished opening in shared mode,
+ * where there can be more than one client accessing the same camera.
+ *
+ * <p>At this point, the camera device is ready to use, and
+ * {@link CameraDevice#createCaptureSession} can be called to set up the shared capture
+ * session.</p>
+ *
+ * @param camera the camera device that has become opened
+ * @param isPrimaryClient true if the client opening the camera is currently the primary
+ * client.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public void onOpenedInSharedMode(@NonNull CameraDevice camera, boolean isPrimaryClient) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when client access priorities have changed for a camera device opened
+ * in shared mode where there can be more than one client accessing the same camera.
+ *
+ * If the client priority changed from secondary to primary, then it can now
+ * create capture request and change the capture request parameters. If client priority
+ * changed from primary to secondary, that implies that a higher priority client has also
+ * opened the camera in shared mode and the new client is now a primary client
+ *
+ * @param camera the camera device whose access priorities have changed.
+ * @param isPrimaryClient true if the client is now the primary client.
+ * false if another higher priority client also opened the
+ * camera and is now the new primary client and this client is
+ * now a secondary client.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public void onClientSharedAccessPriorityChanged(@NonNull CameraDevice camera,
+ boolean isPrimaryClient) {
+ // Default empty implementation
+ }
+
+ /**
* The method called when a camera device has been closed with
* {@link CameraDevice#close}.
*
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 3cf508a6db00..58fe4774f178 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -1066,6 +1066,7 @@ public final class CameraExtensionCharacteristics {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
case ImageFormat.JPEG_R:
+ case ImageFormat.DEPTH_JPEG:
case ImageFormat.YCBCR_P010:
break;
default:
@@ -1096,9 +1097,10 @@ public final class CameraExtensionCharacteristics {
// processed YUV_420 buffers.
return getSupportedSizes(
extenders.second.getSupportedPostviewResolutions(sz), format);
- } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
- // Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the basic
- // extension case
+ } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 ||
+ (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) {
+ // DepthJpeg/Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the
+ // basic extension case
return new ArrayList<>();
} else {
throw new IllegalArgumentException("Unsupported format: " + format);
@@ -1194,8 +1196,8 @@ public final class CameraExtensionCharacteristics {
*
* <p>Device-specific extensions currently support at most three
* multi-frame capture surface formats. ImageFormat.JPEG will be supported by all
- * extensions while ImageFormat.YUV_420_888, ImageFormat.JPEG_R, or ImageFormat.YCBCR_P010
- * may or may not be supported.</p>
+ * extensions while ImageFormat.YUV_420_888, ImageFormat.JPEG_R, ImageFormat.YCBCR_P010 or
+ * ImageFormat.DEPTH_JPEG may or may not be supported.</p>
*
* @param extension the extension type
* @param format device-specific extension output format
@@ -1203,7 +1205,8 @@ public final class CameraExtensionCharacteristics {
* supported.
* @throws IllegalArgumentException in case of format different from ImageFormat.JPEG,
* ImageFormat.YUV_420_888, ImageFormat.JPEG_R,
- * ImageFormat.YCBCR_P010; or unsupported extension.
+ * ImageFormat.DEPTH_JPEG, ImageFormat.YCBCR_P010; or
+ * unsupported extension.
*/
public @NonNull
List<Size> getExtensionSupportedSizes(@Extension int extension, int format) {
@@ -1227,6 +1230,7 @@ public final class CameraExtensionCharacteristics {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
case ImageFormat.JPEG_R:
+ case ImageFormat.DEPTH_JPEG:
case ImageFormat.YCBCR_P010:
break;
default:
@@ -1260,8 +1264,9 @@ public final class CameraExtensionCharacteristics {
} else {
return generateSupportedSizes(null, format, streamMap);
}
- } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
- // Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the
+ } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 ||
+ (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) {
+ // DepthJpeg/Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the
// basic extension case
return new ArrayList<>();
} else {
@@ -1292,7 +1297,8 @@ public final class CameraExtensionCharacteristics {
* or null if no capture latency info can be provided
* @throws IllegalArgumentException in case of format different from {@link ImageFormat#JPEG},
* {@link ImageFormat#YUV_420_888}, {@link ImageFormat#JPEG_R}
- * {@link ImageFormat#YCBCR_P010};
+ * {@link ImageFormat#YCBCR_P010},
+ * {@link ImageFormat#DEPTH_JPEG};
* or unsupported extension.
*/
public @Nullable Range<Long> getEstimatedCaptureLatencyRangeMillis(@Extension int extension,
@@ -1301,6 +1307,7 @@ public final class CameraExtensionCharacteristics {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
case ImageFormat.JPEG_R:
+ case ImageFormat.DEPTH_JPEG:
case ImageFormat.YCBCR_P010:
//No op
break;
@@ -1349,8 +1356,9 @@ public final class CameraExtensionCharacteristics {
// specific and cannot be estimated accurately enough.
return null;
}
- if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
- // JpegR/UltraHDR + YCBCR_P010 is not supported for basic extensions
+ if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 ||
+ (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) {
+ // DepthJpeg/JpegR/UltraHDR + YCBCR_P010 is not supported for basic extensions
return null;
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 75e20582b7b4..266efb7b759c 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -976,6 +976,46 @@ public final class CameraManager {
}
/**
+ * Checks if a camera device can be opened in a shared mode for a given {@code cameraId}.
+ * If this method returns false for a {@code cameraId}, calling {@link #openSharedCamera}
+ * for that {@code cameraId} will throw an {@link UnsupportedOperationException}.
+ *
+ * @param cameraId The unique identifier of the camera device for which sharing support is
+ * being queried. This identifier must be present in
+ * {@link #getCameraIdList()}.
+ *
+ * @return {@code true} if camera can be opened in shared mode
+ * for the provided {@code cameraId}; {@code false} otherwise.
+ *
+ * @throws IllegalArgumentException If {@code cameraId} is null, or if {@code cameraId} does not
+ * match any device in {@link #getCameraIdList()}.
+ * @throws CameraAccessException if the camera device has been disconnected.
+ *
+ * @see #getCameraIdList()
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ @SystemApi
+ public boolean isCameraDeviceSharingSupported(@NonNull String cameraId)
+ throws CameraAccessException {
+ if (cameraId == null) {
+ throw new IllegalArgumentException("Camera ID was null");
+ }
+
+ if (CameraManagerGlobal.sCameraServiceDisabled
+ || !Arrays.asList(CameraManagerGlobal.get().getCameraIdList(mContext.getDeviceId(),
+ getDevicePolicyFromContext(mContext))).contains(cameraId)) {
+ throw new IllegalArgumentException(
+ "Camera ID '" + cameraId + "' not available on device.");
+ }
+
+ CameraCharacteristics chars = getCameraCharacteristics(cameraId);
+ long[] sharedOutputConfiguration =
+ chars.get(CameraCharacteristics.SHARED_SESSION_OUTPUT_CONFIGURATIONS);
+ return (sharedOutputConfiguration != null);
+ }
+
+ /**
* Retrieves the AttributionSourceState to pass to the CameraService.
*
* @param deviceIdOverride An override of the AttributionSource's deviceId, if not equal to
@@ -1036,6 +1076,9 @@ public final class CameraManager {
* @param cameraId The unique identifier of the camera device to open
* @param callback The callback for the camera. Must not be null.
* @param executor The executor to invoke the callback with. Must not be null.
+ * @param oomScoreOffset The minimum oom score that cameraservice must see for this client.
+ * @param rotationOverride The type of rotation override.
+ * @param sharedMode Parameter specifying if the camera should be opened in shared mode.
*
* @throws CameraAccessException if the camera is disabled by device policy,
* too many camera devices are already open, or the cameraId does not match
@@ -1051,7 +1094,8 @@ public final class CameraManager {
*/
private CameraDevice openCameraDeviceUserAsync(String cameraId,
CameraDevice.StateCallback callback, Executor executor,
- final int oomScoreOffset, int rotationOverride) throws CameraAccessException {
+ final int oomScoreOffset, int rotationOverride, boolean sharedMode)
+ throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
synchronized (mLock) {
@@ -1070,7 +1114,7 @@ public final class CameraManager {
characteristics,
this,
mContext.getApplicationInfo().targetSdkVersion,
- mContext, cameraDeviceSetup);
+ mContext, cameraDeviceSetup, sharedMode);
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
try {
@@ -1091,7 +1135,7 @@ public final class CameraManager {
mContext.getApplicationInfo().targetSdkVersion,
rotationOverride,
clientAttribution,
- getDevicePolicyFromContext(mContext));
+ getDevicePolicyFromContext(mContext), sharedMode);
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
@@ -1218,7 +1262,8 @@ public final class CameraManager {
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {
- openCameraImpl(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler));
+ openCameraImpl(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
+ /*oomScoreOffset*/0, getRotationOverride(mContext), /*sharedMode*/false);
}
/**
@@ -1258,7 +1303,7 @@ public final class CameraManager {
/*oomScoreOffset*/0,
overrideToPortrait
? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
- : ICameraService.ROTATION_OVERRIDE_NONE);
+ : ICameraService.ROTATION_OVERRIDE_NONE, /*sharedMode*/false);
}
/**
@@ -1303,9 +1348,56 @@ public final class CameraManager {
if (executor == null) {
throw new IllegalArgumentException("executor was null");
}
- openCameraImpl(cameraId, callback, executor);
+ openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0,
+ getRotationOverride(mContext), /*sharedMode*/false);
+ }
+
+ /**
+ * Opens a shared connection to a camera with the given ID.
+ *
+ * <p>The behavior of this method matches that of
+ * {@link #openCamera(String, Executor, StateCallback)}, except that it opens the camera in
+ * shared mode where more than one client can access the camera at the same time.</p>
+ *
+ * @param cameraId The unique identifier of the camera device to open.
+ * @param executor The executor which will be used when invoking the callback.
+ * @param callback The callback which is invoked once the camera is opened
+ *
+ * @throws CameraAccessException if the camera is disabled by device policy, or is being used
+ * by a higher-priority client in non-shared mode or the device
+ * has reached its maximal resource and cannot open this camera
+ * device.
+ *
+ * @throws IllegalArgumentException if cameraId, the callback or the executor was null,
+ * or the cameraId does not match any currently or previously
+ * available camera device.
+ *
+ * @throws SecurityException if the application does not have permission to
+ * access the camera
+ *
+ * @see #getCameraIdList
+ * @see android.app.admin.DevicePolicyManager#setCameraDisabled
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.SYSTEM_CAMERA,
+ android.Manifest.permission.CAMERA,
+ })
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public void openSharedCamera(@NonNull String cameraId,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull final CameraDevice.StateCallback callback)
+ throws CameraAccessException {
+ if (executor == null) {
+ throw new IllegalArgumentException("executor was null");
+ }
+ openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0,
+ getRotationOverride(mContext), /*sharedMode*/true);
}
+
/**
* Open a connection to a camera with the given ID. Also specify what oom score must be offset
* by cameraserver for this client. This api can be useful for system
@@ -1372,29 +1464,35 @@ public final class CameraManager {
"oomScoreOffset < 0, cannot increase priority of camera client");
}
openCameraImpl(cameraId, callback, executor, oomScoreOffset,
- getRotationOverride(mContext));
+ getRotationOverride(mContext), /*sharedMode*/false);
}
/**
* Open a connection to a camera with the given ID, on behalf of another application.
- * Also specify the minimum oom score and process state the application
- * should have, as seen by the cameraserver.
- *
- * <p>The behavior of this method matches that of {@link #openCamera}, except that it allows
- * the caller to specify the UID to use for permission/etc verification. This can only be
- * done by services trusted by the camera subsystem to act on behalf of applications and
- * to forward the real UID.</p>
*
+ * @param cameraId
+ * The unique identifier of the camera device to open
+ * @param callback
+ * The callback which is invoked once the camera is opened
+ * @param executor
+ * The executor which will be used when invoking the callback.
* @param oomScoreOffset
* The minimum oom score that cameraservice must see for this client.
* @param rotationOverride
* The type of rotation override (none, override_to_portrait, rotation_only)
* that should be followed for this camera id connection
+ * @param sharedMode
+ * Parameter specifying if the camera should be opened in shared mode.
+ *
+ * @throws CameraAccessException if the camera is disabled by device policy,
+ * has been disconnected, or is being used by a higher-priority camera API client in
+ * non shared mode.
+ *
* @hide
*/
public void openCameraImpl(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
- int oomScoreOffset, int rotationOverride)
+ int oomScoreOffset, int rotationOverride, boolean sharedMode)
throws CameraAccessException {
if (cameraId == null) {
@@ -1407,24 +1505,7 @@ public final class CameraManager {
}
openCameraDeviceUserAsync(cameraId, callback, executor, oomScoreOffset,
- rotationOverride);
- }
-
- /**
- * Open a connection to a camera with the given ID, on behalf of another application.
- *
- * <p>The behavior of this method matches that of {@link #openCamera}, except that it allows
- * the caller to specify the UID to use for permission/etc verification. This can only be
- * done by services trusted by the camera subsystem to act on behalf of applications and
- * to forward the real UID.</p>
- *
- * @hide
- */
- public void openCameraImpl(@NonNull String cameraId,
- @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor)
- throws CameraAccessException {
- openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0,
- getRotationOverride(mContext));
+ rotationOverride, sharedMode);
}
/**
@@ -2541,6 +2622,10 @@ public final class CameraManager {
}
@Override
public void onCameraClosed(String id, int deviceId) {
+ }
+ @Override
+ public void onCameraOpenedInSharedMode(String id, String clientPackageId,
+ int deviceId, boolean primaryClient) {
}};
String[] cameraIds;
@@ -3325,6 +3410,11 @@ public final class CameraManager {
}
@Override
+ public void onCameraOpenedInSharedMode(String cameraId, String clientPackageId,
+ int deviceId, boolean primaryClient) {
+ }
+
+ @Override
public void onCameraOpened(String cameraId, String clientPackageId, int deviceId) {
synchronized (mLock) {
onCameraOpenedLocked(new DeviceCameraInfo(cameraId, deviceId), clientPackageId);
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 8d36fbdc8b10..d2fcfd62bfca 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2121,6 +2121,38 @@ public abstract class CameraMetadata<TKey> {
public static final int AUTOMOTIVE_LOCATION_EXTRA_RIGHT = 10;
//
+ // Enumeration values for CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+ //
+
+ /**
+ * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final int SHARED_SESSION_COLOR_SPACE_UNSPECIFIED = -1;
+
+ /**
+ * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final int SHARED_SESSION_COLOR_SPACE_SRGB = 0;
+
+ /**
+ * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final int SHARED_SESSION_COLOR_SPACE_DISPLAY_P3 = 7;
+
+ /**
+ * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public static final int SHARED_SESSION_COLOR_SPACE_BT2020_HLG = 16;
+
+ //
// Enumeration values for CaptureRequest#COLOR_CORRECTION_MODE
//
diff --git a/core/java/android/hardware/camera2/CameraSharedCaptureSession.java b/core/java/android/hardware/camera2/CameraSharedCaptureSession.java
new file mode 100644
index 000000000000..5426d4d10bec
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraSharedCaptureSession.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.view.Surface;
+
+import com.android.internal.camera.flags.Flags;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A shared capture session for a {@link CameraDevice}, when a camera device is opened in shared
+ * mode possibly by multiple clients at the same time.
+ *
+ * <p>An active shared capture session is a special type of capture session used exclusively
+ * for shared camera access by multiple applications, provided the camera device supports this
+ * mode. To determine if a camera device supports shared mode, use the
+ * {@link android.hardware.camera2.CameraManager#isCameraDeviceSharingSupported} API.
+ * If supported, multiple clients can open the camera by calling
+ * {@link android.hardware.camera2.CameraManager#openSharedCamera} and create a shared capture
+ * session by calling {@link CameraDevice#createCaptureSession(SessionConfiguration)} and using
+ * session type as {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED}</p>
+ *
+ * <p>When an application has opened a camera device in shared mode, it can only create a shared
+ * capture session using session type as
+ * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED}. Any other session
+ * type value will trigger {@link IllegalArgumentException}. Once the configuration is complete and
+ * the session is ready to actually capture data, the provided
+ * {@link CameraCaptureSession.StateCallback}'s
+ * {@link CameraCaptureSession.StateCallback#onConfigured} callback will be called and will
+ * receive a CameraCaptureSession (castable to {@link CameraSharedCaptureSession}).</p>
+ *
+ * <p>Shared capture sessions uses a predefined configuration detailed in
+ * {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION}. Using different configuration values
+ * when creating session will result in an {@link IllegalArgumentException}.</p>
+ *
+ * <p>When camera is opened in shared mode, the highest priority client among all the clients will
+ * be the primary client while the others would be secondary clients. Clients will know if they are
+ * primary or secondary by the device state callback
+ * {@link CameraDevice.StateCallback#onOpenedInSharedMode}. Once the camera has been opened in
+ * shared mode, their access priorities of being a primary or secondary client can change if
+ * another higher priority client opens the camera later. Once the camera has been opened,
+ * any change in primary client status will be shared by the device state callback
+ * {@link CameraDevice.StateCallback#onClientSharedAccessPriorityChanged}.</p>
+ *
+ * <p>The priority of client access is determined by considering two factors: its current process
+ * state and its "out of memory" score. Clients operating in the background are assigned a lower
+ * priority. In contrast, clients running in the foreground, along with system-level clients, are
+ * given a higher priority.</p>
+ *
+ * <p>Primary clients can create capture requests, modify any capture parameters and send them to
+ * the capture session for a one-shot capture or as a repeating request using the following apis:
+ * </p>
+ *
+ * <ul>
+ *
+ * <li>{@link CameraSharedCaptureSession#capture}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#captureSingleRequest}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setRepeatingRequest}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setSingleRepeatingRequest}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#stopRepeating}</li>
+ *
+ * </ul>
+ *
+ * <p>Secondary clients cannot create a capture request and modify any capture parameters. However,
+ * they can start the camera streaming to desired surface targets using
+ * {@link CameraSharedCaptureSession#startStreaming}, which will apply default parameters. Once the
+ * streaming has successfully started, then they can stop the streaming using
+ * {@link CameraSharedCaptureSession#stopStreaming}.</p>
+ *
+ * <p>The following APIs are not supported in shared capture sessions by either the primary or
+ * secondary client.</p>
+ *
+ * <ul>
+ *
+ * <li>{@link CameraSharedCaptureSession#captureBurst}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#captureBurstRequests}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setRepeatingBurst}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setRepeatingBurstRequests}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#switchToOffline}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#updateOutputConfiguration}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#finalizeOutputConfigurations}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#prepare}</li>
+ *
+ * </ul>
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+@SystemApi
+public abstract class CameraSharedCaptureSession extends CameraCaptureSession {
+
+ /**
+ * Request start of the streaming of camera images by this shared capture session.
+ *
+ * <p>With this method, the camera device will continually capture images
+ * using the settings provided by primary client if there is ongoing repeating request
+ * by the primary client or default settings if no ongoing streaming request in progress.</p>
+ *
+ * <p> startStreaming has lower priority than the capture requests submitted
+ * through {@link #capture} by primary client, so if {@link #capture} is called when a
+ * streaming is active, the capture request will be processed before any further
+ * streaming requests are processed.</p>
+ *
+ * <p>To stop the streaming, call {@link #stopStreaming}</p>
+ *
+ * <p>Calling this method will replace any earlier streaming set up by this method.</p>
+ *
+ * @param surfaces List of target surfaces to use for streaming.
+ * @param executor The executor which will be used for invoking the listener.
+ * @param listener The callback object to notify the status and progress of the image capture.
+ *
+ * @return int A unique capture sequence ID used by
+ * {@link CaptureCallback#onCaptureSequenceCompleted}.
+ *
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error
+ * @throws IllegalStateException if this session is no longer active, either because the session
+ * was explicitly closed, a new session has been created
+ * or the camera device has been closed.
+ * @throws IllegalArgumentException If the request references no surfaces or references surfaces
+ * that are not currently configured as outputs; or
+ * the executor is null, or the listener is null.
+ * @see #stopStreaming
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ @SystemApi
+ public abstract int startStreaming(@NonNull List<Surface> surfaces,
+ @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener)
+ throws CameraAccessException;
+
+ /**
+ * <p>Cancel any ongoing streaming started by {@link #startStreaming}</p>
+ *
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error
+ * @throws IllegalStateException if this session is no longer active, either because the session
+ * was explicitly closed, a new session has been created
+ * or the camera device has been closed.
+ *
+ * @see #startStreaming
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ @SystemApi
+ public abstract void stopStreaming() throws CameraAccessException;
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index fc03b517e6d4..d511e9f64c17 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -186,12 +186,12 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
HashMap<Integer, List<Size>> supportedCaptureSizes = new HashMap<>();
- IntArray supportedCaptureOutputFormats =
- new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
- supportedCaptureOutputFormats.addAll(
- CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- for (int format : supportedCaptureOutputFormats.toArray()) {
+ Integer[] supportedCaptureOutputFormats =
+ new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()];
+ supportedCaptureOutputFormats =
+ CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray(
+ supportedCaptureOutputFormats);
+ for (int format : supportedCaptureOutputFormats) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
if (supportedSizes != null) {
@@ -230,7 +230,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
Size burstCaptureSurfaceSize =
new Size(burstCaptureSurfaceInfo.mWidth, burstCaptureSurfaceInfo.mHeight);
HashMap<Integer, List<Size>> supportedPostviewSizes = new HashMap<>();
- for (int format : supportedCaptureOutputFormats.toArray()) {
+ for (int format : supportedCaptureOutputFormats) {
List<Size> supportedSizesPostview = extensionChars.getPostviewSupportedSizes(
config.getExtension(), burstCaptureSurfaceSize, format);
if (supportedSizesPostview != null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 84072585d7f0..ea70abb55b48 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -18,6 +18,7 @@ package android.hardware.camera2.impl;
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.compat.CompatChanges;
@@ -41,12 +42,15 @@ import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.ICameraOfflineSession;
import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.DynamicRangeProfiles;
import android.hardware.camera2.params.ExtensionSessionConfiguration;
import android.hardware.camera2.params.InputConfiguration;
import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
import android.hardware.camera2.params.MultiResolutionStreamInfo;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.params.SharedSessionConfiguration;
+import android.hardware.camera2.params.SharedSessionConfiguration.SharedOutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.utils.SurfaceUtils;
@@ -188,6 +192,8 @@ public class CameraDeviceImpl extends CameraDevice
private ExecutorService mOfflineSwitchService;
private CameraOfflineSessionImpl mOfflineSessionImpl;
+ private boolean mSharedMode;
+ private boolean mIsPrimaryClient;
// Runnables for all state transitions, except error, which needs the
// error code argument
@@ -208,6 +214,25 @@ public class CameraDeviceImpl extends CameraDevice
}
};
+ private final Runnable mCallOnOpenedInSharedMode = new Runnable() {
+ @Override
+ public void run() {
+ if (!Flags.cameraMultiClient()) {
+ return;
+ }
+ StateCallbackKK sessionCallback = null;
+ synchronized (mInterfaceLock) {
+ if (mRemoteDevice == null) return; // Camera already closed
+
+ sessionCallback = mSessionStateCallback;
+ }
+ if (sessionCallback != null) {
+ sessionCallback.onOpenedInSharedMode(CameraDeviceImpl.this, mIsPrimaryClient);
+ }
+ mDeviceCallback.onOpenedInSharedMode(CameraDeviceImpl.this, mIsPrimaryClient);
+ }
+ };
+
private final Runnable mCallOnUnconfigured = new Runnable() {
@Override
public void run() {
@@ -322,6 +347,32 @@ public class CameraDeviceImpl extends CameraDevice
}
});
}
+
+ public void onOpenedInSharedMode(@NonNull CameraDevice camera, boolean primaryClient) {
+ if (!Flags.cameraMultiClient()) {
+ return;
+ }
+ mClientExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mClientStateCallback.onOpenedInSharedMode(camera, primaryClient);
+ }
+ });
+ }
+
+ public void onClientSharedAccessPriorityChanged(@NonNull CameraDevice camera,
+ boolean primaryClient) {
+ if (!Flags.cameraMultiClient()) {
+ return;
+ }
+ mClientExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mClientStateCallback.onClientSharedAccessPriorityChanged(camera, primaryClient);
+ }
+ });
+ }
+
@Override
public void onOpened(@NonNull CameraDevice camera) {
mClientExecutor.execute(new Runnable() {
@@ -358,7 +409,8 @@ public class CameraDeviceImpl extends CameraDevice
@NonNull CameraManager manager,
int appTargetSdkVersion,
Context ctx,
- @Nullable CameraDevice.CameraDeviceSetup cameraDeviceSetup) {
+ @Nullable CameraDevice.CameraDeviceSetup cameraDeviceSetup,
+ boolean sharedMode) {
if (cameraId == null || callback == null || executor == null || characteristics == null
|| manager == null) {
throw new IllegalArgumentException("Null argument given");
@@ -375,6 +427,7 @@ public class CameraDeviceImpl extends CameraDevice
mAppTargetSdkVersion = appTargetSdkVersion;
mContext = ctx;
mCameraDeviceSetup = cameraDeviceSetup;
+ mSharedMode = sharedMode;
final int MAX_TAG_LEN = 23;
String tag = String.format("CameraDevice-JV-%s", mCameraId);
@@ -438,7 +491,12 @@ public class CameraDeviceImpl extends CameraDevice
}
}
- mDeviceExecutor.execute(mCallOnOpened);
+ if (Flags.cameraMultiClient() && mSharedMode) {
+ mIsPrimaryClient = mRemoteDevice.isPrimaryClient();
+ mDeviceExecutor.execute(mCallOnOpenedInSharedMode);
+ } else {
+ mDeviceExecutor.execute(mCallOnOpened);
+ }
mDeviceExecutor.execute(mCallOnUnconfigured);
mRemoteDeviceInit = true;
@@ -576,7 +634,11 @@ public class CameraDeviceImpl extends CameraDevice
stopRepeating();
try {
- waitUntilIdle();
+ // if device is opened in shared mode, there can be multiple clients accessing the
+ // camera device. So do not wait for idle if the device is opened in shared mode.
+ if (!mSharedMode) {
+ waitUntilIdle();
+ }
mRemoteDevice.beginConfigure();
@@ -764,6 +826,54 @@ public class CameraDeviceImpl extends CameraDevice
checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
}
+ private boolean checkSharedOutputConfiguration(OutputConfiguration outConfig) {
+ if (!Flags.cameraMultiClient()) {
+ return false;
+ }
+ SharedSessionConfiguration sharedSessionConfiguration =
+ mCharacteristics.get(CameraCharacteristics.SHARED_SESSION_CONFIGURATION);
+ if (sharedSessionConfiguration == null) {
+ return false;
+ }
+
+ List<SharedOutputConfiguration> sharedConfigs =
+ sharedSessionConfiguration.getOutputStreamsInformation();
+ for (SharedOutputConfiguration sharedConfig : sharedConfigs) {
+ if (outConfig.getConfiguredSize().equals(sharedConfig.getSize())
+ && (outConfig.getConfiguredFormat() == sharedConfig.getFormat())
+ && (outConfig.getSurfaceGroupId() == OutputConfiguration.SURFACE_GROUP_ID_NONE)
+ && (outConfig.getSurfaceType() == sharedConfig.getSurfaceType())
+ && (outConfig.getMirrorMode() == sharedConfig.getMirrorMode())
+ && (outConfig.getUsage() == sharedConfig.getUsage())
+ && (outConfig.isReadoutTimestampEnabled()
+ == sharedConfig.isReadoutTimestampEnabled())
+ && (outConfig.getTimestampBase() == sharedConfig.getTimestampBase())
+ && (outConfig.getStreamUseCase() == sharedConfig.getStreamUseCase())
+ && (outConfig.getColorSpace().equals(
+ sharedSessionConfiguration.getColorSpace()))
+ && (outConfig.getDynamicRangeProfile()
+ == DynamicRangeProfiles.STANDARD)
+ && (outConfig.getConfiguredDataspace() == sharedConfig.getDataspace())
+ && (Objects.equals(outConfig.getPhysicalCameraId(),
+ sharedConfig.getPhysicalCameraId()))
+ && (outConfig.getSensorPixelModes().isEmpty())
+ && (!outConfig.isShared())) {
+ //Found valid config, return true
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkSharedSessionConfiguration(List<OutputConfiguration> outputConfigs) {
+ for (OutputConfiguration out : outputConfigs) {
+ if (!checkSharedOutputConfiguration(out)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
public void createCaptureSession(SessionConfiguration config)
throws CameraAccessException {
@@ -778,6 +888,14 @@ public class CameraDeviceImpl extends CameraDevice
if (config.getExecutor() == null) {
throw new IllegalArgumentException("Invalid executor");
}
+ if (mSharedMode) {
+ if (config.getSessionType() != SessionConfiguration.SESSION_SHARED) {
+ throw new IllegalArgumentException("Invalid session type");
+ }
+ if (!checkSharedSessionConfiguration(outputConfigs)) {
+ throw new IllegalArgumentException("Invalid output configurations");
+ }
+ }
createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
config.getStateCallback(), config.getExecutor(), config.getSessionType(),
config.getSessionParameters());
@@ -801,6 +919,11 @@ public class CameraDeviceImpl extends CameraDevice
throw new IllegalArgumentException("Constrained high speed session doesn't support"
+ " input configuration yet.");
}
+ boolean isSharedSession = (operatingMode == ICameraDeviceUser.SHARED_MODE);
+ if (isSharedSession && inputConfig != null) {
+ throw new IllegalArgumentException("Shared capture session doesn't support"
+ + " input configuration yet.");
+ }
if (mCurrentExtensionSession != null) {
mCurrentExtensionSession.commitStats();
@@ -860,6 +983,10 @@ public class CameraDeviceImpl extends CameraDevice
newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
callback, executor, this, mDeviceExecutor, configureSuccess,
mCharacteristics);
+ } else if (isSharedSession) {
+ newSession = new CameraSharedCaptureSessionImpl(mNextSessionId++,
+ callback, executor, this, mDeviceExecutor, configureSuccess,
+ mIsPrimaryClient);
} else {
newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
callback, executor, this, mDeviceExecutor, configureSuccess);
@@ -1882,6 +2009,40 @@ public class CameraDeviceImpl extends CameraDevice
}
}
+ /**
+ * Callback when client access priorities change when camera is opened in shared mode.
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ "onClientSharedAccessPriorityChanged received, primary client = "
+ + primaryClient));
+ }
+ synchronized (mInterfaceLock) {
+ if (mRemoteDevice == null && mRemoteDeviceInit) {
+ return; // Camera already closed, user is not interested in this callback anymore.
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mDeviceExecutor.execute(obtainRunnable(
+ CameraDeviceImpl::notifyClientSharedAccessPriorityChanged, this,
+ primaryClient).recycleOnUse());
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ private void notifyClientSharedAccessPriorityChanged(boolean primaryClient) {
+ if (!CameraDeviceImpl.this.isClosed()) {
+ mIsPrimaryClient = primaryClient;
+ mDeviceCallback.onClientSharedAccessPriorityChanged(CameraDeviceImpl.this,
+ primaryClient);
+ }
+ }
+
public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
if (DEBUG) {
Log.d(TAG, String.format(
@@ -2447,6 +2608,12 @@ public class CameraDeviceImpl extends CameraDevice
}
@Override
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+ CameraDeviceImpl.this.onClientSharedAccessPriorityChanged(primaryClient);
+ }
+
+ @Override
public void onPrepared(int streamId) {
final OutputConfiguration output;
final StateCallbackKK sessionCallback;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index ce1609dec4e6..ed73e624e242 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -186,12 +186,12 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
}
HashMap<Integer, List<Size>> supportedCaptureSizes = new HashMap<>();
- IntArray supportedCaptureOutputFormats =
- new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
- supportedCaptureOutputFormats.addAll(
- CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- for (int format : supportedCaptureOutputFormats.toArray()) {
+ Integer[] supportedCaptureOutputFormats =
+ new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()];
+ supportedCaptureOutputFormats =
+ CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray(
+ supportedCaptureOutputFormats);
+ for (int format : supportedCaptureOutputFormats) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
if (supportedSizes != null) {
@@ -223,7 +223,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
Size burstCaptureSurfaceSize =
new Size(burstCaptureSurfaceInfo.mWidth, burstCaptureSurfaceInfo.mHeight);
HashMap<Integer, List<Size>> supportedPostviewSizes = new HashMap<>();
- for (int format : supportedCaptureOutputFormats.toArray()) {
+ for (int format : supportedCaptureOutputFormats) {
List<Size> supportedSizesPostview = extensionChars.getPostviewSupportedSizes(
config.getExtension(), burstCaptureSurfaceSize, format);
if (supportedSizesPostview != null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index f91d277d571f..212c909bcbba 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -32,11 +32,14 @@ import android.os.Handler;
import android.util.IntArray;
import android.util.Log;
import android.util.Size;
+import android.util.SparseIntArray;
import android.view.Surface;
import com.android.internal.camera.flags.Flags;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -48,11 +51,16 @@ public final class CameraExtensionUtils {
public final static int JPEG_DEFAULT_QUALITY = 100;
public final static int JPEG_DEFAULT_ROTATION = 0;
- public static final int[] SUPPORTED_CAPTURE_OUTPUT_FORMATS = {
- CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
- ImageFormat.JPEG,
- ImageFormat.JPEG_R
- };
+ public static HashSet<Integer> SUPPORTED_CAPTURE_OUTPUT_FORMATS = new HashSet<>();
+
+ static {
+ SUPPORTED_CAPTURE_OUTPUT_FORMATS.addAll(Arrays.asList(
+ CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT, ImageFormat.JPEG,
+ ImageFormat.YCBCR_P010, ImageFormat.JPEG_R ));
+ if (Flags.depthJpegExtensions()) {
+ SUPPORTED_CAPTURE_OUTPUT_FORMATS.add(ImageFormat.DEPTH_JPEG);
+ }
+ }
public static class SurfaceInfo {
public int mWidth = 0;
@@ -101,6 +109,13 @@ public final class CameraExtensionUtils {
surfaceInfo.mFormat = ImageFormat.JPEG_R;
return surfaceInfo;
}
+ if (Flags.depthJpegExtensions()) {
+ if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB)
+ && (dataspace == StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH)) {
+ surfaceInfo.mFormat = ImageFormat.DEPTH_JPEG;
+ return surfaceInfo;
+ }
+ }
return surfaceInfo;
}
@@ -125,14 +140,14 @@ public final class CameraExtensionUtils {
public static Surface getBurstCaptureSurface(
@NonNull List<OutputConfiguration> outputConfigs,
@NonNull HashMap<Integer, List<Size>> supportedCaptureSizes) {
- IntArray supportedCaptureOutputFormats =
- new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
- supportedCaptureOutputFormats.addAll(
- CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
+ Integer[] supportedCaptureOutputFormats =
+ new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()];
+ supportedCaptureOutputFormats =
+ CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray(
+ supportedCaptureOutputFormats);
for (OutputConfiguration config : outputConfigs) {
SurfaceInfo surfaceInfo = querySurface(config.getSurface());
- for (int supportedFormat : supportedCaptureOutputFormats.toArray()) {
+ for (int supportedFormat : supportedCaptureOutputFormats) {
if (surfaceInfo.mFormat == supportedFormat) {
Size captureSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
if (supportedCaptureSizes.containsKey(supportedFormat)) {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 1cc085658bfa..c0a5928a369b 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -63,6 +63,7 @@ import android.hardware.camera2.params.OisSample;
import android.hardware.camera2.params.RecommendedStreamConfiguration;
import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.SharedSessionConfiguration;
import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.params.StreamConfigurationDuration;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -866,6 +867,15 @@ public class CameraMetadataNative implements Parcelable {
return (T) metadata.getLensIntrinsicSamples();
}
});
+ sGetCommandMap.put(
+ CameraCharacteristics.SHARED_SESSION_CONFIGURATION.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getSharedSessionConfiguration();
+ }
+ });
}
private int[] getAvailableFormats() {
@@ -1658,6 +1668,22 @@ public class CameraMetadataNative implements Parcelable {
listHighResolution);
}
+ private SharedSessionConfiguration getSharedSessionConfiguration() {
+ if (!Flags.cameraMultiClient()) {
+ return null;
+ }
+ Integer sharedSessionColorSpace = getBase(
+ CameraCharacteristics.SHARED_SESSION_COLOR_SPACE);
+ long[] sharedOutputConfigurations = getBase(
+ CameraCharacteristics.SHARED_SESSION_OUTPUT_CONFIGURATIONS);
+
+ if ((sharedSessionColorSpace == null) || (sharedOutputConfigurations == null)) {
+ return null;
+ }
+
+ return new SharedSessionConfiguration(sharedSessionColorSpace, sharedOutputConfigurations);
+ }
+
private StreamConfigurationMap getStreamConfigurationMapMaximumResolution() {
StreamConfiguration[] configurations = getBase(
CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION);
diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
index eb2ff88ec1b2..1769c4638805 100644
--- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
@@ -16,11 +16,13 @@
package android.hardware.camera2.impl;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.FlaggedApi;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraOfflineSession;
import android.hardware.camera2.CameraOfflineSession.CameraOfflineSessionCallback;
import android.hardware.camera2.CaptureFailure;
@@ -40,15 +42,15 @@ import android.util.Range;
import android.util.SparseArray;
import android.view.Surface;
+import com.android.internal.camera.flags.Flags;
+
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.Executor;
-
-import static com.android.internal.util.Preconditions.*;
+import java.util.concurrent.atomic.AtomicBoolean;
public class CameraOfflineSessionImpl extends CameraOfflineSession
implements IBinder.DeathRecipient {
@@ -176,6 +178,12 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession
}
@Override
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+ Log.v(TAG, "onClientSharedAccessPriorityChanged primaryClient = " + primaryClient);
+ }
+
+ @Override
public void onDeviceIdle() {
synchronized(mInterfaceLock) {
if (mRemoteSession == null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java
new file mode 100644
index 000000000000..a1f31c0ced5e
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.impl;
+
+import android.annotation.FlaggedApi;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraSharedCaptureSession;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.view.Surface;
+
+import com.android.internal.camera.flags.Flags;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Standard implementation of CameraSharedCaptureSession.
+ *
+ * <p>
+ * Mostly just forwards calls to an instance of CameraCaptureSessionImpl,
+ * but implements the few necessary behavior changes and additional methods required
+ * for the shared session mode.
+ * </p>
+ */
+@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+public class CameraSharedCaptureSessionImpl
+ extends CameraSharedCaptureSession implements CameraCaptureSessionCore {
+ private static final String TAG = "CameraSharedCaptureSessionImpl";
+ private final CameraCaptureSessionImpl mSessionImpl;
+ private final ConditionVariable mInitialized = new ConditionVariable();
+ private boolean mIsPrimary;
+
+ /**
+ * Create a new CameraCaptureSession.
+ */
+ CameraSharedCaptureSessionImpl(int id,
+ CameraCaptureSession.StateCallback callback, Executor stateExecutor,
+ android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
+ Executor deviceStateExecutor, boolean configureSuccess, boolean isPrimary) {
+ CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
+ mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
+ stateExecutor, deviceImpl, deviceStateExecutor, configureSuccess);
+ mIsPrimary = isPrimary;
+ mInitialized.open();
+ }
+
+ @Override
+ public int startStreaming(List<Surface> surfaces, Executor executor, CaptureCallback listener)
+ throws CameraAccessException {
+ // Todo: Need to add implementation.
+ return 0;
+ }
+
+ @Override
+ public void stopStreaming() throws CameraAccessException {
+ // Todo: Need to add implementation.
+ }
+
+ @Override
+ public void close() {
+ mSessionImpl.close();
+ }
+
+ @Override
+ public Surface getInputSurface() {
+ return null;
+ }
+
+ @Override
+ public boolean isReprocessable() {
+ return false;
+ }
+
+ @Override
+ public void abortCaptures() throws CameraAccessException {
+ if (mIsPrimary) {
+ mSessionImpl.abortCaptures();
+ }
+ }
+
+ @Override
+ public int setRepeatingRequest(CaptureRequest request, CaptureCallback listener,
+ Handler handler) throws CameraAccessException {
+ if (mIsPrimary) {
+ return mSessionImpl.setRepeatingRequest(request, listener, handler);
+ }
+ throw new UnsupportedOperationException("Shared capture session only supports this method"
+ + " for primary clients");
+ }
+
+ @Override
+ public void stopRepeating() throws CameraAccessException {
+ if (mIsPrimary) {
+ mSessionImpl.stopRepeating();
+ }
+ }
+
+ @Override
+ public int capture(CaptureRequest request, CaptureCallback listener, Handler handler)
+ throws CameraAccessException {
+ if (mIsPrimary) {
+ return mSessionImpl.capture(request, listener, handler);
+ }
+ throw new UnsupportedOperationException("Shared capture session only supports this method"
+ + " for primary clients");
+ }
+
+ @Override
+ public void tearDown(Surface surface) throws CameraAccessException {
+ mSessionImpl.tearDown(surface);
+ }
+
+ @Override
+ public CameraDevice getDevice() {
+ return mSessionImpl.getDevice();
+ }
+
+ @Override
+ public boolean isAborting() {
+ return mSessionImpl.isAborting();
+ }
+
+ @Override
+ public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() {
+ return mSessionImpl.getDeviceStateCallback();
+ }
+
+ @Override
+ public void replaceSessionClose() {
+ mSessionImpl.replaceSessionClose();
+ }
+
+ @Override
+ public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback listener,
+ Handler handler) throws CameraAccessException {
+ throw new UnsupportedOperationException("Shared Capture session doesn't support"
+ + " this method");
+ }
+
+ @Override
+ public int captureBurst(List<CaptureRequest> requests, CaptureCallback listener,
+ Handler handler) throws CameraAccessException {
+ throw new UnsupportedOperationException("Shared Capture session doesn't support"
+ + " this method");
+ }
+
+ @Override
+ public void updateOutputConfiguration(OutputConfiguration config)
+ throws CameraAccessException {
+ throw new UnsupportedOperationException("Shared capture session doesn't support"
+ + " this method");
+ }
+
+ @Override
+ public void finalizeOutputConfigurations(List<OutputConfiguration> deferredOutputConfigs)
+ throws CameraAccessException {
+ throw new UnsupportedOperationException("Shared capture session doesn't support"
+ + " this method");
+ }
+
+ @Override
+ public void prepare(Surface surface) throws CameraAccessException {
+ throw new UnsupportedOperationException("Shared capture session doesn't support"
+ + " this method");
+ }
+
+ @Override
+ public void prepare(int maxCount, Surface surface) throws CameraAccessException {
+ throw new UnsupportedOperationException("Shared capture session doesn't support"
+ + " this method");
+ }
+
+ @Override
+ public void closeWithoutDraining() {
+ throw new UnsupportedOperationException("Shared capture session doesn't support"
+ + " this method");
+ }
+
+ private class WrapperCallback extends StateCallback {
+ private final StateCallback mCallback;
+
+ WrapperCallback(StateCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ mInitialized.block();
+ mCallback.onConfigured(CameraSharedCaptureSessionImpl.this);
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ mInitialized.block();
+ mCallback.onConfigureFailed(CameraSharedCaptureSessionImpl.this);
+ }
+
+ @Override
+ public void onReady(CameraCaptureSession session) {
+ mCallback.onReady(CameraSharedCaptureSessionImpl.this);
+ }
+
+ @Override
+ public void onActive(CameraCaptureSession session) {
+ mCallback.onActive(CameraSharedCaptureSessionImpl.this);
+ }
+
+ @Override
+ public void onCaptureQueueEmpty(CameraCaptureSession session) {
+ mCallback.onCaptureQueueEmpty(CameraSharedCaptureSessionImpl.this);
+ }
+
+ @Override
+ public void onClosed(CameraCaptureSession session) {
+ mCallback.onClosed(CameraSharedCaptureSessionImpl.this);
+ }
+
+ @Override
+ public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
+ mCallback.onSurfacePrepared(CameraSharedCaptureSessionImpl.this,
+ surface);
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index aec2cff61d99..831c75ec5d33 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -301,4 +301,16 @@ public class ICameraDeviceUserWrapper {
}
}
+ /**
+ * API to check if the client is primary client when camera device is opened in shared mode.
+ */
+ public boolean isPrimaryClient() throws CameraAccessException {
+ try {
+ return mRemoteDevice.isPrimaryClient();
+ } catch (ServiceSpecificException e) {
+ throw ExceptionUtils.throwAsPublicException(e);
+ } catch (RemoteException e) {
+ throw ExceptionUtils.throwAsPublicException(e);
+ }
+ }
}
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index d38be9b7b694..e12c46322d8c 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -29,6 +29,7 @@ import android.annotation.TestApi;
import android.graphics.ColorSpace;
import android.graphics.ImageFormat;
import android.graphics.ImageFormat.Format;
+import android.hardware.DataSpace.NamedDataSpace;
import android.hardware.HardwareBuffer;
import android.hardware.HardwareBuffer.Usage;
import android.hardware.camera2.CameraCaptureSession;
@@ -1729,6 +1730,79 @@ public final class OutputConfiguration implements Parcelable {
}
/**
+ * Get the configured format associated with this {@link OutputConfiguration}.
+ *
+ * @return {@link android.graphics.ImageFormat#Format} associated with this
+ * {@link OutputConfiguration}.
+ *
+ * @hide
+ */
+ public @Format int getConfiguredFormat() {
+ return mConfiguredFormat;
+ }
+
+ /**
+ * Get the usage flag associated with this {@link OutputConfiguration}.
+ *
+ * @return {@link HardwareBuffer#Usage} associated with this {@link OutputConfiguration}.
+ *
+ * @hide
+ */
+ public @Usage long getUsage() {
+ return mUsage;
+ }
+
+ /**
+ * Get the surface type associated with this {@link OutputConfiguration}.
+ *
+ * @return The surface type associated with this {@link OutputConfiguration}.
+ *
+ * @see #SURFACE_TYPE_SURFACE_VIEW
+ * @see #SURFACE_TYPE_SURFACE_TEXTURE
+ * @see #SURFACE_TYPE_MEDIA_RECORDER
+ * @see #SURFACE_TYPE_MEDIA_CODEC
+ * @see #SURFACE_TYPE_IMAGE_READER
+ * @see #SURFACE_TYPE_UNKNOWN
+ * @hide
+ */
+ public int getSurfaceType() {
+ return mSurfaceType;
+ }
+
+ /**
+ * Get the sensor pixel modes associated with this {@link OutputConfiguration}.
+ *
+ * @return List of {@link #SensorPixelMode} associated with this {@link OutputConfiguration}.
+ *
+ * @hide
+ */
+ public @NonNull List<Integer> getSensorPixelModes() {
+ return mSensorPixelModesUsed;
+ }
+
+ /**
+ * Get the sharing mode associated with this {@link OutputConfiguration}.
+ *
+ * @return true if surface sharing is enabled with this {@link OutputConfiguration}.
+ *
+ * @hide
+ */
+ public boolean isShared() {
+ return mIsShared;
+ }
+
+ /**
+ * Get the dataspace associated with this {@link OutputConfiguration}.
+ *
+ * @return {@link Dataspace#NamedDataSpace} for this {@link OutputConfiguration}.
+ *
+ * @hide
+ */
+ public @NamedDataSpace int getConfiguredDataspace() {
+ return mConfiguredDataspace;
+ }
+
+ /**
* Get the physical camera ID associated with this {@link OutputConfiguration}.
*
* <p>If this OutputConfiguration isn't targeting a physical camera of a logical
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 50c6b5b8b995..82aa64b1474c 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -23,6 +23,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.graphics.ColorSpace;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@@ -78,6 +79,19 @@ public final class SessionConfiguration implements Parcelable {
CameraDevice.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED;
/**
+ * A shared session type containing instances of {@link OutputConfiguration} from a set of
+ * predefined stream configurations. A shared session can be shared among multiple clients.
+ * Shared session does not have any {@link InputConfiguration} as it does not support
+ * reprocessable sessions.
+ *
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+ @SystemApi
+ public static final int SESSION_SHARED = CameraDevice.SESSION_OPERATION_MODE_SHARED;
+
+ /**
* First vendor-specific session mode
* @hide
*/
diff --git a/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java
new file mode 100644
index 000000000000..cdcc92ce4404
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.graphics.ColorSpace;
+import android.graphics.ImageFormat.Format;
+import android.hardware.DataSpace.NamedDataSpace;
+import android.hardware.HardwareBuffer.Usage;
+import android.hardware.camera2.params.OutputConfiguration.MirrorMode;
+import android.hardware.camera2.params.OutputConfiguration.StreamUseCase;
+import android.hardware.camera2.params.OutputConfiguration.TimestampBase;
+import android.util.Log;
+import android.util.Size;
+
+import com.android.internal.camera.flags.Flags;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Immutable class to store the shared session configuration
+ * {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION} to set up
+ * {@link android.view.Surface Surfaces} for creating a
+ * {@link android.hardware.camera2.CameraSharedCaptureSession capture session} using
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)} and
+ * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED
+ * shared capture session} when camera has been opened in shared mode using
+ * {@link #openSharedCamera(String, Executor, StateCallback)}.
+ *
+ * <p>This is the authoritative list for all output configurations that are supported by a camera
+ * device when opened in shared mode.</p>
+ *
+ * <p>An instance of this object is available from {@link CameraCharacteristics} using
+ * the {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION} key and the
+ * {@link CameraCharacteristics#get} method.</p>
+ *
+ * <pre><code>{@code
+ * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ * StreamConfigurationMap configs = characteristics.get(
+ * CameraCharacteristics.SHARED_SESSION_CONFIGURATION);
+ * }</code></pre>
+ *
+ * @see CameraCharacteristics#SHARED_SESSION_CONFIGURATION
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
+ * @see SessionConfiguration#SESSION_SHARED
+ * @see CameraManager#openSharedCamera(String, Executor, StateCallback)
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+public final class SharedSessionConfiguration {
+ private static final String TAG = "SharedSessionConfiguration";
+ // Metadata android.info.availableSharedOutputConfigurations has list of shared output
+ // configurations. Each output configuration has minimum of 11 entries of size long
+ // followed by the physical camera id if present.
+ // See android.info.availableSharedOutputConfigurations for details.
+ private static final int SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES = 11;
+ /**
+ * Immutable class to store shared output stream information.
+ */
+ public static final class SharedOutputConfiguration {
+ private final int mSurfaceType;
+ private final Size mSize;
+ private final int mFormat;
+ private final int mDataspace;
+ private final long mStreamUseCase;
+ private String mPhysicalCameraId;
+ private final long mUsage;
+ private int mTimestampBase;
+ private int mMirrorMode;
+ private boolean mReadoutTimestampEnabled;
+
+ /**
+ * Create a new {@link SharedOutputConfiguration}.
+ *
+ * @param surfaceType Surface Type for this output configuration.
+ * @param sz Size for this output configuration.
+ * @param format {@link android.graphics.ImageFormat#Format} associated with this
+ * {@link OutputConfiguration}.
+ * @param mirrorMode {@link OutputConfiguration#MirrorMode} for this output configuration.
+ * @param readoutTimeStampEnabled Flag indicating whether readout timestamp is enabled
+ * for this output configuration.
+ * @param timestampBase {@link OutputConfiguration#TimestampBase} for this output
+ * configuration.
+ * @param dataspace {@link Dataspace#NamedDataSpace} for this output configuration.
+ * @param usage {@link HardwareBuffer#Usage} for this output configuration.
+ * @param streamUseCase {@link OutputConfiguration#StreamUseCase} for this output
+ * configuration.
+ * @param physicalCamId Physical Camera Id for this output configuration.
+ *
+ * @hide
+ */
+ public SharedOutputConfiguration(int surfaceType, @NonNull Size sz, @Format int format,
+ @MirrorMode int mirrorMode, boolean readoutTimeStampEnabled,
+ @TimestampBase int timestampBase, @NamedDataSpace int dataspace, @Usage long usage,
+ @StreamUseCase long streamUseCase, @Nullable String physicalCamId) {
+ mSurfaceType = surfaceType;
+ mSize = sz;
+ mFormat = format;
+ mMirrorMode = mirrorMode;
+ mReadoutTimestampEnabled = readoutTimeStampEnabled;
+ mTimestampBase = timestampBase;
+ mDataspace = dataspace;
+ mUsage = usage;
+ mStreamUseCase = streamUseCase;
+ mPhysicalCameraId = physicalCamId;
+ }
+
+ /**
+ * Returns the surface type configured for the shared output configuration.
+ * @return SURFACE_TYPE_UNKNOWN = -1
+ * SURFACE_TYPE_SURFACE_VIEW = 0
+ * SURFACE_TYPE_SURFACE_TEXTURE = 1
+ * SURFACE_TYPE_MEDIA_RECORDER = 2
+ * SURFACE_TYPE_MEDIA_CODEC = 3
+ * SURFACE_TYPE_IMAGE_READER = 4
+ */
+ public int getSurfaceType() {
+ return mSurfaceType;
+ }
+
+ /**
+ * Returns the format of the shared output configuration.
+ * @return format The format of the configured output. This must be one of the
+ * {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat}
+ * constants. Note that not all formats are supported by the camera device.
+ */
+ public @Format int getFormat() {
+ return mFormat;
+ }
+
+ /**
+ * Returns the configured size for the shared output configuration.
+ * @return surfaceSize Size for the shared output configuration
+ *
+ */
+ public @NonNull Size getSize() {
+ return mSize;
+ }
+
+ /**
+ * Return datatspace configured for the shared output configuration.
+ *
+ * @return {@link Dataspace#NamedDataSpace} configured for shared session
+ */
+ public @NamedDataSpace int getDataspace() {
+ return mDataspace;
+ }
+
+ /**
+ * Get the mirroring mode configured for the shared output configuration.
+ *
+ * @return {@link OutputConfiguration#MirrorMode} configured for the shared session
+ */
+ public @MirrorMode int getMirrorMode() {
+ return mMirrorMode;
+ }
+
+ /**
+ * Get the stream use case configured for the shared output configuration.
+ *
+ * @return {@link OutputConfiguration#StreamUseCase} configured for the shared session
+ */
+ public @StreamUseCase long getStreamUseCase() {
+ return mStreamUseCase;
+ }
+
+ /**
+ * Get the timestamp base configured for the shared output configuration.
+ *
+ * @return {@link OutputConfiguration#TimestampBase} configured for the shared session
+ */
+ public @TimestampBase int getTimestampBase() {
+ return mTimestampBase;
+ }
+
+ /** Whether readout timestamp is used for this shared output configuration.
+ *
+ */
+ public boolean isReadoutTimestampEnabled() {
+ return mReadoutTimestampEnabled;
+ }
+
+ /** Returns the usage if set for this shared output configuration.
+ *
+ * @return {@link HardwareBuffer#Usage} flags if set for shared output configuration with
+ * the ImageReader output surface.
+ */
+ public @Usage long getUsage() {
+ return mUsage;
+ }
+
+ public @Nullable String getPhysicalCameraId() {
+ return mPhysicalCameraId;
+ }
+ }
+
+ /**
+ * Create a new {@link SharedSessionConfiguration}.
+ *
+ * <p>The array parameters ownership is passed to this object after creation; do not
+ * write to them after this constructor is invoked.</p>
+ *
+ * @param sharedColorSpace the colorspace to be used for the shared output configurations.
+ * @param sharedOutputConfigurations a non-{@code null} array of metadata
+ * android.info.availableSharedOutputConfigurations
+ *
+ * @hide
+ */
+ public SharedSessionConfiguration(int sharedColorSpace,
+ @NonNull long[] sharedOutputConfigurations) {
+ mColorSpace = sharedColorSpace;
+ byte physicalCameraIdLen;
+ int surfaceType, width, height, format, mirrorMode, timestampBase, dataspace;
+ long usage, streamUseCase;
+ boolean isReadOutTimestampEnabled;
+ // Parse metadata android.info.availableSharedOutputConfigurations which contains
+ // list of shared output configurations.
+ int numOfEntries = sharedOutputConfigurations.length;
+ int i = 0;
+ while (numOfEntries >= SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES) {
+ surfaceType = (int) sharedOutputConfigurations[i];
+ width = (int) sharedOutputConfigurations[i + 1];
+ height = (int) sharedOutputConfigurations[i + 2];
+ format = (int) sharedOutputConfigurations[i + 3];
+ mirrorMode = (int) sharedOutputConfigurations[i + 4];
+ isReadOutTimestampEnabled = (sharedOutputConfigurations[i + 5] != 0);
+ timestampBase = (int) sharedOutputConfigurations[i + 6];
+ dataspace = (int) sharedOutputConfigurations[i + 7];
+ usage = sharedOutputConfigurations[i + 8];
+ streamUseCase = sharedOutputConfigurations[i + 9];
+ physicalCameraIdLen = (byte) sharedOutputConfigurations[i + 10];
+ numOfEntries -= SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES;
+ i += SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES;
+ if (numOfEntries < physicalCameraIdLen) {
+ Log.e(TAG, "Number of remaining data in shared configuration is less than"
+ + " physical camera id length . Malformed metadata"
+ + " android.info.availableSharedOutputConfigurations.");
+ break;
+ }
+ StringBuilder physicalCameraId = new StringBuilder();
+ long asciiValue;
+ for (int j = 0; j < physicalCameraIdLen; j++) {
+ asciiValue = sharedOutputConfigurations[i + j];
+ if (asciiValue == 0) { // Check for null terminator
+ break;
+ }
+ physicalCameraId.append((char) asciiValue);
+ }
+ SharedOutputConfiguration outputInfo;
+ outputInfo = new SharedOutputConfiguration(surfaceType, new Size(width, height),
+ format, mirrorMode, isReadOutTimestampEnabled, timestampBase,
+ dataspace, usage, streamUseCase, physicalCameraId.toString());
+ mOutputStreamConfigurations.add(outputInfo);
+ i += physicalCameraIdLen;
+ numOfEntries -= physicalCameraIdLen;
+ }
+ if (numOfEntries != 0) {
+ Log.e(TAG, "Unexpected entries left in shared output configuration."
+ + " Malformed metadata android.info.availableSharedOutputConfigurations.");
+ }
+ }
+
+ /**
+ * Return the shared session color space which is configured.
+ *
+ * @return the shared session color space
+ */
+ @SuppressLint("MethodNameUnits")
+ public @Nullable ColorSpace getColorSpace() {
+ if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
+ return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]);
+ } else {
+ return null;
+ }
+ }
+ /**
+ * Get information about each shared output configuarion in the shared session.
+ *
+ * @return Non-modifiable list of output configuration.
+ *
+ */
+ public @NonNull List<SharedOutputConfiguration> getOutputStreamsInformation() {
+ return Collections.unmodifiableList(mOutputStreamConfigurations);
+ }
+
+ private int mColorSpace;
+ private final ArrayList<SharedOutputConfiguration> mOutputStreamConfigurations =
+ new ArrayList<SharedOutputConfiguration>();
+}
+
diff --git a/core/java/android/hardware/contexthub/HubDiscoveryInfo.java b/core/java/android/hardware/contexthub/HubDiscoveryInfo.java
new file mode 100644
index 000000000000..581040dbfa56
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubDiscoveryInfo.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.hardware.location.ContextHubManager;
+
+/**
+ * Class that represents the result of from an hub endpoint discovery.
+ *
+ * <p>The type is returned from an endpoint discovery query via {@link
+ * ContextHubManager#findEndpoints}.
+ *
+ * <p>Application may use the values {@link #getHubEndpointInfo} to retrieve the {@link
+ * HubEndpointInfo} that describes the endpoint that matches the query.
+ *
+ * <p>Application may use the values {@link #getHubServiceInfo()} to retrieve the {@link
+ * HubServiceInfo} that describes the service that matches the query.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubDiscoveryInfo {
+ @NonNull private final HubEndpointInfo mEndpointInfo;
+ @Nullable private final HubServiceInfo mServiceInfo;
+
+ /** @hide */
+ public HubDiscoveryInfo(@NonNull HubEndpointInfo endpointInfo) {
+ mEndpointInfo = endpointInfo;
+ mServiceInfo = null;
+ }
+
+ /** @hide */
+ public HubDiscoveryInfo(
+ @NonNull HubEndpointInfo endpointInfo, @NonNull HubServiceInfo serviceInfo) {
+ mEndpointInfo = endpointInfo;
+ mServiceInfo = serviceInfo;
+ }
+
+ /** Get the {@link HubEndpointInfo} for the endpoint found. */
+ @NonNull
+ public HubEndpointInfo getHubEndpointInfo() {
+ return mEndpointInfo;
+ }
+
+ /**
+ * Get the {@link HubServiceInfo} for the endpoint found. The value will be null if there is no
+ * service info specified in the query.
+ */
+ @Nullable
+ public HubServiceInfo getHubServiceInfo() {
+ return mServiceInfo;
+ }
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java
new file mode 100644
index 000000000000..078b4d4629e0
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpoint.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.content.Context;
+import android.hardware.location.IContextHubService;
+import android.hardware.location.IContextHubTransactionCallback;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.annotation.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * An object representing an endpoint exposed to ContextHub and VendorHub. The object encapsulates
+ * the lifecycle and message callbacks for an endpoint.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubEndpoint {
+ private static final String TAG = "HubEndpoint";
+
+ private final Object mLock = new Object();
+ private final HubEndpointInfo mPendingHubEndpointInfo;
+ @Nullable private final IHubEndpointLifecycleCallback mLifecycleCallback;
+ @Nullable private final IHubEndpointMessageCallback mMessageCallback;
+ @NonNull private final Executor mLifecycleCallbackExecutor;
+ @NonNull private final Executor mMessageCallbackExecutor;
+
+ @GuardedBy("mLock")
+ private final SparseArray<HubEndpointSession> mActiveSessions = new SparseArray<>();
+
+ private final IContextHubEndpointCallback mServiceCallback =
+ new IContextHubEndpointCallback.Stub() {
+ @Override
+ public void onSessionOpenRequest(
+ int sessionId,
+ HubEndpointInfo initiator,
+ @Nullable HubServiceInfo serviceInfo)
+ throws RemoteException {
+ HubEndpointSession activeSession;
+ synchronized (mLock) {
+ activeSession = mActiveSessions.get(sessionId);
+ // TODO(b/378974199): Consider refactor these assertions
+ if (activeSession != null) {
+ Log.i(
+ TAG,
+ "onSessionOpenComplete: session already exists, id="
+ + sessionId);
+ return;
+ }
+ }
+
+ if (mLifecycleCallback != null) {
+ mLifecycleCallbackExecutor.execute(
+ () ->
+ processSessionOpenRequestResult(
+ sessionId,
+ initiator,
+ serviceInfo,
+ mLifecycleCallback.onSessionOpenRequest(
+ initiator, serviceInfo)));
+ }
+ }
+
+ private void processSessionOpenRequestResult(
+ int sessionId,
+ HubEndpointInfo initiator,
+ @Nullable HubServiceInfo serviceInfo,
+ HubEndpointSessionResult result) {
+ if (result == null) {
+ throw new IllegalArgumentException(
+ "HubEndpointSessionResult shouldn't be null.");
+ }
+
+ if (result.isAccepted()) {
+ acceptSession(sessionId, initiator, serviceInfo);
+ } else {
+ Log.i(
+ TAG,
+ "Session "
+ + sessionId
+ + " from "
+ + initiator
+ + " was rejected, reason="
+ + result.getReason());
+ rejectSession(sessionId);
+ }
+ }
+
+ private void acceptSession(
+ int sessionId,
+ HubEndpointInfo initiator,
+ @Nullable HubServiceInfo serviceInfo) {
+ if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
+ // No longer registered?
+ return;
+ }
+
+ // Retrieve the active session
+ HubEndpointSession activeSession;
+ synchronized (mLock) {
+ activeSession = mActiveSessions.get(sessionId);
+ // TODO(b/378974199): Consider refactor these assertions
+ if (activeSession != null) {
+ Log.e(
+ TAG,
+ "onSessionOpenRequestResult: session already exists, id="
+ + sessionId);
+ return;
+ }
+
+ activeSession =
+ new HubEndpointSession(
+ sessionId,
+ HubEndpoint.this,
+ mAssignedHubEndpointInfo,
+ initiator,
+ serviceInfo);
+ try {
+ // oneway call to notify system service that the request is completed
+ mServiceToken.openSessionRequestComplete(sessionId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "onSessionOpenRequestResult: ", e);
+ return;
+ }
+
+ mActiveSessions.put(sessionId, activeSession);
+ }
+
+ // Execute the callback
+ activeSession.setOpened();
+ if (mLifecycleCallback != null) {
+ final HubEndpointSession finalActiveSession = activeSession;
+ mLifecycleCallbackExecutor.execute(
+ () -> mLifecycleCallback.onSessionOpened(finalActiveSession));
+ }
+ }
+
+ private void rejectSession(int sessionId) {
+ if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
+ // No longer registered?
+ return;
+ }
+
+ try {
+ mServiceToken.closeSession(
+ sessionId,
+ IHubEndpointLifecycleCallback
+ .REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void onSessionOpenComplete(int sessionId) throws RemoteException {
+ final HubEndpointSession activeSession;
+
+ // Retrieve the active session
+ synchronized (mLock) {
+ activeSession = mActiveSessions.get(sessionId);
+ }
+ // TODO(b/378974199): Consider refactor these assertions
+ if (activeSession == null) {
+ Log.i(
+ TAG,
+ "onSessionOpenComplete: no pending session open request? id="
+ + sessionId);
+ return;
+ }
+
+ // Execute the callback
+ activeSession.setOpened();
+ if (mLifecycleCallback != null) {
+ mLifecycleCallbackExecutor.execute(
+ () -> mLifecycleCallback.onSessionOpened(activeSession));
+ }
+ }
+
+ @Override
+ public void onSessionClosed(int sessionId, int reason) throws RemoteException {
+ final HubEndpointSession activeSession;
+
+ // Retrieve the active session
+ synchronized (mLock) {
+ activeSession = mActiveSessions.get(sessionId);
+ }
+ // TODO(b/378974199): Consider refactor these assertions
+ if (activeSession == null) {
+ Log.i(TAG, "onSessionClosed: session not active, id=" + sessionId);
+ return;
+ }
+
+ // Execute the callback
+ if (mLifecycleCallback != null) {
+ mLifecycleCallbackExecutor.execute(
+ () -> {
+ mLifecycleCallback.onSessionClosed(activeSession, reason);
+
+ // Remove the session object first to call
+ activeSession.setClosed();
+ synchronized (mLock) {
+ mActiveSessions.remove(sessionId);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onMessageReceived(int sessionId, HubMessage message)
+ throws RemoteException {
+ final HubEndpointSession activeSession;
+
+ // Retrieve the active session
+ synchronized (mLock) {
+ activeSession = mActiveSessions.get(sessionId);
+ }
+ if (activeSession == null) {
+ Log.i(TAG, "onMessageReceived: session not active, id=" + sessionId);
+ }
+
+ if (activeSession == null || mMessageCallback == null) {
+ if (message.getDeliveryParams().isResponseRequired()) {
+ try {
+ mServiceToken.sendMessageDeliveryStatus(
+ sessionId,
+ message.getMessageSequenceNumber(),
+ ErrorCode.DESTINATION_NOT_FOUND);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ return;
+ }
+
+ // Execute the callback
+ mMessageCallbackExecutor.execute(
+ () -> {
+ mMessageCallback.onMessageReceived(activeSession, message);
+ if (message.getDeliveryParams().isResponseRequired()) {
+ try {
+ mServiceToken.sendMessageDeliveryStatus(
+ sessionId,
+ message.getMessageSequenceNumber(),
+ ErrorCode.OK);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ });
+ }
+ };
+
+ /** Binder returned from system service, non-null while registered. */
+ @Nullable private IContextHubEndpoint mServiceToken;
+
+ /** HubEndpointInfo with the assigned endpoint id from system service. */
+ @Nullable private HubEndpointInfo mAssignedHubEndpointInfo;
+
+ private HubEndpoint(
+ @NonNull HubEndpointInfo pendingEndpointInfo,
+ @Nullable IHubEndpointLifecycleCallback endpointLifecycleCallback,
+ @NonNull Executor lifecycleCallbackExecutor,
+ @Nullable IHubEndpointMessageCallback endpointMessageCallback,
+ @NonNull Executor messageCallbackExecutor) {
+ mPendingHubEndpointInfo = pendingEndpointInfo;
+
+ mLifecycleCallback = endpointLifecycleCallback;
+ mLifecycleCallbackExecutor = lifecycleCallbackExecutor;
+ mMessageCallback = endpointMessageCallback;
+ mMessageCallbackExecutor = messageCallbackExecutor;
+ }
+
+ /** @hide */
+ public void register(IContextHubService service) {
+ // TODO(b/378974199): Consider refactor these assertions
+ if (mServiceToken != null) {
+ // Already registered
+ return;
+ }
+ try {
+ IContextHubEndpoint serviceToken =
+ service.registerEndpoint(mPendingHubEndpointInfo, mServiceCallback);
+ mAssignedHubEndpointInfo = serviceToken.getAssignedHubEndpointInfo();
+ mServiceToken = serviceToken;
+ } catch (RemoteException e) {
+ Log.e(TAG, "registerEndpoint: failed to register endpoint", e);
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void unregister() {
+ IContextHubEndpoint serviceToken = mServiceToken;
+ // TODO(b/378974199): Consider refactor these assertions
+ if (serviceToken == null) {
+ // Not yet registered
+ return;
+ }
+
+ try {
+ synchronized (mLock) {
+ // Don't call HubEndpointSession.close() here.
+ for (int i = 0; i < mActiveSessions.size(); i++) {
+ mActiveSessions.get(mActiveSessions.keyAt(i)).setClosed();
+ }
+ mActiveSessions.clear();
+ }
+ mServiceToken.unregister();
+ } catch (RemoteException e) {
+ Log.e(TAG, "unregisterEndpoint: failed to unregister endpoint", e);
+ e.rethrowFromSystemServer();
+ } finally {
+ mServiceToken = null;
+ mAssignedHubEndpointInfo = null;
+ }
+ }
+
+ /** @hide */
+ public void openSession(HubEndpointInfo destinationInfo, @Nullable HubServiceInfo serviceInfo) {
+ // TODO(b/378974199): Consider refactor these assertions
+ if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
+ // No longer registered?
+ return;
+ }
+
+ HubEndpointSession newSession;
+ try {
+ // Request system service to assign session id.
+ int sessionId = mServiceToken.openSession(destinationInfo, serviceInfo);
+
+ // Save the newly created session
+ synchronized (mLock) {
+ newSession =
+ new HubEndpointSession(
+ sessionId,
+ HubEndpoint.this,
+ destinationInfo,
+ mAssignedHubEndpointInfo,
+ serviceInfo);
+ mActiveSessions.put(sessionId, newSession);
+ }
+ } catch (RemoteException e) {
+ // Move this to toString
+ Log.e(TAG, "openSession: failed to open session to " + destinationInfo, e);
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void closeSession(HubEndpointSession session) {
+ IContextHubEndpoint serviceToken = mServiceToken;
+ // TODO(b/378974199): Consider refactor these assertions
+ if (serviceToken == null || mAssignedHubEndpointInfo == null) {
+ // Not registered
+ return;
+ }
+
+ synchronized (mLock) {
+ if (!mActiveSessions.contains(session.getId())) {
+ // Already closed?
+ return;
+ }
+ session.setClosed();
+ mActiveSessions.remove(session.getId());
+ }
+
+ try {
+ // Oneway notification to system service
+ serviceToken.closeSession(
+ session.getId(),
+ IHubEndpointLifecycleCallback.REASON_CLOSE_ENDPOINT_SESSION_REQUESTED);
+ } catch (RemoteException e) {
+ Log.e(TAG, "closeSession: failed to close session " + session, e);
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ void sendMessage(
+ HubEndpointSession session,
+ HubMessage message,
+ @Nullable IContextHubTransactionCallback transactionCallback) {
+ IContextHubEndpoint serviceToken = mServiceToken;
+ if (serviceToken == null) {
+ // Not registered
+ return;
+ }
+
+ try {
+ serviceToken.sendMessage(session.getId(), message, transactionCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendMessage: failed to send message session=" + session, e);
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ public int getVersion() {
+ return mPendingHubEndpointInfo.getVersion();
+ }
+
+ @Nullable
+ public String getTag() {
+ return mPendingHubEndpointInfo.getTag();
+ }
+
+ @NonNull
+ public Collection<HubServiceInfo> getServiceInfoCollection() {
+ return mPendingHubEndpointInfo.getServiceInfoCollection();
+ }
+
+ @Nullable
+ public IHubEndpointLifecycleCallback getLifecycleCallback() {
+ return mLifecycleCallback;
+ }
+
+ @Nullable
+ public IHubEndpointMessageCallback getMessageCallback() {
+ return mMessageCallback;
+ }
+
+ /** Builder for a {@link HubEndpoint} object. */
+ public static final class Builder {
+ private final String mPackageName;
+
+ @Nullable private IHubEndpointLifecycleCallback mLifecycleCallback;
+
+ @NonNull private Executor mLifecycleCallbackExecutor;
+
+ @Nullable private IHubEndpointMessageCallback mMessageCallback;
+ @NonNull private Executor mMessageCallbackExecutor;
+
+ private int mVersion;
+ @Nullable private String mTag;
+
+ private List<HubServiceInfo> mServiceInfos = Collections.emptyList();
+
+ /** Create a builder for {@link HubEndpoint} */
+ public Builder(@NonNull Context context) {
+ mPackageName = context.getPackageName();
+ mVersion = (int) context.getApplicationInfo().longVersionCode;
+ mLifecycleCallbackExecutor = context.getMainExecutor();
+ mMessageCallbackExecutor = context.getMainExecutor();
+ }
+
+ /**
+ * Set the version for the endpoint. Default is 0.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setVersion(int version) {
+ mVersion = version;
+ return this;
+ }
+
+ /**
+ * Set a tag string. The tag can be used to further identify the creator of the endpoint.
+ * Endpoints created by the same package share the same name but should have different tags.
+ */
+ @NonNull
+ public Builder setTag(@NonNull String tag) {
+ mTag = tag;
+ return this;
+ }
+
+ /** Attach a callback interface for lifecycle events for this Endpoint */
+ @NonNull
+ public Builder setLifecycleCallback(
+ @NonNull IHubEndpointLifecycleCallback lifecycleCallback) {
+ mLifecycleCallback = lifecycleCallback;
+ return this;
+ }
+
+ /**
+ * Attach a callback interface for lifecycle events for this Endpoint with a specified
+ * executor
+ */
+ @NonNull
+ public Builder setLifecycleCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull IHubEndpointLifecycleCallback lifecycleCallback) {
+ mLifecycleCallbackExecutor = executor;
+ mLifecycleCallback = lifecycleCallback;
+ return this;
+ }
+
+ /** Attach a callback interface for message events for this Endpoint */
+ @NonNull
+ public Builder setMessageCallback(@NonNull IHubEndpointMessageCallback messageCallback) {
+ mMessageCallback = messageCallback;
+ return this;
+ }
+
+ /**
+ * Attach a callback interface for message events for this Endpoint with a specified
+ * executor
+ */
+ @NonNull
+ public Builder setMessageCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull IHubEndpointMessageCallback messageCallback) {
+ mMessageCallbackExecutor = executor;
+ mMessageCallback = messageCallback;
+ return this;
+ }
+
+ /**
+ * Add a service to the available services from this endpoint. The {@link HubServiceInfo}
+ * object can be built with {@link HubServiceInfo.Builder}.
+ */
+ @NonNull
+ public Builder setServiceInfoCollection(
+ @NonNull Collection<HubServiceInfo> hubServiceInfos) {
+ // Make a copy first
+ mServiceInfos = new ArrayList<>(hubServiceInfos);
+ return this;
+ }
+
+ /** Build the {@link HubEndpoint} object. */
+ @NonNull
+ public HubEndpoint build() {
+ return new HubEndpoint(
+ new HubEndpointInfo(mPackageName, mVersion, mTag, mServiceInfos),
+ mLifecycleCallback,
+ mLifecycleCallbackExecutor,
+ mMessageCallback,
+ mMessageCallbackExecutor);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/verify/pkg/VerificationStatus.aidl b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl
index 6a1cb4f2d1d2..025b2b1f685a 100644
--- a/core/java/android/content/pm/verify/pkg/VerificationStatus.aidl
+++ b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.verify.pkg;
+package android.hardware.contexthub;
/** @hide */
-parcelable VerificationStatus;
+parcelable HubEndpointInfo;
diff --git a/core/java/android/hardware/contexthub/HubEndpointInfo.java b/core/java/android/hardware/contexthub/HubEndpointInfo.java
new file mode 100644
index 000000000000..5265d5663459
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointInfo.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Parcelable representing an endpoint from ContextHub or VendorHub.
+ *
+ * <p>HubEndpointInfo contains information about an endpoint, including its name, tag and other
+ * information. A HubEndpointInfo object can be used to accurately identify a specific endpoint.
+ * Application can use this object to identify and describe an endpoint.
+ *
+ * <p>See: {@link android.hardware.location.ContextHubManager#findEndpoints} for how to retrieve
+ * {@link HubEndpointInfo} for endpoints on a hub.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public final class HubEndpointInfo implements Parcelable {
+ /**
+ * A unique identifier for one endpoint. A unique identifier for one endpoint consists of two
+ * parts: (1) a unique long number for a hub and (2) a long number for the endpoint, unique
+ * within a hub. This class overrides equality methods and can be used to compare if two
+ * endpoints are the same.
+ */
+ public static class HubEndpointIdentifier {
+ private final long mEndpointId;
+ private final long mHubId;
+
+ /** @hide */
+ public HubEndpointIdentifier(long hubId, long endpointId) {
+ mEndpointId = endpointId;
+ mHubId = hubId;
+ }
+
+ /** @hide */
+ public HubEndpointIdentifier(android.hardware.contexthub.EndpointId halEndpointId) {
+ mEndpointId = halEndpointId.id;
+ mHubId = halEndpointId.hubId;
+ }
+
+ /** Get the endpoint portion of the identifier. */
+ public long getEndpoint() {
+ return mEndpointId;
+ }
+
+ /** Get the hub portion of the identifier. */
+ public long getHub() {
+ return mHubId;
+ }
+
+ /**
+ * Create an invalid endpoint id, to represent endpoint that are not yet registered with the
+ * HAL.
+ *
+ * @hide
+ */
+ public static HubEndpointIdentifier invalid() {
+ return new HubEndpointIdentifier(
+ android.hardware.contexthub.HubInfo.HUB_ID_INVALID,
+ android.hardware.contexthub.EndpointId.ENDPOINT_ID_INVALID);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEndpointId, mHubId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof HubEndpointIdentifier other)) {
+ return false;
+ }
+ if (other.mHubId != mHubId) {
+ return false;
+ }
+ return other.mEndpointId == mEndpointId;
+ }
+ }
+
+ /** This endpoint is from the Android framework */
+ public static final int TYPE_FRAMEWORK = 1;
+
+ /** This endpoint is from an Android app */
+ public static final int TYPE_APP = 2;
+
+ /** This endpoint is from an Android native program. */
+ public static final int TYPE_NATIVE = 3;
+
+ /** This endpoint is from a nanoapp. */
+ public static final int TYPE_NANOAPP = 4;
+
+ /** This endpoint is a generic endpoint served by a hub (not from a nanoapp). */
+ public static final int TYPE_HUB_ENDPOINT = 5;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TYPE_FRAMEWORK,
+ TYPE_APP,
+ TYPE_NATIVE,
+ TYPE_NANOAPP,
+ TYPE_HUB_ENDPOINT,
+ })
+ public @interface EndpointType {}
+
+ private final HubEndpointIdentifier mId;
+ @EndpointType private final int mType;
+ private final String mName;
+ private final int mVersion;
+ @Nullable private final String mTag;
+
+ @NonNull private final List<String> mRequiredPermissions;
+ @NonNull private final List<HubServiceInfo> mHubServiceInfos;
+
+ /** @hide */
+ public HubEndpointInfo(android.hardware.contexthub.EndpointInfo endpointInfo) {
+ mId = new HubEndpointIdentifier(endpointInfo.id.hubId, endpointInfo.id.id);
+ mType = endpointInfo.type;
+ mName = endpointInfo.name;
+ mVersion = endpointInfo.version;
+ mTag = endpointInfo.tag;
+ mRequiredPermissions = Arrays.asList(endpointInfo.requiredPermissions);
+ mHubServiceInfos = new ArrayList<>(endpointInfo.services.length);
+ for (int i = 0; i < endpointInfo.services.length; i++) {
+ mHubServiceInfos.add(new HubServiceInfo(endpointInfo.services[i]));
+ }
+ }
+
+ /** @hide */
+ public HubEndpointInfo(
+ String name,
+ int version,
+ @Nullable String tag,
+ @NonNull List<HubServiceInfo> hubServiceInfos) {
+ mId = HubEndpointIdentifier.invalid();
+ mType = TYPE_APP;
+ mName = name;
+ mVersion = version;
+ mTag = tag;
+ mRequiredPermissions = Collections.emptyList();
+ mHubServiceInfos = hubServiceInfos;
+ }
+
+ private HubEndpointInfo(Parcel in) {
+ long hubId = in.readLong();
+ long endpointId = in.readLong();
+ mId = new HubEndpointIdentifier(hubId, endpointId);
+ mType = in.readInt();
+ mName = in.readString();
+ mVersion = in.readInt();
+ mTag = in.readString();
+ mRequiredPermissions = new ArrayList<>();
+ in.readStringList(mRequiredPermissions);
+ mHubServiceInfos = new ArrayList<>();
+ in.readTypedList(mHubServiceInfos, HubServiceInfo.CREATOR);
+ }
+
+ /** Parcel implementation details */
+ @Override
+ public int describeContents() {
+ int flags = 0;
+ for (HubServiceInfo serviceInfo : mHubServiceInfos) {
+ flags |= serviceInfo.describeContents();
+ }
+ return flags;
+ }
+
+ /** Parcel implementation details */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeLong(mId.getHub());
+ dest.writeLong(mId.getEndpoint());
+ dest.writeInt(mType);
+ dest.writeString(mName);
+ dest.writeInt(mVersion);
+ dest.writeString(mTag);
+ dest.writeStringList(mRequiredPermissions);
+ dest.writeTypedList(mHubServiceInfos, flags);
+ }
+
+ /** Get a unique identifier for this endpoint. */
+ @NonNull
+ public HubEndpointIdentifier getIdentifier() {
+ return mId;
+ }
+
+ /**
+ * Get the type of this endpoint. Application may use this field to get more information about
+ * who registered this endpoint for diagnostic purposes.
+ *
+ * <p>Type can be one of {@link HubEndpointInfo#TYPE_APP}, {@link
+ * HubEndpointInfo#TYPE_FRAMEWORK}, {@link HubEndpointInfo#TYPE_NANOAPP}, {@link
+ * HubEndpointInfo#TYPE_NATIVE} or {@link HubEndpointInfo#TYPE_HUB_ENDPOINT}.
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /** Get the human-readable name of this endpoint (for debugging purposes). */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Get the version of this endpoint.
+ *
+ * <p>Monotonically increasing version number. The two sides of an endpoint session can use this
+ * version number to identify the other side and determine compatibility with each other. The
+ * interpretation of the version number is specific to the implementation of an endpoint.
+ *
+ * <p>The version number should not be used to compare endpoints implementation freshness for
+ * different endpoint types.
+ *
+ * <p>Depending on type of the endpoint, the following values (and formats) are used:
+ *
+ * <ol>
+ * <li>{@link #TYPE_FRAMEWORK}: android.os.Build.VERSION.SDK_INT_FULL
+ * <li>{@link #TYPE_APP}: versionCode
+ * <li>{@link #TYPE_NATIVE}: unspecified format (supplied by endpoint code)
+ * <li>{@link #TYPE_NANOAPP}: nanoapp version, typically following 0xMMmmpppp scheme where MM
+ * = major version, mm = minor version, pppp = patch version
+ * <li>{@link #TYPE_HUB_ENDPOINT}: unspecified format (supplied by endpoint code), following
+ * nanoapp versioning scheme is recommended
+ * </ol>
+ */
+ public int getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Get the tag that further identifies the submodule that created this endpoint. For example, a
+ * single application could provide multiple endpoints. These endpoints will share the same
+ * name, but will have different tags. This tag can be used to identify the submodule within the
+ * application that provided the endpoint.
+ */
+ @Nullable
+ public String getTag() {
+ return mTag;
+ }
+
+ /**
+ * Get the list of required permissions in order to talk to this endpoint.
+ *
+ * <p>This list is enforced by the Context Hub Service. The app would need to have the required
+ * permissions list to open a session with this particular endpoint. Otherwise this will be
+ * rejected by as permission failures.
+ *
+ * <p>This is mostly for allowing app to check what permission it needs first internally. App
+ * will need to request permissions grant at runtime if not already granted. See {@link
+ * android.content.Context#checkPermission} for more details.
+ *
+ * <p>See {@link android.Manifest.permission} for a list of standard Android permissions as
+ * possible values.
+ */
+ @SuppressLint("RequiresPermission")
+ @NonNull
+ public Collection<String> getRequiredPermissions() {
+ return Collections.unmodifiableList(mRequiredPermissions);
+ }
+
+ /**
+ * Get the list of services provided by this endpoint.
+ *
+ * <p>See {@link HubServiceInfo} for more information.
+ */
+ @NonNull
+ public Collection<HubServiceInfo> getServiceInfoCollection() {
+ return Collections.unmodifiableList(mHubServiceInfos);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder out = new StringBuilder();
+ out.append("Endpoint [0x");
+ out.append(Long.toHexString(mId.getEndpoint()));
+ out.append("@ Hub 0x");
+ out.append(Long.toHexString(mId.getHub()));
+ out.append("] Name=");
+ out.append(mName);
+ out.append(", Tag=");
+ out.append(mTag);
+ return out.toString();
+ }
+
+ public static final @android.annotation.NonNull Creator<HubEndpointInfo> CREATOR =
+ new Creator<>() {
+ public HubEndpointInfo createFromParcel(Parcel in) {
+ return new HubEndpointInfo(in);
+ }
+
+ public HubEndpointInfo[] newArray(int size) {
+ return new HubEndpointInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java
new file mode 100644
index 000000000000..cf952cbdbfdc
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointSession.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.hardware.location.ContextHubTransaction;
+import android.hardware.location.ContextHubTransactionHelper;
+import android.hardware.location.IContextHubTransactionCallback;
+import android.util.CloseGuard;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * An object representing a communication session between two different hub endpoints.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubEndpointSession implements AutoCloseable {
+ private final CloseGuard mCloseGuard = new CloseGuard();
+
+ private final int mId;
+
+ @NonNull private final HubEndpoint mHubEndpoint;
+ @NonNull private final HubEndpointInfo mInitiator;
+ @NonNull private final HubEndpointInfo mDestination;
+ @Nullable private final HubServiceInfo mServiceInfo;
+
+ private final AtomicBoolean mIsClosed = new AtomicBoolean(true);
+
+ /** @hide */
+ HubEndpointSession(
+ int id,
+ @NonNull HubEndpoint hubEndpoint,
+ @NonNull HubEndpointInfo destination,
+ @NonNull HubEndpointInfo initiator,
+ @Nullable HubServiceInfo serviceInfo) {
+ mId = id;
+ mHubEndpoint = hubEndpoint;
+ mDestination = destination;
+ mInitiator = initiator;
+ mServiceInfo = serviceInfo;
+ }
+
+ /**
+ * Send a message to the peer endpoint in this session.
+ *
+ * @param message The message object constructed with {@link HubMessage#createMessage}.
+ * @return For messages that does not require a response, the transaction will immediately
+ * complete. For messages that requires a response, the transaction will complete after
+ * receiving the response for the message.
+ */
+ @NonNull
+ public ContextHubTransaction<Void> sendMessage(@NonNull HubMessage message) {
+ if (mIsClosed.get()) {
+ throw new IllegalStateException("Session is already closed.");
+ }
+
+ boolean isResponseRequired = message.getDeliveryParams().isResponseRequired();
+ ContextHubTransaction<Void> ret =
+ new ContextHubTransaction<>(
+ isResponseRequired
+ ? ContextHubTransaction.TYPE_HUB_MESSAGE_REQUIRES_RESPONSE
+ : ContextHubTransaction.TYPE_HUB_MESSAGE_DEFAULT);
+ if (!isResponseRequired) {
+ // If the message doesn't require acknowledgement, respond with success immediately
+ // TODO(b/379162322): Improve handling of synchronous failures.
+ mHubEndpoint.sendMessage(this, message, null);
+ ret.setResponse(
+ new ContextHubTransaction.Response<>(
+ ContextHubTransaction.RESULT_SUCCESS, null));
+ } else {
+ IContextHubTransactionCallback callback =
+ ContextHubTransactionHelper.createTransactionCallback(ret);
+ // Sequence number will be assigned at the service
+ mHubEndpoint.sendMessage(this, message, callback);
+ }
+ return ret;
+ }
+
+ /** @hide */
+ public int getId() {
+ return mId;
+ }
+
+ /** @hide */
+ public void setOpened() {
+ mIsClosed.set(false);
+ mCloseGuard.open("close");
+ }
+
+ /** @hide */
+ public void setClosed() {
+ mIsClosed.set(true);
+ mCloseGuard.close();
+ }
+
+ /**
+ * Closes the connection for this session between an endpoint and the Context Hub Service.
+ *
+ * <p>When this function is invoked, the messaging associated with this session is invalidated.
+ * All futures messages targeted for this client are dropped.
+ */
+ public void close() {
+ if (!mIsClosed.getAndSet(true)) {
+ mCloseGuard.close();
+ mHubEndpoint.closeSession(this);
+ }
+ }
+
+ /**
+ * Get the {@link HubServiceInfo} associated with this session. Null value indicates that there
+ * is no service associated to this session.
+ *
+ * <p>For hub initiated sessions, the object was previously used in as an argument for open
+ * request in {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}.
+ *
+ * <p>For app initiated sessions, the object was previously used in an open request in {@link
+ * android.hardware.location.ContextHubManager#openSession}
+ */
+ @Nullable
+ public HubServiceInfo getServiceInfo() {
+ return mServiceInfo;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Session [");
+ stringBuilder.append(mId);
+ stringBuilder.append("]: [");
+ stringBuilder.append(mInitiator);
+ stringBuilder.append("]->[");
+ stringBuilder.append(mDestination);
+ stringBuilder.append("]");
+ return stringBuilder.toString();
+ }
+
+ /** @hide */
+ protected void finalize() throws Throwable {
+ try {
+ // Note that guard could be null if the constructor threw.
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpointSessionResult.java b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java
new file mode 100644
index 000000000000..1f2bdb985008
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+
+/**
+ * Return type of {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}. The value determines
+ * whether a open session request from the remote is accepted or not.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubEndpointSessionResult {
+ private final boolean mAccepted;
+
+ @Nullable private final String mReason;
+
+ private HubEndpointSessionResult(boolean accepted, @Nullable String reason) {
+ mAccepted = accepted;
+ mReason = reason;
+ }
+
+ /**
+ * Retrieve the decision of the session request.
+ *
+ * @return Whether a session request was accepted or not, previously set with {@link #accept()}
+ * or {@link #reject(String)}.
+ */
+ public boolean isAccepted() {
+ return mAccepted;
+ }
+
+ /**
+ * Retrieve the decision of the session request.
+ *
+ * @return The reason previously set in {@link #reject(String)}. If the result was {@link
+ * #accept()}, the reason will be null.
+ */
+ @Nullable
+ public String getReason() {
+ return mReason;
+ }
+
+ /** Accept the request. */
+ @NonNull
+ public static HubEndpointSessionResult accept() {
+ return new HubEndpointSessionResult(true, null);
+ }
+
+ /**
+ * Reject the request with a reason.
+ *
+ * @param reason Reason why the request was rejected, for diagnostic purposes.
+ */
+ @NonNull
+ public static HubEndpointSessionResult reject(@NonNull String reason) {
+ return new HubEndpointSessionResult(false, reason);
+ }
+}
diff --git a/core/java/android/hardware/contexthub/HubMessage.aidl b/core/java/android/hardware/contexthub/HubMessage.aidl
new file mode 100644
index 000000000000..86afce233062
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubMessage.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+/**
+ * @hide
+ */
+parcelable HubMessage;
diff --git a/core/java/android/hardware/contexthub/HubMessage.java b/core/java/android/hardware/contexthub/HubMessage.java
new file mode 100644
index 000000000000..dc8a8c52ea55
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubMessage.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import libcore.util.HexEncoding;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A class describing general messages send through the Context Hub Service.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public final class HubMessage implements Parcelable {
+ private static final int DEBUG_LOG_NUM_BYTES = 16;
+
+ private final int mMessageType;
+ private final byte[] mMessageBody;
+
+ private final DeliveryParams mDeliveryParams;
+ private int mMessageSequenceNumber;
+
+ /**
+ * Configurable options for message delivery. This option can be passed into {@link
+ * HubEndpointSession#sendMessage} to specify the behavior of message delivery.
+ */
+ public static class DeliveryParams {
+ private boolean mResponseRequired;
+
+ private DeliveryParams(boolean responseRequired) {
+ mResponseRequired = responseRequired;
+ }
+
+ /** Get the acknowledgement requirement. */
+ public boolean isResponseRequired() {
+ return mResponseRequired;
+ }
+
+ /**
+ * Set the response requirement for a message. Message sent with this option will have a
+ * {@link android.hardware.location.ContextHubTransaction.Response} when the peer received
+ * the message. Default is false.
+ */
+ @NonNull
+ public DeliveryParams setResponseRequired(boolean required) {
+ mResponseRequired = required;
+ return this;
+ }
+
+ /** Construct a default delivery option. */
+ @NonNull
+ public static DeliveryParams makeBasic() {
+ return new DeliveryParams(false);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder out = new StringBuilder();
+ out.append("DeliveryParams[");
+ out.append("responseRequired = ").append(mResponseRequired);
+ out.append("]");
+ return out.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mResponseRequired);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj instanceof DeliveryParams other) {
+ return other.mResponseRequired == mResponseRequired;
+ }
+
+ return false;
+ }
+ }
+
+ private HubMessage(int messageType, byte[] messageBody, DeliveryParams deliveryParams) {
+ mMessageType = messageType;
+ mMessageBody = messageBody;
+ mDeliveryParams = deliveryParams;
+ }
+
+ /**
+ * Creates a HubMessage object to send to through an endpoint.
+ *
+ * @param messageType the endpoint & service dependent message type
+ * @param messageBody the byte array message contents
+ * @return the HubMessage object
+ */
+ @NonNull
+ public static HubMessage createMessage(int messageType, @NonNull byte[] messageBody) {
+ return new HubMessage(messageType, messageBody, DeliveryParams.makeBasic());
+ }
+
+ /**
+ * Creates a HubMessage object to send to through an endpoint.
+ *
+ * @param messageType the endpoint & service dependent message type
+ * @param messageBody the byte array message contents
+ * @param deliveryParams The message delivery parameters. See {@link HubMessage.DeliveryParams}
+ * for more details.
+ * @return the HubMessage object
+ */
+ @NonNull
+ public static HubMessage createMessage(
+ int messageType, @NonNull byte[] messageBody, @NonNull DeliveryParams deliveryParams) {
+ return new HubMessage(messageType, messageBody, deliveryParams);
+ }
+
+ /**
+ * Retrieve the message type.
+ *
+ * @return the type of the message
+ */
+ public int getMessageType() {
+ return mMessageType;
+ }
+
+ /**
+ * Retrieve the body of the message. The body can be an empty byte array.
+ *
+ * @return the byte array contents of the message
+ */
+ @NonNull
+ public byte[] getMessageBody() {
+ return mMessageBody;
+ }
+
+ /**
+ * Retrieve the {@link DeliveryParams} object specifying the behavior of message delivery.
+ *
+ * @hide
+ */
+ public DeliveryParams getDeliveryParams() {
+ return mDeliveryParams;
+ }
+
+ /**
+ * Assign a message sequence number. This should only be called by the system service.
+ *
+ * @hide
+ */
+ public void setMessageSequenceNumber(int messageSequenceNumber) {
+ mMessageSequenceNumber = messageSequenceNumber;
+ }
+
+ /**
+ * Returns the message sequence number. The default value is 0.
+ *
+ * @return the message sequence number of the message
+ * @hide
+ */
+ public int getMessageSequenceNumber() {
+ return mMessageSequenceNumber;
+ }
+
+ private HubMessage(@NonNull Parcel in) {
+ mMessageType = in.readInt();
+
+ int msgSize = in.readInt();
+ mMessageBody = new byte[msgSize];
+ in.readByteArray(mMessageBody);
+
+ mDeliveryParams = DeliveryParams.makeBasic();
+ mDeliveryParams.setResponseRequired(in.readInt() == 1);
+ mMessageSequenceNumber = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mMessageType);
+
+ out.writeInt(mMessageBody.length);
+ out.writeByteArray(mMessageBody);
+
+ out.writeInt(mDeliveryParams.isResponseRequired() ? 1 : 0);
+ out.writeInt(mMessageSequenceNumber);
+ }
+
+ public static final @NonNull Creator<HubMessage> CREATOR =
+ new Creator<>() {
+ @Override
+ public HubMessage createFromParcel(Parcel in) {
+ return new HubMessage(in);
+ }
+
+ @Override
+ public HubMessage[] newArray(int size) {
+ return new HubMessage[size];
+ }
+ };
+
+ @NonNull
+ @Override
+ public String toString() {
+ int length = mMessageBody.length;
+
+ StringBuilder out = new StringBuilder();
+ out.append("HubMessage[type = ").append(mMessageType);
+ out.append(", length = ").append(mMessageBody.length);
+ out.append(", messageSequenceNumber = ").append(mMessageSequenceNumber);
+ out.append(", deliveryParams = ").append(mDeliveryParams);
+ out.append("](");
+
+ if (length > 0) {
+ out.append("data = 0x");
+ }
+ for (int i = 0; i < Math.min(length, DEBUG_LOG_NUM_BYTES); i++) {
+ out.append(HexEncoding.encodeToString(mMessageBody[i], true /* upperCase */));
+
+ if ((i + 1) % 4 == 0) {
+ out.append(" ");
+ }
+ }
+ if (length > DEBUG_LOG_NUM_BYTES) {
+ out.append("...");
+ }
+ out.append(")");
+
+ return out.toString();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+
+ boolean isEqual = false;
+ if (object instanceof HubMessage other) {
+ isEqual =
+ (other.getMessageType() == mMessageType)
+ && Arrays.equals(other.getMessageBody(), mMessageBody)
+ && (other.getDeliveryParams().equals(mDeliveryParams))
+ && (other.getMessageSequenceNumber() == mMessageSequenceNumber);
+ }
+
+ return isEqual;
+ }
+
+ @Override
+ public int hashCode() {
+ if (!Flags.fixApiCheck()) {
+ return super.hashCode();
+ }
+
+ return Objects.hash(
+ mMessageType,
+ Arrays.hashCode(mMessageBody),
+ mDeliveryParams,
+ mMessageSequenceNumber);
+ }
+}
diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.aidl b/core/java/android/hardware/contexthub/HubServiceInfo.aidl
new file mode 100644
index 000000000000..98b1bbab8b60
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubServiceInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+/**
+ * @hide
+ */
+parcelable HubServiceInfo;
diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.java b/core/java/android/hardware/contexthub/HubServiceInfo.java
new file mode 100644
index 000000000000..a1c52fb5864f
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubServiceInfo.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * A class describing services provided by endpoints.
+ *
+ * <p>An endpoint can provide zero or more service. See {@link
+ * HubEndpoint.Builder#setServiceInfoCollection(Collection)} and {@link
+ * HubEndpointInfo#getServiceInfoCollection()}.
+ *
+ * <p>An endpoint session can be service-less or associated to one service.See {@link
+ * HubEndpointSession#getServiceInfo()}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public final class HubServiceInfo implements Parcelable {
+ /** Customized format for messaging. Fully customized and opaque messaging format. */
+ public static final int FORMAT_CUSTOM = 0;
+
+ /**
+ * Binder-based messaging. The host endpoint is defining this service in Stable AIDL. Messages
+ * between endpoints that uses this service will be using the binder marhsalling format.
+ */
+ public static final int FORMAT_AIDL = 1;
+
+ /**
+ * Pigweed RPC messaging with Protobuf. This endpoint is a Pigweed RPC. Messages between
+ * endpoints will use Pigweed RPC marshalling format (protobuf).
+ */
+ public static final int FORMAT_PW_RPC_PROTOBUF = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ FORMAT_CUSTOM,
+ FORMAT_AIDL,
+ FORMAT_PW_RPC_PROTOBUF,
+ })
+ public @interface ServiceFormat {}
+
+ @NonNull private final String mServiceDescriptor;
+
+ @ServiceFormat private final int mFormat;
+ private final int mMajorVersion;
+ private final int mMinorVersion;
+
+ /** @hide */
+ public HubServiceInfo(android.hardware.contexthub.Service service) {
+ mServiceDescriptor = service.serviceDescriptor;
+ mFormat = service.format;
+ mMajorVersion = service.majorVersion;
+ mMinorVersion = service.minorVersion;
+ }
+
+ private HubServiceInfo(Parcel in) {
+ mServiceDescriptor = Objects.requireNonNull(in.readString());
+ mFormat = in.readInt();
+ mMajorVersion = in.readInt();
+ mMinorVersion = in.readInt();
+ }
+
+ public HubServiceInfo(
+ @NonNull String serviceDescriptor,
+ @ServiceFormat int format,
+ int majorVersion,
+ int minorVersion) {
+ mServiceDescriptor = serviceDescriptor;
+ mFormat = format;
+ mMajorVersion = majorVersion;
+ mMinorVersion = minorVersion;
+ }
+
+ /** Get the unique identifier of this service. See {@link Builder} for more information. */
+ @NonNull
+ public String getServiceDescriptor() {
+ return mServiceDescriptor;
+ }
+
+ /**
+ * Get the type of the service.
+ *
+ * <p>The value can be one of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link
+ * HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}.
+ */
+ public int getFormat() {
+ return mFormat;
+ }
+
+ /** Get the major version of this service. */
+ public int getMajorVersion() {
+ return mMajorVersion;
+ }
+
+ /** Get the minor version of this service. */
+ public int getMinorVersion() {
+ return mMinorVersion;
+ }
+
+ /** Parcel implementation details */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Parcel implementation details */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mServiceDescriptor);
+ dest.writeInt(mFormat);
+ dest.writeInt(mMajorVersion);
+ dest.writeInt(mMinorVersion);
+ }
+
+ /** Builder for a {@link HubServiceInfo} object. */
+ public static final class Builder {
+ @NonNull private final String mServiceDescriptor;
+
+ @ServiceFormat private final int mFormat;
+ private final int mMajorVersion;
+ private final int mMinorVersion;
+
+ /**
+ * Create a builder for {@link HubServiceInfo} with a service descriptor.
+ *
+ * <p>Service descriptor should uniquely identify the interface (scoped to type). Convention
+ * of the descriptor depend on interface type.
+ *
+ * <p>Examples:
+ *
+ * <ol>
+ * <li>AOSP-defined AIDL: android.hardware.something.IFoo/default
+ * <li>Vendor-defined AIDL: com.example.something.IBar/default
+ * <li>Pigweed RPC with Protobuf: com.example.proto.ExampleService
+ * </ol>
+ *
+ * @param serviceDescriptor The service descriptor.
+ * @param format One of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link
+ * HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}.
+ * @param majorVersion Breaking changes should be a major version bump.
+ * @param minorVersion Monotonically increasing minor version.
+ * @throws IllegalArgumentException if one or more fields are not valid.
+ */
+ public Builder(
+ @NonNull String serviceDescriptor,
+ @ServiceFormat int format,
+ int majorVersion,
+ int minorVersion) {
+ if (format != FORMAT_CUSTOM
+ && format != FORMAT_AIDL
+ && format != FORMAT_PW_RPC_PROTOBUF) {
+ throw new IllegalArgumentException("Invalid format type.");
+ }
+ mFormat = format;
+
+ if (majorVersion < 0) {
+ throw new IllegalArgumentException(
+ "Major version cannot be set to negative number.");
+ }
+ mMajorVersion = majorVersion;
+
+ if (minorVersion < 0) {
+ throw new IllegalArgumentException(
+ "Minor version cannot be set to negative number.");
+ }
+ mMinorVersion = minorVersion;
+
+ if (serviceDescriptor.isBlank()) {
+ throw new IllegalArgumentException("Invalid service descriptor.");
+ }
+ mServiceDescriptor = serviceDescriptor;
+ }
+
+ /**
+ * Build the {@link HubServiceInfo} object.
+ *
+ * @throws IllegalStateException if the Builder is missing required info.
+ */
+ @NonNull
+ public HubServiceInfo build() {
+ if (mMajorVersion < 0 || mMinorVersion < 0) {
+ throw new IllegalStateException("Major and minor version must be set.");
+ }
+ return new HubServiceInfo(
+ mServiceDescriptor, mFormat, mMajorVersion, mMinorVersion);
+ }
+ }
+
+ /** Parcel implementation details */
+ @NonNull
+ public static final Parcelable.Creator<HubServiceInfo> CREATOR =
+ new Parcelable.Creator<>() {
+ public HubServiceInfo createFromParcel(Parcel in) {
+ return new HubServiceInfo(in);
+ }
+
+ public HubServiceInfo[] newArray(int size) {
+ return new HubServiceInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl
new file mode 100644
index 000000000000..1c98b4b3f4f5
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.HubMessage;
+import android.hardware.contexthub.HubServiceInfo;
+import android.hardware.location.IContextHubTransactionCallback;
+
+/**
+ * @hide
+ */
+interface IContextHubEndpoint {
+ /**
+ * Retrieve the up-to-date EndpointInfo, with assigned endpoint id.
+ */
+ HubEndpointInfo getAssignedHubEndpointInfo();
+
+ /**
+ * Request system service to open a session with a specific destination.
+ *
+ * @param destination A valid HubEndpointInfo representing the destination.
+ *
+ * @throws IllegalArgumentException If the HubEndpointInfo is not valid.
+ * @throws IllegalStateException If there are too many opened sessions.
+ */
+ int openSession(in HubEndpointInfo destination, in @nullable HubServiceInfo serviceInfo);
+
+ /**
+ * Request system service to close a specific session
+ *
+ * @param sessionId An integer identifying the session, assigned by system service
+ * @param reason An integer identifying the reason
+ *
+ * @throws IllegalStateException If the session wasn't opened.
+ */
+ void closeSession(int sessionId, int reason);
+
+ /**
+ * Callback when a session is opened. This callback is the status callback for a previous
+ * IContextHubEndpointCallback.onSessionOpenRequest().
+ *
+ * @param sessionId The integer representing the communication session, previously set in
+ * onSessionOpenRequest().
+ *
+ * @throws IllegalStateException If the session wasn't opened.
+ */
+ void openSessionRequestComplete(int sessionId);
+
+ /**
+ * Unregister this endpoint from the HAL, invalidate the EndpointInfo previously assigned.
+ */
+ void unregister();
+
+ /**
+ * Send a message parcelable to system service for a specific session.
+ *
+ * @param sessionId The integer representing the communication session, previously set in
+ * IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+ * @param message The HubMessage parcelable that represents the message and its delivery options.
+ * @param transactionCallback Nullable. If the hub message requires a reply, the transactionCallback
+ * will be set to non-null.
+ */
+ void sendMessage(int sessionId, in HubMessage message,
+ in @nullable IContextHubTransactionCallback transactionCallback);
+
+ /**
+ * Send a message delivery status to system service for a specific message
+ *
+ * @param sessionId The integer representing the communication session, previously set in
+ * IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+ * @param messageSeqNumber The message sequence number, this should match a previously received HubMessage.
+ * @param errorCode The message delivery status detail.
+ */
+ void sendMessageDeliveryStatus(int sessionId, int messageSeqNumber, byte errorCode);
+}
diff --git a/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl
new file mode 100644
index 000000000000..1ae5fb9d28c1
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.HubMessage;
+import android.hardware.contexthub.HubServiceInfo;
+
+/**
+ * @hide
+ */
+oneway interface IContextHubEndpointCallback {
+ /**
+ * Request from system service to open a session, requested by a specific initiator.
+ *
+ * @param sessionId An integer identifying the session, assigned by the initiator
+ * @param initiator HubEndpointInfo representing the requester
+ * @param serviceInfo Nullable HubServiceInfo representing the service associated with this session
+ */
+ void onSessionOpenRequest(int sessionId, in HubEndpointInfo initiator, in @nullable HubServiceInfo serviceInfo);
+
+ /**
+ * Request from system service to close a specific session
+ *
+ * @param sessionId An integer identifying the session
+ * @param reason An integer identifying the reason
+ */
+ void onSessionClosed(int sessionId, int reason);
+
+ /**
+ * Notifies the system service that the session requested by IContextHubEndpoint.openSession
+ * is ready to use.
+ *
+ * @param sessionId The integer representing the communication session, previously set in
+ * IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+ */
+ void onSessionOpenComplete(int sessionId);
+
+ /**
+ * Message notification from system service for a specific session
+
+ * @param sessionId The integer representing the communication session, previously set in
+ * IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+ * @param message The HubMessage parcelable that represents the message.
+ */
+ void onMessageReceived(int sessionId, in HubMessage message);
+}
diff --git a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
new file mode 100644
index 000000000000..46884393b49b
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface for listening to lifecycle events of a hub endpoint.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public interface IHubEndpointLifecycleCallback {
+ /** Unknown reason. */
+ int REASON_UNSPECIFIED = 0;
+
+ /** The peer rejected the request to open this endpoint session. */
+ int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3;
+
+ /** The peer closed this endpoint session. */
+ int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ REASON_UNSPECIFIED,
+ REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED,
+ REASON_CLOSE_ENDPOINT_SESSION_REQUESTED,
+ })
+ @interface EndpointLifecycleReason {}
+
+ /**
+ * Called when an endpoint is requesting a session be opened with another endpoint.
+ *
+ * @param requester The {@link HubEndpointInfo} object representing the requester
+ * @param serviceInfo The {@link HubServiceInfo} object representing the service associated with
+ * this session. Null indicates that there is no service associated with this session.
+ */
+ @NonNull
+ HubEndpointSessionResult onSessionOpenRequest(
+ @NonNull HubEndpointInfo requester, @Nullable HubServiceInfo serviceInfo);
+
+ /**
+ * Called when a communication session is opened and ready to be used.
+ *
+ * @param session The {@link HubEndpointSession} object that can be used for communication
+ */
+ void onSessionOpened(@NonNull HubEndpointSession session);
+
+ /**
+ * Called when a communication session is requested to be closed, or the peer endpoint rejected
+ * the session open request.
+ *
+ * @param session The {@link HubEndpointSession} object that is now closed and shouldn't be
+ * used.
+ * @param reason The reason why this session was closed.
+ */
+ void onSessionClosed(@NonNull HubEndpointSession session, @EndpointLifecycleReason int reason);
+}
diff --git a/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java b/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java
new file mode 100644
index 000000000000..fde7017b5e76
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+
+/**
+ * An interface used to deliver messages to an opened endpoint session.
+ *
+ * <p>This interface can be attached to an endpoint through {@link
+ * HubEndpoint.Builder#setMessageCallback} method. Methods in this interface will only be called
+ * when the endpoint is currently registered and has an open session. The endpoint will receive
+ * session lifecycle callbacks through {@link IHubEndpointLifecycleCallback}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public interface IHubEndpointMessageCallback {
+ /**
+ * Callback interface for receiving messages for a particular endpoint session.
+ *
+ * @param session The session this message is sent through. Previously specified in a {@link
+ * IHubEndpointLifecycleCallback#onSessionOpened(HubEndpointSession)} call.
+ * @param message The {@link HubMessage} object representing a message received by the endpoint
+ * that registered this callback interface. This message is constructed by the
+ */
+ void onMessageReceived(@NonNull HubEndpointSession session, @NonNull HubMessage message);
+}
diff --git a/core/java/android/hardware/contexthub/OWNERS b/core/java/android/hardware/contexthub/OWNERS
new file mode 100644
index 000000000000..a65a2bf9ee36
--- /dev/null
+++ b/core/java/android/hardware/contexthub/OWNERS
@@ -0,0 +1,2 @@
+# ContextHub team
+file:platform/system/chre:/OWNERS
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 28da644dd837..25327a9b1d52 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -21,6 +21,8 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.HdrCapabilities.HdrType;
import static android.view.Display.INVALID_DISPLAY;
+import static com.android.server.display.feature.flags.Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS;
+
import android.Manifest;
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
@@ -59,6 +61,7 @@ import android.view.Surface;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.display.feature.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -100,6 +103,7 @@ public final class DisplayManager {
private final WeakDisplayCache mDisplayCache = new WeakDisplayCache();
private int mDisplayIdToMirror = INVALID_DISPLAY;
+ private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
/**
* Broadcast receiver that indicates when the Wifi display status changes.
@@ -576,6 +580,8 @@ public final class DisplayManager {
EVENT_FLAG_DISPLAY_ADDED,
EVENT_FLAG_DISPLAY_CHANGED,
EVENT_FLAG_DISPLAY_REMOVED,
+ EVENT_FLAG_DISPLAY_REFRESH_RATE,
+ EVENT_FLAG_DISPLAY_STATE
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventFlag {}
@@ -596,8 +602,8 @@ public final class DisplayManager {
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
- * @hide
*/
+ @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
public static final long EVENT_FLAG_DISPLAY_ADDED = 1L << 0;
/**
@@ -605,8 +611,8 @@ public final class DisplayManager {
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
- * @hide
*/
+ @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
public static final long EVENT_FLAG_DISPLAY_REMOVED = 1L << 1;
/**
@@ -614,10 +620,27 @@ public final class DisplayManager {
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
- * @hide
*/
+ @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;
+
+ /**
+ * Event flag to register for a display's refresh rate changes.
+ *
+ * @see #registerDisplayListener(DisplayListener, Handler, long)
+ */
+ @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+ public static final long EVENT_FLAG_DISPLAY_REFRESH_RATE = 1L << 3;
+
+ /**
+ * Event flag to register for a display state changes.
+ *
+ * @see #registerDisplayListener(DisplayListener, Handler, long)
+ */
+ @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+ public static final long EVENT_FLAG_DISPLAY_STATE = 1L << 4;
+
/**
* Event flag to register for a display's brightness changes. This notification is sent
* through the {@link DisplayListener#onDisplayChanged} callback method. New brightness
@@ -787,9 +810,6 @@ public final class DisplayManager {
* if the listener should be invoked on the calling thread's looper.
* @param eventFlags A bitmask of the event types for which this listener is subscribed.
*
- * @see #EVENT_FLAG_DISPLAY_ADDED
- * @see #EVENT_FLAG_DISPLAY_CHANGED
- * @see #EVENT_FLAG_DISPLAY_REMOVED
* @see #registerDisplayListener(DisplayListener, Handler)
* @see #unregisterDisplayListener
*
@@ -806,18 +826,31 @@ public final class DisplayManager {
* Registers a display listener to receive notifications about given display event types.
*
* @param listener The listener to register.
+ * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null.
+ * @param eventFlags A bitmask of the event types for which this listener is subscribed.
+ *
+ * @see #registerDisplayListener(DisplayListener, Handler)
+ * @see #unregisterDisplayListener
+ *
+ */
+ @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+ public void registerDisplayListener(@NonNull Executor executor, @EventFlag long eventFlags,
+ @NonNull DisplayListener listener) {
+ mGlobal.registerDisplayListener(listener, executor,
+ mGlobal.mapFlagsToInternalEventFlag(eventFlags, 0),
+ ActivityThread.currentPackageName());
+ }
+
+ /**
+ * Registers a display listener to receive notifications about given display event types.
+ *
+ * @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
* @param eventFlags A bitmask of the event types for which this listener is subscribed.
* @param privateEventFlags A bitmask of the private event types for which this listener
* is subscribed.
*
- * @see #EVENT_FLAG_DISPLAY_ADDED
- * @see #EVENT_FLAG_DISPLAY_CHANGED
- * @see #EVENT_FLAG_DISPLAY_REMOVED
- * @see #PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS
- * @see #PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED
- * @see #PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED
* @see #registerDisplayListener(DisplayListener, Handler)
* @see #unregisterDisplayListener
*
@@ -1582,6 +1615,17 @@ public final class DisplayManager {
}
/**
+ * Returns whether this device supports Always On Display.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_IS_ALWAYS_ON_AVAILABLE_API)
+ public boolean isAlwaysOnDisplayCurrentlyAvailable() {
+ return getAmbientDisplayConfiguration().alwaysOnAvailableForUser(mContext.getUserId());
+ }
+
+ /**
* Returns whether device supports seamless refresh rate switching.
*
* Match content frame rate setting has three options: seamless, non-seamless and never.
@@ -1643,6 +1687,15 @@ public final class DisplayManager {
}
}
+ private AmbientDisplayConfiguration getAmbientDisplayConfiguration() {
+ synchronized (this) {
+ if (mAmbientDisplayConfiguration == null) {
+ mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
+ }
+ }
+ return mAmbientDisplayConfiguration;
+ }
+
/**
* Creates a VirtualDisplay that will mirror the content of displayIdToMirror
* @param name The name for the virtual display
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 03b44f63e3b7..1e66beea42a6 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -17,6 +17,7 @@
package android.hardware.display;
+import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
import static android.hardware.display.DisplayManager.EventFlag;
import static android.Manifest.permission.MANAGE_DISPLAYS;
import static android.view.Display.HdrCapabilities.HdrType;
@@ -62,6 +63,7 @@ import android.view.DisplayInfo;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.feature.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -108,6 +110,8 @@ public final class DisplayManagerGlobal {
EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED,
EVENT_DISPLAY_CONNECTED,
EVENT_DISPLAY_DISCONNECTED,
+ EVENT_DISPLAY_REFRESH_RATE_CHANGED,
+ EVENT_DISPLAY_STATE_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayEvent {}
@@ -119,6 +123,8 @@ public final class DisplayManagerGlobal {
public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5;
public static final int EVENT_DISPLAY_CONNECTED = 6;
public static final int EVENT_DISPLAY_DISCONNECTED = 7;
+ public static final int EVENT_DISPLAY_REFRESH_RATE_CHANGED = 8;
+ public static final int EVENT_DISPLAY_STATE_CHANGED = 9;
@LongDef(prefix = {"INTERNAL_EVENT_DISPLAY"}, flag = true, value = {
INTERNAL_EVENT_FLAG_DISPLAY_ADDED,
@@ -127,6 +133,8 @@ public final class DisplayManagerGlobal {
INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED,
INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED,
INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
+ INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
+ INTERNAL_EVENT_FLAG_DISPLAY_STATE
})
@Retention(RetentionPolicy.SOURCE)
public @interface InternalEventFlag {}
@@ -137,6 +145,8 @@ public final class DisplayManagerGlobal {
public static final long INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED = 1L << 3;
public static final long INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED = 1L << 4;
public static final long INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 5;
+ public static final long INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE = 1L << 6;
+ public static final long INTERNAL_EVENT_FLAG_DISPLAY_STATE = 1L << 7;
@UnsupportedAppUsage
private static DisplayManagerGlobal sInstance;
@@ -179,9 +189,11 @@ public final class DisplayManagerGlobal {
}
private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache =
- new PropertyInvalidatedCache<Integer, DisplayInfo>(
- 8, // size of display cache
- CACHE_KEY_DISPLAY_INFO_PROPERTY) {
+ new PropertyInvalidatedCache<>(
+ new PropertyInvalidatedCache.Args(MODULE_SYSTEM)
+ .maxEntries(8).api(CACHE_KEY_DISPLAY_INFO_API).isolateUids(false),
+ CACHE_KEY_DISPLAY_INFO_API, null) {
+
@Override
public DisplayInfo recompute(Integer id) {
try {
@@ -1427,6 +1439,18 @@ public final class DisplayManagerGlobal {
mListener.onDisplayDisconnected(displayId);
}
break;
+ case EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+ if ((mInternalEventFlagsMask
+ & INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE) != 0) {
+ mListener.onDisplayChanged(displayId);
+ }
+ break;
+ case EVENT_DISPLAY_STATE_CHANGED:
+ if ((mInternalEventFlagsMask
+ & INTERNAL_EVENT_FLAG_DISPLAY_STATE) != 0) {
+ mListener.onDisplayChanged(displayId);
+ }
+ break;
}
if (DEBUG) {
Trace.endSection();
@@ -1493,18 +1517,17 @@ public final class DisplayManagerGlobal {
}
/**
- * Name of the property containing a unique token which changes every time we update the
- * system's display configuration.
+ * The API portion of the key that identifies the unique PropertyInvalidatedCache token which
+ * changes every time we update the system's display configuration.
*/
- public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY =
- PropertyInvalidatedCache.createSystemCacheKey("display_info");
+ private static final String CACHE_KEY_DISPLAY_INFO_API = "display_info";
/**
* Invalidates the contents of the display info cache for all applications. Can only
* be called by system_server.
*/
public static void invalidateLocalDisplayInfoCaches() {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY);
+ PropertyInvalidatedCache.invalidateCache(MODULE_SYSTEM, CACHE_KEY_DISPLAY_INFO_API);
}
/**
@@ -1566,6 +1589,10 @@ public final class DisplayManagerGlobal {
return "EVENT_DISPLAY_CONNECTED";
case EVENT_DISPLAY_DISCONNECTED:
return "EVENT_DISPLAY_DISCONNECTED";
+ case EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+ return "EVENT_DISPLAY_REFRESH_RATE_CHANGED";
+ case EVENT_DISPLAY_STATE_CHANGED:
+ return "EVENT_DISPLAY_STATE_CHANGED";
}
return "UNKNOWN";
}
@@ -1630,6 +1657,17 @@ public final class DisplayManagerGlobal {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED;
}
+ if (Flags.displayListenerPerformanceImprovements()) {
+ if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE) != 0) {
+ baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
+ }
+
+ if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_STATE) != 0) {
+ baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_STATE;
+ }
+ }
+
+
return baseEventMask;
}
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 399184cfaecb..68b6cfc012fc 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -470,6 +470,31 @@ public abstract class DisplayManagerInternal {
*/
public abstract boolean isDisplayReadyForMirroring(int displayId);
+
+ /**
+ * Used by the window manager to override the per-display screen brightness based on the
+ * current foreground activity.
+ *
+ * The key of the array is the displayId. If a displayId is missing from the array, this is
+ * equivalent to clearing any existing brightness overrides for that display.
+ *
+ * This method must only be called by the window manager.
+ */
+ public abstract void setScreenBrightnessOverrideFromWindowManager(
+ SparseArray<DisplayBrightnessOverrideRequest> brightnessOverrides);
+
+ /**
+ * Describes a request for overriding the brightness of a single display.
+ */
+ public static class DisplayBrightnessOverrideRequest {
+ // An override of the screen brightness.
+ // Set to PowerManager.BRIGHTNESS_INVALID if there's no override.
+ public float brightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+
+ // Tag used to identify the app window requesting the brightness override.
+ public CharSequence tag;
+ }
+
/**
* Describes the requested power state of the display.
*
@@ -505,11 +530,11 @@ public abstract class DisplayManagerInternal {
// nearby, turning it off temporarily until the object is moved away.
public boolean useProximitySensor;
- // An override of the screen brightness.
+ // A global override of the screen brightness, applied to all displays.
// Set to PowerManager.BRIGHTNESS_INVALID if there's no override.
public float screenBrightnessOverride;
- // Tag used to identify the app window requesting the brightness override.
+ // Tag used to identify the reason for the global brightness override.
public CharSequence screenBrightnessOverrideTag;
// An override of the screen auto-brightness adjustment factor in the range -1 (dimmer) to
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java
index e349b81614bc..f00c3a53ad0c 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -23,6 +23,7 @@ import static android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Parcel;
import android.os.Parcelable;
@@ -150,6 +151,138 @@ public final class DisplayTopology implements Parcelable {
}
}
+ /**
+ * Rearranges the topology toward the positions given for each display. The width and height of
+ * each display, as well as the primary display, are not changed by this call.
+ * <p>
+ * Upon returning, the topology will be valid and normalized with each display as close to the
+ * requested positions as possible.
+ *
+ * @param newPos the desired positions (upper-left corner) of each display. The keys in the map
+ * are the display IDs.
+ * @throws IllegalArgumentException if the keys in {@code positions} are not the exact display
+ * IDs in this topology, no more, no less
+ */
+ public void rearrange(Map<Integer, PointF> newPos) {
+ var availableParents = new ArrayList<TreeNode>();
+
+ availableParents.addLast(mRoot);
+
+ var needsParent = allNodesIdMap();
+
+ // In the case of missing items, if this check doesn't detect it, a NPE will be thrown
+ // later.
+ if (needsParent.size() != newPos.size()) {
+ throw new IllegalArgumentException("newPos has wrong number of entries: " + newPos);
+ }
+
+ mRoot.mChildren.clear();
+ for (TreeNode n : needsParent.values()) {
+ n.mChildren.clear();
+ }
+
+ needsParent.remove(mRoot.mDisplayId);
+ // Start with a root island and add children to it one-by-one until the island consists of
+ // all the displays. The root island begins with only the root node, which has no
+ // parent. Then we greedily choose an optimal pairing of two nodes, consisting of a node
+ // from the island and a node not yet in the island. This is repeating until all nodes are
+ // in the island.
+ //
+ // The optimal pair is the pair which has the smallest deviation. The deviation consists of
+ // an x-axis component and a y-axis component, called xDeviation and yDeviation.
+ //
+ // The deviations are like distances but a little different. They are calculated in two
+ // steps. The first step calculates both axes in a similar way. The next step compares the
+ // two values and chooses which axis to attach along. Depending on which axis is chosen,
+ // the deviation for one axis is updated. See below for details.
+ while (!needsParent.isEmpty()) {
+ double bestDist = Double.POSITIVE_INFINITY;
+ TreeNode bestChild = null, bestParent = null;
+
+ for (var child : needsParent.values()) {
+ PointF childPos = newPos.get(child.mDisplayId);
+ float childRight = childPos.x + child.getWidth();
+ float childBottom = childPos.y + child.getHeight();
+ for (var parent : availableParents) {
+ PointF parentPos = newPos.get(parent.mDisplayId);
+ float parentRight = parentPos.x + parent.getWidth();
+ float parentBottom = parentPos.y + parent.getHeight();
+
+ // This is the smaller of the two ranges minus the amount of overlap shared
+ // between them. The "amount of overlap" is negative if there is no overlap, but
+ // this does not make a parenting ineligible, because we allow for attaching at
+ // the corner and for floating point error. The overlap is more negative the
+ // farther apart the closest corner pair is.
+ //
+ // For each axis, this calculates (SmallerRange - Overlap). If one range lies
+ // completely in the other (or they are equal), the axis' deviation will be
+ // zero.
+ //
+ // The "SmallerRange," which refers to smaller of the widths of the two rects,
+ // or smaller of the heights of the two rects, is added to the deviation so that
+ // a maximum overlap results in a deviation of zero.
+ float xSmallerRange = Math.min(child.getWidth(), parent.getWidth());
+ float ySmallerRange = Math.min(child.getHeight(), parent.getHeight());
+ float xOverlap
+ = Math.min(parentRight, childRight)
+ - Math.max(parentPos.x, childPos.x);
+ float yOverlap
+ = Math.min(parentBottom, childBottom)
+ - Math.max(parentPos.y, childPos.y);
+ float xDeviation = xSmallerRange - xOverlap;
+ float yDeviation = ySmallerRange - yOverlap;
+
+ float offset;
+ int pos;
+ if (xDeviation <= yDeviation) {
+ if (childPos.y < parentPos.y) {
+ yDeviation = childBottom - parentPos.y;
+ pos = POSITION_TOP;
+ } else {
+ yDeviation = parentBottom - childPos.y;
+ pos = POSITION_BOTTOM;
+ }
+ offset = childPos.x - parentPos.x;
+ } else {
+ if (childPos.x < parentPos.x) {
+ xDeviation = childRight - parentPos.x;
+ pos = POSITION_LEFT;
+ } else {
+ xDeviation = parentRight - childPos.x;
+ pos = POSITION_RIGHT;
+ }
+ offset = childPos.y - parentPos.y;
+ }
+
+ double dist = Math.hypot(xDeviation, yDeviation);
+ if (dist >= bestDist) {
+ continue;
+ }
+
+ bestDist = dist;
+ bestChild = child;
+ bestParent = parent;
+ // Eagerly update the child's parenting info, even though we may not use it, in
+ // which case it will be overwritten later.
+ bestChild.mPosition = pos;
+ bestChild.mOffset = offset;
+ }
+ }
+
+ assert bestParent != null & bestChild != null;
+
+ bestParent.addChild(bestChild);
+ if (null == needsParent.remove(bestChild.mDisplayId)) {
+ throw new IllegalStateException("child not in pending set! " + bestChild);
+ }
+ availableParents.add(bestChild);
+ }
+
+ // The conversion may have introduced an intersection of two display rects. If they are
+ // bigger than our error tolerance, this function will remove them.
+ normalize();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -450,6 +583,20 @@ public final class DisplayTopology implements Parcelable {
return a == b || (Float.isNaN(a) && Float.isNaN(b)) || Math.abs(a - b) < EPSILON;
}
+ private Map<Integer, TreeNode> allNodesIdMap() {
+ var pend = new ArrayDeque<TreeNode>();
+ var found = new HashMap<Integer, TreeNode>();
+
+ pend.push(mRoot);
+ do {
+ TreeNode node = pend.pop();
+ found.put(node.mDisplayId, node);
+ pend.addAll(node.mChildren);
+ } while (!pend.isEmpty());
+
+ return found;
+ }
+
public static final class TreeNode implements Parcelable {
public static final int POSITION_LEFT = 0;
public static final int POSITION_TOP = 1;
diff --git a/core/java/android/hardware/flags/overlayproperties_flags.aconfig b/core/java/android/hardware/flags/flags.aconfig
index 6c86108c4034..5ca6c6bed1f0 100644
--- a/core/java/android/hardware/flags/overlayproperties_flags.aconfig
+++ b/core/java/android/hardware/flags/flags.aconfig
@@ -2,6 +2,15 @@ package: "android.hardware.flags"
container: "system"
flag {
+ name: "luts_api"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "core_graphics"
+ description: "public Luts related Apis"
+ bug: "349667978"
+}
+
+flag {
name: "overlayproperties_class_api"
is_exported: true
namespace: "core_graphics"
diff --git a/core/java/android/hardware/input/AidlInputGestureData.aidl b/core/java/android/hardware/input/AidlInputGestureData.aidl
index e33ec53dd208..f7410d2e7783 100644
--- a/core/java/android/hardware/input/AidlInputGestureData.aidl
+++ b/core/java/android/hardware/input/AidlInputGestureData.aidl
@@ -28,15 +28,18 @@ parcelable AidlInputGestureData {
String appLaunchPackageName;
String appLaunchClassName;
+ @JavaDerive(equals=true)
parcelable KeyTrigger {
int keycode;
int modifierState;
}
+ @JavaDerive(equals=true)
parcelable TouchpadGestureTrigger {
int gestureType;
}
+ @JavaDerive(equals=true)
union Trigger {
KeyTrigger key;
TouchpadGestureTrigger touchpadGesture;
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 3284761eb273..ed510e467f82 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -281,4 +281,6 @@ interface IInputManager {
AidlInputGestureData[] getCustomInputGestures(int userId, int tag);
AidlInputGestureData[] getAppLaunchBookmarks();
+
+ void resetLockedModifierState();
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index f8241925dff0..10224c1be788 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -260,7 +260,7 @@ public final class InputManager {
}
/**
- * Custom input gesture error: Input gesture already exists
+ * Custom input gesture result success
*
* @hide
*/
@@ -1590,6 +1590,21 @@ public final class InputManager {
}
/**
+ * Resets locked modifier state (i.e.. Caps Lock, Num Lock, Scroll Lock state)
+ *
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
+ public void resetLockedModifierState() {
+ try {
+ mIm.resetLockedModifierState();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* A callback used to be notified about battery state changes for an input device. The
* {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the
* listener is successfully registered to provide the initial battery state of the device.
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 71b60cff9367..114459e5e819 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -31,7 +31,7 @@ import static com.android.hardware.input.Flags.touchpadTapDragging;
import static com.android.hardware.input.Flags.touchpadThreeFingerTapShortcut;
import static com.android.hardware.input.Flags.touchpadVisualizer;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
-import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiPressGestures;
+import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiKeyGestures;
import static com.android.input.flags.Flags.FLAG_KEYBOARD_REPEAT_KEYS;
import static com.android.input.flags.Flags.enableInputFilterRustImpl;
import static com.android.input.flags.Flags.keyboardRepeatKeys;
@@ -522,8 +522,11 @@ public class InputSettings {
* @hide
*/
public static boolean useTouchpadThreeFingerTapShortcut(@NonNull Context context) {
- // TODO(b/365063048): determine whether to enable the shortcut based on the settings.
- return isTouchpadThreeFingerTapShortcutFeatureFlagEnabled();
+ int customizedShortcut = Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION,
+ KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED, UserHandle.USER_CURRENT);
+ return customizedShortcut != KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED
+ && isTouchpadThreeFingerTapShortcutFeatureFlagEnabled();
}
/**
@@ -1155,6 +1158,6 @@ public class InputSettings {
* @hide
*/
public static boolean doesKeyGestureEventHandlerSupportMultiKeyGestures() {
- return useKeyGestureEventHandler() && useKeyGestureEventHandlerMultiPressGestures();
+ return useKeyGestureEventHandler() && useKeyGestureEventHandlerMultiKeyGestures();
}
}
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 24951c4d516e..711dc3a2cf7c 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -115,12 +115,14 @@ public final class KeyGestureEvent {
public static final int KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS = 67;
public static final int KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW = 68;
public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69;
- public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 70;
- public static final int KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE = 71;
+ public static final int KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW = 70;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW = 71;
public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN = 72;
public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT = 73;
public static final int KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION = 74;
public static final int KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK = 75;
+ public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 76;
+
public static final int FLAG_CANCELLED = 1;
@@ -205,12 +207,13 @@ public final class KeyGestureEvent {
KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
- KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
- KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
+ KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
+ KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN,
KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT,
KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK,
+ KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW
})
@Retention(RetentionPolicy.SOURCE)
public @interface KeyGestureType {
@@ -557,14 +560,6 @@ public final class KeyGestureEvent {
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
- case KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW:
- return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_LEFT_FREEFORM_WINDOW;
- case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
- return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_RIGHT_FREEFORM_WINDOW;
- case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
- return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MAXIMIZE_FREEFORM_WINDOW;
- case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
- return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RESTORE_FREEFORM_WINDOW_SIZE;
default:
return LOG_EVENT_UNSPECIFIED;
}
@@ -777,10 +772,10 @@ public final class KeyGestureEvent {
return "KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW";
case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
- case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
- return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
- case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
- return "KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE";
+ case KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW:
+ return "KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW";
+ case KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW:
+ return "KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW";
case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN:
return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN";
case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT:
@@ -789,6 +784,8 @@ public final class KeyGestureEvent {
return "KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION";
case KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK:
return "KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK";
+ case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
+ return "KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW";
default:
return Integer.toHexString(value);
}
diff --git a/core/java/android/hardware/input/KeyGlyphMap.java b/core/java/android/hardware/input/KeyGlyphMap.java
index f82d1cf276b9..de5df9188c17 100644
--- a/core/java/android/hardware/input/KeyGlyphMap.java
+++ b/core/java/android/hardware/input/KeyGlyphMap.java
@@ -133,6 +133,14 @@ public final class KeyGlyphMap implements Parcelable {
}
};
+ public int getModifierState() {
+ return mModifierState;
+ }
+
+ public int getKeycode() {
+ return mKeycode;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 4b2f2c218e5a..0c89059a475a 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -88,6 +88,17 @@ flag {
}
flag {
+ name: "input_manager_lifecycle_support"
+ namespace: "input"
+ description: "Add support for Lifecycle support in input manager"
+ bug: "362473586"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
namespace: "input_native"
name: "manage_key_gestures"
description: "Manage key gestures through Input APIs"
@@ -103,8 +114,8 @@ flag {
}
flag {
- namespace: "input_native"
- name: "use_key_gesture_event_handler_multi_press_gestures"
+ namespace: "input"
+ name: "use_key_gesture_event_handler_multi_key_gestures"
description: "Use KeyGestureEvent handler APIs to control multi key press gestures"
bug: "358569822"
}
@@ -170,4 +181,11 @@ flag {
namespace: "input"
description: "Adds key gestures for talkback and magnifier"
bug: "375277034"
-} \ No newline at end of file
+}
+
+flag {
+ name: "can_window_override_power_gesture_api"
+ namespace: "wallet_integration"
+ description: "Adds new API in WindowManager class to check if the window can override the power key double tap behavior."
+ bug: "378736024"
+ } \ No newline at end of file
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 494bfc926384..426cd69f76a0 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -34,6 +34,11 @@ import android.chre.flags.Flags;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.contexthub.ErrorCode;
+import android.hardware.contexthub.HubDiscoveryInfo;
+import android.hardware.contexthub.HubEndpoint;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.HubServiceInfo;
+import android.hardware.contexthub.IHubEndpointLifecycleCallback;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
@@ -42,6 +47,7 @@ import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -679,6 +685,65 @@ public final class ContextHubManager {
}
/**
+ * Find a list of endpoints that matches a specific ID.
+ *
+ * @param endpointId Statically generated ID for an endpoint.
+ * @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery.
+ */
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @NonNull
+ public List<HubDiscoveryInfo> findEndpoints(long endpointId) {
+ // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load
+ // timing.
+ try {
+ List<HubEndpointInfo> endpointInfos = mService.findEndpoints(endpointId);
+ List<HubDiscoveryInfo> results = new ArrayList<>(endpointInfos.size());
+ // Wrap with result type
+ for (HubEndpointInfo endpointInfo : endpointInfos) {
+ results.add(new HubDiscoveryInfo(endpointInfo));
+ }
+ return results;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Find a list of endpoints that provides a specific service.
+ *
+ * @param serviceDescriptor Statically generated ID for an endpoint.
+ * @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery.
+ * @throws IllegalArgumentException if the serviceDescriptor is empty/null.
+ */
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @NonNull
+ public List<HubDiscoveryInfo> findEndpoints(@NonNull String serviceDescriptor) {
+ // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load
+ // timing.
+ if (serviceDescriptor.isBlank()) {
+ throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor);
+ }
+ try {
+ List<HubEndpointInfo> endpointInfos =
+ mService.findEndpointsWithService(serviceDescriptor);
+ List<HubDiscoveryInfo> results = new ArrayList<>(endpointInfos.size());
+ // Wrap with result type
+ for (HubEndpointInfo endpointInfo : endpointInfos) {
+ for (HubServiceInfo serviceInfo : endpointInfo.getServiceInfoCollection()) {
+ if (serviceInfo.getServiceDescriptor().equals(serviceDescriptor)) {
+ results.add(new HubDiscoveryInfo(endpointInfo, serviceInfo));
+ }
+ }
+ }
+ return results;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Set a callback to receive messages from the context hub
*
* @param callback Callback object
@@ -1010,6 +1075,80 @@ public final class ContextHubManager {
}
/**
+ * Registers an endpoint and its callback with the Context Hub Service.
+ *
+ * <p>An endpoint is registered with the Context Hub Service and published to the HAL. When the
+ * registration succeeds, the endpoint can receive notifications through the provided callback.
+ *
+ * @param hubEndpoint {@link HubEndpoint} object created by {@link HubEndpoint.Builder}
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ public void registerEndpoint(@NonNull HubEndpoint hubEndpoint) {
+ hubEndpoint.register(mService);
+ }
+
+ /**
+ * Use a registered endpoint to connect to another endpoint (destination) without specifying a
+ * service.
+ *
+ * <p>Context Hub Service will create the endpoint session and notify the registered endpoint.
+ * The registered endpoint will receive callbacks on its {@link IHubEndpointLifecycleCallback}
+ * object regarding the lifecycle events of the session.
+ *
+ * @param hubEndpoint {@link HubEndpoint} object previously registered via {@link
+ * ContextHubManager#registerEndpoint(HubEndpoint)}.
+ * @param destination {@link HubEndpointInfo} object that represents an endpoint from previous
+ * endpoint discovery results (e.g. from {@link ContextHubManager#findEndpoints(long)}).
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ public void openSession(
+ @NonNull HubEndpoint hubEndpoint, @NonNull HubEndpointInfo destination) {
+ hubEndpoint.openSession(destination, null);
+ }
+
+ /**
+ * Use a registered endpoint to connect to another endpoint (destination) for a service
+ * described by a {@link HubServiceInfo} object.
+ *
+ * <p>Context Hub Service will create the endpoint session and notify the registered endpoint.
+ * The registered endpoint will receive callbacks on its {@link IHubEndpointLifecycleCallback}
+ * object regarding the lifecycle events of the session.
+ *
+ * @param hubEndpoint {@link HubEndpoint} object previously registered via {@link
+ * ContextHubManager#registerEndpoint(HubEndpoint)}.
+ * @param destination {@link HubEndpointInfo} object that represents an endpoint from previous
+ * endpoint discovery results (e.g. from {@link ContextHubManager#findEndpoints(long)}).
+ * @param serviceInfo {@link HubServiceInfo} object that describes the service associated with
+ * this session. The information will be sent to the destination as part of open request.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ public void openSession(
+ @NonNull HubEndpoint hubEndpoint,
+ @NonNull HubEndpointInfo destination,
+ @NonNull HubServiceInfo serviceInfo) {
+ hubEndpoint.openSession(destination, serviceInfo);
+ }
+
+ /**
+ * Unregisters an endpoint and its callback with the Context Hub Service.
+ *
+ * <p>An endpoint is unregistered from the HAL. The endpoint object will no longer receive
+ * notification through the provided callback.
+ *
+ * @param hubEndpoint {@link HubEndpoint} object created by {@link HubEndpoint.Builder}. This
+ * should match a previously registered object via {@link
+ * ContextHubManager#registerEndpoint(HubEndpoint)}.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ public void unregisterEndpoint(@NonNull HubEndpoint hubEndpoint) {
+ hubEndpoint.unregister();
+ }
+
+ /**
* Queries for the list of preloaded nanoapp IDs on the system.
*
* @param hubInfo The Context Hub to query a list of nanoapp IDs from.
@@ -1168,6 +1307,7 @@ public final class ContextHubManager {
requireNonNull(mainLooper, "mainLooper cannot be null");
mService = service;
mMainLooper = mainLooper;
+
try {
mService.registerCallback(mClientCallback);
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index bd87b5cb6d54..ee55f81bb2a7 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -51,18 +51,23 @@ public class ContextHubTransaction<T> {
/**
* Constants describing the type of a transaction through the Context Hub Service.
- * {@hide}
+ *
+ * @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "TYPE_" }, value = {
- TYPE_LOAD_NANOAPP,
- TYPE_UNLOAD_NANOAPP,
- TYPE_ENABLE_NANOAPP,
- TYPE_DISABLE_NANOAPP,
- TYPE_QUERY_NANOAPPS,
- TYPE_RELIABLE_MESSAGE,
- })
- public @interface Type { }
+ @IntDef(
+ prefix = {"TYPE_"},
+ value = {
+ TYPE_LOAD_NANOAPP,
+ TYPE_UNLOAD_NANOAPP,
+ TYPE_ENABLE_NANOAPP,
+ TYPE_DISABLE_NANOAPP,
+ TYPE_QUERY_NANOAPPS,
+ TYPE_RELIABLE_MESSAGE,
+ TYPE_HUB_MESSAGE_DEFAULT,
+ TYPE_HUB_MESSAGE_REQUIRES_RESPONSE,
+ })
+ public @interface Type {}
public static final int TYPE_LOAD_NANOAPP = 0;
public static final int TYPE_UNLOAD_NANOAPP = 1;
@@ -71,24 +76,34 @@ public class ContextHubTransaction<T> {
public static final int TYPE_QUERY_NANOAPPS = 4;
public static final int TYPE_RELIABLE_MESSAGE = 5;
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ public static final int TYPE_HUB_MESSAGE_DEFAULT = 6;
+
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ public static final int TYPE_HUB_MESSAGE_REQUIRES_RESPONSE = 7;
+
/**
* Constants describing the result of a transaction or request through the Context Hub Service.
- * {@hide}
+ *
+ * @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "RESULT_" }, value = {
- RESULT_SUCCESS,
- RESULT_FAILED_UNKNOWN,
- RESULT_FAILED_BAD_PARAMS,
- RESULT_FAILED_UNINITIALIZED,
- RESULT_FAILED_BUSY,
- RESULT_FAILED_AT_HUB,
- RESULT_FAILED_TIMEOUT,
- RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
- RESULT_FAILED_HAL_UNAVAILABLE,
- RESULT_FAILED_NOT_SUPPORTED,
- })
+ @IntDef(
+ prefix = {"RESULT_"},
+ value = {
+ RESULT_SUCCESS,
+ RESULT_FAILED_UNKNOWN,
+ RESULT_FAILED_BAD_PARAMS,
+ RESULT_FAILED_UNINITIALIZED,
+ RESULT_FAILED_BUSY,
+ RESULT_FAILED_AT_HUB,
+ RESULT_FAILED_TIMEOUT,
+ RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
+ RESULT_FAILED_HAL_UNAVAILABLE,
+ RESULT_FAILED_NOT_SUPPORTED,
+ })
public @interface Result {}
+
public static final int RESULT_SUCCESS = 0;
/**
* Generic failure mode.
@@ -143,7 +158,8 @@ public class ContextHubTransaction<T> {
*/
private R mContents;
- Response(@ContextHubTransaction.Result int result, R contents) {
+ /** @hide */
+ public Response(@ContextHubTransaction.Result int result, R contents) {
mResult = result;
mContents = contents;
}
@@ -206,7 +222,8 @@ public class ContextHubTransaction<T> {
*/
private boolean mIsResponseSet = false;
- ContextHubTransaction(@Type int type) {
+ /** @hide */
+ public ContextHubTransaction(@Type int type) {
mTransactionType = type;
}
@@ -338,16 +355,16 @@ public class ContextHubTransaction<T> {
/**
* Sets the response of the transaction.
*
- * This method should only be invoked by ContextHubManager as a result of a callback from
- * the Context Hub Service indicating the response from a transaction. This method should not be
+ * <p>This method should only be invoked by ContextHubManager as a result of a callback from the
+ * Context Hub Service indicating the response from a transaction. This method should not be
* invoked more than once.
*
* @param response the response to set
- *
* @throws IllegalStateException if this method is invoked multiple times
* @throws NullPointerException if the response is null
+ * @hide
*/
- /* package */ void setResponse(ContextHubTransaction.Response<T> response) {
+ public void setResponse(ContextHubTransaction.Response<T> response) {
synchronized (this) {
Objects.requireNonNull(response, "Response cannot be null");
if (mIsResponseSet) {
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index b0cc763dc8fd..f9f412446038 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -18,17 +18,20 @@ package android.hardware.location;
// Declare any non-default types here with import statements
import android.app.PendingIntent;
-import android.hardware.location.HubInfo;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.IContextHubEndpoint;
+import android.hardware.contexthub.IContextHubEndpointCallback;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubMessage;
-import android.hardware.location.NanoApp;
-import android.hardware.location.NanoAppBinary;
-import android.hardware.location.NanoAppFilter;
-import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.HubInfo;
import android.hardware.location.IContextHubCallback;
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.IContextHubTransactionCallback;
+import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppFilter;
+import android.hardware.location.NanoAppInstanceInfo;
/**
* @hide
@@ -122,4 +125,16 @@ interface IContextHubService {
// Enables or disables test mode
@EnforcePermission("ACCESS_CONTEXT_HUB")
boolean setTestMode(in boolean enable);
+
+ // Finds all endpoints that has a specific ID
+ @EnforcePermission("ACCESS_CONTEXT_HUB")
+ List<HubEndpointInfo> findEndpoints(long endpointId);
+
+ // Finds all endpoints that has a specific service
+ @EnforcePermission("ACCESS_CONTEXT_HUB")
+ List<HubEndpointInfo> findEndpointsWithService(String service);
+
+ // Register an endpoint with the context hub
+ @EnforcePermission("ACCESS_CONTEXT_HUB")
+ IContextHubEndpoint registerEndpoint(in HubEndpointInfo pendingEndpointInfo, in IContextHubEndpointCallback callback);
}
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 4bc5bd2427ea..26308f69cfbe 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -16,6 +16,9 @@
package android.inputmethodservice;
+import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT;
+
+import android.annotation.FlaggedApi;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -193,6 +196,12 @@ public abstract class AbstractInputMethodService extends WindowProviderService
}
}
+ @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
+ @Override
+ public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) {
+ return AbstractInputMethodService.this.onShouldVerifyKeyEvent(event);
+ }
+
/**
* Take care of dispatching incoming trackball events to the appropriate
* callbacks on the service, and tell the client when this is done.
@@ -308,6 +317,14 @@ public abstract class AbstractInputMethodService extends WindowProviderService
return false;
}
+ /**
+ * @see InputMethodService#onShouldVerifyKeyEvent(KeyEvent)
+ */
+ @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
+ public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) {
+ return false;
+ }
+
/** @hide */
@Override
public final int getWindowType() {
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 62b131af74fe..9b37533f5b02 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -16,12 +16,16 @@
package android.inputmethodservice;
+import static android.view.inputmethod.Flags.verifyKeyEvent;
+
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Rect;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.view.InputChannel;
@@ -41,6 +45,8 @@ import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import java.util.Objects;
+
class IInputMethodSessionWrapper extends IInputMethodSession.Stub
implements HandlerCaller.Callback {
private static final String TAG = "InputMethodWrapper";
@@ -56,6 +62,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
private static final int DO_REMOVE_IME_SURFACE = 130;
private static final int DO_FINISH_INPUT = 140;
private static final int DO_INVALIDATE_INPUT = 150;
+ private final Context mContext;
@UnsupportedAppUsage
@@ -66,6 +73,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
public IInputMethodSessionWrapper(Context context,
InputMethodSession inputMethodSession, InputChannel channel) {
+ mContext = context;
mCaller = new HandlerCaller(context, null,
this, true /*asyncHandler*/);
mInputMethodSession = inputMethodSession;
@@ -233,6 +241,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
}
private final class ImeInputEventReceiver extends InputEventReceiver
implements InputMethodSession.EventCallback {
+ // Time after which a KeyEvent is invalid
+ private static final long KEY_EVENT_ALLOW_PERIOD_MS = 100L;
private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();
public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) {
@@ -247,10 +257,23 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
return;
}
+ if (event instanceof KeyEvent keyEvent && needsVerification(keyEvent)) {
+ // any KeyEvent with modifiers (e.g. Ctrl/Alt/Fn) must be verified that
+ // they originated from system.
+ InputManager im = mContext.getSystemService(InputManager.class);
+ Objects.requireNonNull(im);
+ final long age = SystemClock.uptimeMillis() - keyEvent.getEventTime();
+ if (age >= KEY_EVENT_ALLOW_PERIOD_MS && im.verifyInputEvent(keyEvent) == null) {
+ Log.w(TAG, "Unverified or Invalid KeyEvent injected into IME. Dropping "
+ + keyEvent);
+ finishInputEvent(event, false /* handled */);
+ return;
+ }
+ }
+
final int seq = event.getSequenceNumber();
mPendingEvents.put(seq, event);
- if (event instanceof KeyEvent) {
- KeyEvent keyEvent = (KeyEvent)event;
+ if (event instanceof KeyEvent keyEvent) {
mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this);
} else {
MotionEvent motionEvent = (MotionEvent)event;
@@ -271,5 +294,21 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
finishInputEvent(event, handled);
}
}
+
+ private boolean hasKeyModifiers(KeyEvent event) {
+ if (event.hasNoModifiers()) {
+ return false;
+ }
+ return event.hasModifiers(KeyEvent.META_CTRL_ON)
+ || event.hasModifiers(KeyEvent.META_ALT_ON)
+ || event.hasModifiers(KeyEvent.KEYCODE_FUNCTION);
+ }
+
+ private boolean needsVerification(KeyEvent event) {
+ //TODO(b/331730488): Handle a11y events as well.
+ return verifyKeyEvent()
+ && (hasKeyModifiers(event)
+ || mInputMethodSession.onShouldVerifyKeyEvent(event));
+ }
}
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 8c3f0ef08039..4bde8e2b44ee 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -55,6 +55,8 @@ import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECT
import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_OTHER;
import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED;
import static android.view.inputmethod.Flags.FLAG_CONNECTIONLESS_HANDWRITING;
+import static android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API;
+import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT;
import static android.view.inputmethod.Flags.ctrlShiftShortcut;
import static android.view.inputmethod.Flags.predictiveBackIme;
@@ -406,6 +408,12 @@ public class InputMethodService extends AbstractInputMethodService {
private boolean mUsingCtrlShiftShortcut = false;
/**
+ * Last handwriting bounds used for stylus handwriting
+ * {@link #setStylusHandwritingRegion(Region)}.
+ */
+ private Region mLastHandwritingRegion;
+
+ /**
* Returns whether {@link InputMethodService} is responsible for rendering the back button and
* the IME switcher button or not when the gestural navigation is enabled.
*
@@ -1531,6 +1539,7 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
editorInfo.makeCompatible(getApplicationInfo().targetSdkVersion);
+ mLastHandwritingRegion = null;
getInputMethodInternal().restartInput(new RemoteInputConnection(ric, sessionId),
editorInfo);
}
@@ -2839,6 +2848,7 @@ public class InputMethodService extends AbstractInputMethodService {
mHandler.removeCallbacks(mFinishHwRunnable);
}
mFinishHwRunnable = null;
+ mLastHandwritingRegion = null;
final int requestId = mHandwritingRequestId.getAsInt();
mHandwritingRequestId = OptionalInt.empty();
@@ -3165,6 +3175,40 @@ public class InputMethodService extends AbstractInputMethodService {
registerDefaultOnBackInvokedCallback();
}
+ /**
+ * Sets a new stylus handwriting region as user continues to write on an editor on screen.
+ * Stylus strokes that are started within the {@code touchableRegion} are treated as
+ * continuation of handwriting and all the events outside are passed-through to the IME target
+ * app, causing stylus handwriting to finish {@link #finishStylusHandwriting()}.
+ * By default, {@link WindowManager#getMaximumWindowMetrics()} is handwritable and
+ * {@code touchableRegion} resets after each handwriting session.
+ * <p>
+ * For example, the IME can use this API to dynamically expand the stylus handwriting region on
+ * every stylus stroke as user continues to write on an editor. The region should grow around
+ * the last stroke so that a UI element below the IME window is still interactable when it is
+ * spaced sufficiently away (~2 character dimensions) from last stroke.
+ * </p>
+ * <p>
+ * Note: Setting handwriting touchable region is supported on IMEs that support stylus
+ * handwriting {@link InputMethodInfo#supportsStylusHandwriting()}.
+ * </p>
+ *
+ * @param handwritingRegion new stylus handwritable {@link Region} that can accept stylus touch.
+ */
+ @FlaggedApi(Flags.FLAG_ADAPTIVE_HANDWRITING_BOUNDS)
+ public final void setStylusHandwritingRegion(@NonNull Region handwritingRegion) {
+ if (handwritingRegion.equals(mLastHandwritingRegion)) {
+ Log.v(TAG, "Failed to set setStylusHandwritingRegion():"
+ + " same region set twice.");
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Setting new handwriting region for stylus handwriting "
+ + handwritingRegion + " from last " + mLastHandwritingRegion);
+ }
+ mLastHandwritingRegion = handwritingRegion;
+ }
/**
* Registers an {@link OnBackInvokedCallback} to handle back invocation when ahead-of-time
@@ -3436,7 +3480,7 @@ public class InputMethodService extends AbstractInputMethodService {
initialize();
mInlineSuggestionSessionController.notifyOnStartInput(
editorInfo == null ? null : editorInfo.packageName,
- editorInfo == null ? null : editorInfo.autofillId);
+ editorInfo == null ? null : editorInfo.getAutofillId());
if (DEBUG) Log.v(TAG, "CALL: onStartInput");
onStartInput(editorInfo, restarting);
if (mDecorViewVisible) {
@@ -3734,6 +3778,23 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * Received by the IME before dispatch to {@link #onKeyDown(int, KeyEvent)} to let the system
+ * know if the {@link KeyEvent} needs to be verified that it originated from the system.
+ * {@link KeyEvent}s may originate from outside of the system and any sensitive keys should be
+ * marked for verification. One example of this could be using key shortcuts for switching to
+ * another IME.
+ *
+ * @param keyEvent the event that may need verification.
+ * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch,
+ * {@code false} otherwise.
+ */
+ @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
+ @Override
+ public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent keyEvent) {
+ return false;
+ }
+
+ /**
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
* the event).
@@ -4392,6 +4453,39 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * Called when the requested visibility of a custom IME Switcher button changes.
+ *
+ * <p>When the system provides an IME navigation bar, it may decide to show an IME Switcher
+ * button inside this bar. However, the IME can request hiding the bar provided by the system
+ * with {@code getWindowInsetsController().hide(captionBar())} (the IME navigation bar provides
+ * {@link Type#captionBar() captionBar} insets to the IME window). If the request is successful,
+ * then it becomes the IME's responsibility to provide a custom IME Switcher button in its
+ * input view, with equivalent functionality.</p>
+ *
+ * <p>This custom button is only requested to be visible when the system provides the IME
+ * navigation bar, both the bar and the IME Switcher button inside it should be visible,
+ * but the IME successfully requested to hide the bar. This does not depend on the current
+ * visibility of the IME. It could be called with {@code true} while the IME is hidden, in
+ * which case the IME should prepare to show the button as soon as the IME itself is shown.</p>
+ *
+ * <p>This is only called when the requested visibility changes. The default value is
+ * {@code false} and as such, this will not be called initially if the resulting value is
+ * {@code false}.</p>
+ *
+ * <p>This can be called at any time after {@link #onCreate}, even if the IME is not currently
+ * visible. However, this is not guaranteed to be called before the IME is shown, as it depends
+ * on when the IME requested hiding the IME navigation bar. If the request is sent during
+ * the showing flow (e.g. during {@link #onStartInputView}), this will be called shortly after
+ * {@link #onWindowShown}, but before the first IME frame is drawn.</p>
+ *
+ * @param visible whether the button is requested visible or not.
+ */
+ @FlaggedApi(FLAG_IME_SWITCHER_REVAMP_API)
+ public void onCustomImeSwitcherButtonRequestedVisible(boolean visible) {
+ // Intentionally empty
+ }
+
+ /**
* Called when the IME switch button was clicked from the client. Depending on the number of
* enabled IME subtypes, this will either switch to the next IME/subtype, or show the input
* method picker dialog.
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index b08454dd7f8f..38be8d9f772d 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -41,6 +41,7 @@ import android.view.WindowInsets;
import android.view.WindowInsetsController.Appearance;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
@@ -178,6 +179,9 @@ final class NavigationBarController {
private boolean mDrawLegacyNavigationBarBackground;
+ /** Whether a custom IME Switcher button should be visible. */
+ private boolean mCustomImeSwitcherVisible;
+
private final Rect mTempRect = new Rect();
private final int[] mTempPos = new int[2];
@@ -265,6 +269,7 @@ final class NavigationBarController {
// IME navigation bar.
boolean visible = insets.isVisible(captionBar());
mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE);
+ checkCustomImeSwitcherVisibility();
}
return view.onApplyWindowInsets(insets);
});
@@ -491,6 +496,8 @@ final class NavigationBarController {
mShouldShowImeSwitcherWhenImeIsShown;
mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown;
+ checkCustomImeSwitcherVisibility();
+
mService.mWindow.getWindow().getDecorView().getWindowInsetsController()
.setImeCaptionBarInsetsHeight(getImeCaptionBarHeight(imeDrawsImeNavBar));
@@ -616,12 +623,33 @@ final class NavigationBarController {
&& mNavigationBarFrame.getVisibility() == View.VISIBLE;
}
+ /**
+ * Checks if a custom IME Switcher button should be visible, and notifies the IME when this
+ * state changes. This can only be {@code true} if three conditions are met:
+ *
+ * <li>The IME should draw the IME navigation bar.</li>
+ * <li>The IME Switcher button should be visible when the IME is visible.</li>
+ * <li>The IME navigation bar should be visible, but was requested hidden by the IME.</li>
+ */
+ private void checkCustomImeSwitcherVisibility() {
+ if (!Flags.imeSwitcherRevampApi()) {
+ return;
+ }
+ final boolean visible = mImeDrawsImeNavBar && mShouldShowImeSwitcherWhenImeIsShown
+ && mNavigationBarFrame != null && !isShown();
+ if (visible != mCustomImeSwitcherVisible) {
+ mCustomImeSwitcherVisible = visible;
+ mService.onCustomImeSwitcherButtonRequestedVisible(mCustomImeSwitcherVisible);
+ }
+ }
+
@Override
public String toDebugString() {
return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar
+ " mNavigationBarFrame=" + mNavigationBarFrame
+ " mShouldShowImeSwitcherWhenImeIsShown="
+ mShouldShowImeSwitcherWhenImeIsShown
+ + " mCustomImeSwitcherVisible=" + mCustomImeSwitcherVisible
+ " mAppearance=0x" + Integer.toHexString(mAppearance)
+ " mDarkIntensity=" + mDarkIntensity
+ " mDrawLegacyNavigationBarBackground=" + mDrawLegacyNavigationBarBackground
diff --git a/core/java/android/net/vcn/VcnFrameworkInitializer.java b/core/java/android/net/ConnectivityFrameworkInitializerBaklava.java
index 8cb213b306be..1f0fa92d7976 100644
--- a/core/java/android/net/vcn/VcnFrameworkInitializer.java
+++ b/core/java/android/net/ConnectivityFrameworkInitializerBaklava.java
@@ -14,15 +14,21 @@
* limitations under the License.
*/
-package android.net.vcn;
+package android.net;
+import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API;
+
+import android.annotation.FlaggedApi;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.app.SystemServiceRegistry;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.net.vcn.IVcnManagementService;
+import android.net.vcn.VcnManager;
import android.os.Build;
import android.os.SystemProperties;
@@ -31,8 +37,9 @@ import android.os.SystemProperties;
*
* @hide
*/
-// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES)
-public final class VcnFrameworkInitializer {
+@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class ConnectivityFrameworkInitializerBaklava {
/**
* Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link
* PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers
@@ -55,7 +62,7 @@ public final class VcnFrameworkInitializer {
*/
private static final int VENDOR_API_FOR_ANDROID_V = 202404;
- private VcnFrameworkInitializer() {}
+ private ConnectivityFrameworkInitializerBaklava() {}
// Suppressing AndroidFrameworkCompatChange because we're querying vendor
// partition SDK level, not application's target SDK version (which BTW we
@@ -86,7 +93,10 @@ public final class VcnFrameworkInitializer {
*
* @throws IllegalStateException if this is called anywhere besides {@link
* SystemServiceRegistry}.
+ * @hide
*/
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static void registerServiceWrappers() {
SystemServiceRegistry.registerContextAwareService(
VcnManager.VCN_MANAGEMENT_SERVICE_STRING,
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index af93c964a8ba..3219ce81c256 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -16,6 +16,7 @@
package android.net.vcn;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API;
import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
@@ -82,7 +83,15 @@ import java.util.concurrent.TimeUnit;
* </ul>
*/
public final class VcnGatewayConnectionConfig {
- /** @hide */
+ /**
+ * Minimum NAT timeout not set.
+ *
+ * <p>When the timeout is not set, the device will automatically choose a keepalive interval and
+ * may reduce the keepalive frequency for power-optimization.
+ */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ // This constant does not represent a minimum value. It indicates the value is not configured.
+ @SuppressLint("MinMaxConstant")
public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1;
/** @hide */
@@ -773,7 +782,7 @@ public final class VcnGatewayConnectionConfig {
*
* @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN
* Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN
- * Gateway.
+ * Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value.
* @return this {@link Builder} instance, for chaining
*/
@NonNull
@@ -781,8 +790,10 @@ public final class VcnGatewayConnectionConfig {
@IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS)
int minUdpPort4500NatTimeoutSeconds) {
Preconditions.checkArgument(
- minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
- "Timeout must be at least 120s");
+ minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
+ || minUdpPort4500NatTimeoutSeconds
+ >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
+ "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET");
mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
return this;
diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java
index 1fc91eea3138..3638429f33fb 100644
--- a/core/java/android/net/vcn/VcnTransportInfo.java
+++ b/core/java/android/net/vcn/VcnTransportInfo.java
@@ -17,13 +17,16 @@
package android.net.vcn;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API;
import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS;
import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.NetworkCapabilities;
import android.net.TransportInfo;
import android.net.wifi.WifiInfo;
@@ -52,23 +55,29 @@ import java.util.Objects;
* @hide
*/
// TODO: Do not store WifiInfo and subscription ID in VcnTransportInfo anymore
-public class VcnTransportInfo implements TransportInfo, Parcelable {
+@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class VcnTransportInfo implements TransportInfo, Parcelable {
@Nullable private final WifiInfo mWifiInfo;
private final int mSubId;
private final int mMinUdpPort4500NatTimeoutSeconds;
+ /** @hide */
public VcnTransportInfo(@NonNull WifiInfo wifiInfo) {
this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
}
+ /** @hide */
public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) {
this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds);
}
+ /** @hide */
public VcnTransportInfo(int subId) {
this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
}
+ /** @hide */
public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) {
this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds);
}
@@ -86,6 +95,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
* <p>If the underlying Network for the associated VCN is Cellular, returns null.
*
* @return the WifiInfo if there is an underlying WiFi connection, else null.
+ * @hide
*/
@Nullable
public WifiInfo getWifiInfo() {
@@ -100,17 +110,27 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
*
* @return the Subscription ID if a cellular underlying Network is present, else {@link
* android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ * @hide
*/
public int getSubId() {
return mSubId;
}
/**
- * Get the VCN provided UDP port 4500 NAT timeout
+ * Get the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping.
*
- * @return the UDP 4500 NAT timeout, or
+ * <p>To ensure uninterrupted connectivity, the device must send keepalive packets before the
+ * timeout. Failure to do so may result in the mapping being cleared and connection termination.
+ * This value is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs,
+ * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data.
+ *
+ * @return the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping, or
* VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set.
+ * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int)
+ * @hide
*/
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public int getMinUdpPort4500NatTimeoutSeconds() {
return mMinUdpPort4500NatTimeoutSeconds;
}
@@ -129,12 +149,21 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
&& mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@Override
public int describeContents() {
return 0;
}
+ /** @hide */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@Override
@NonNull
public TransportInfo makeCopy(long redactions) {
@@ -149,6 +178,9 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
mMinUdpPort4500NatTimeoutSeconds);
}
+ /** @hide */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@Override
public long getApplicableRedactions() {
long redactions = REDACT_FOR_NETWORK_SETTINGS;
@@ -161,7 +193,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
return redactions;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mSubId);
@@ -174,7 +212,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }";
}
- /** Implement the Parcelable interface */
+ /**
+ * Implement the Parcelable interface
+ *
+ * @hide
+ */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final @NonNull Creator<VcnTransportInfo> CREATOR =
new Creator<VcnTransportInfo>() {
public VcnTransportInfo createFromParcel(Parcel in) {
@@ -201,37 +245,63 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
}
};
- /** This class can be used to construct a {@link VcnTransportInfo}. */
+ /**
+ * This class can be used to construct a {@link VcnTransportInfo}.
+ *
+ * @hide
+ */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final class Builder {
private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
- /** Construct Builder */
+ /**
+ * Construct Builder
+ *
+ * @hide
+ */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public Builder() {}
/**
- * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout.
+ * Set the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping.
*
* <p>This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs,
* or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data.
*
- * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN
- * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN
- * Gateway.
+ * @param minUdpPort4500NatTimeoutSeconds the minimum duration that the VCN Gateway
+ * guarantees to preserve a NAT mapping, or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET}
+ * to clear this value. To ensure uninterrupted connectivity, the device must send
+ * keepalive packets within this interval. Failure to do so may result in the mapping
+ * being cleared and connection termination.
* @return this {@link Builder} instance, for chaining
+ * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int)
+ * @hide
*/
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
public Builder setMinUdpPort4500NatTimeoutSeconds(
@IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS)
int minUdpPort4500NatTimeoutSeconds) {
Preconditions.checkArgument(
- minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
- "Timeout must be at least 120s");
+ minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
+ || minUdpPort4500NatTimeoutSeconds
+ >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
+ "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET");
mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
return Builder.this;
}
- /** Build a VcnTransportInfo instance */
+ /**
+ * Build a VcnTransportInfo instance
+ *
+ * @hide
+ */
+ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
public VcnTransportInfo build() {
return new VcnTransportInfo(
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index 1b2c575917b2..b461f95fec53 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -1,5 +1,5 @@
package: "android.net.vcn"
-container: "system"
+container: "com.android.tethering"
flag {
name: "safe_mode_config"
@@ -15,14 +15,4 @@ flag {
description: "Expose APIs from VCN for mainline migration"
is_exported: true
bug: "376339506"
-}
-
-flag {
- name: "fix_config_garbage_collection"
- namespace: "vcn"
- description: "Handle race condition in subscription change"
- bug: "370862489"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
} \ No newline at end of file
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 3b5a99ed089a..01222cdd38b3 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -36,6 +36,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@@ -651,28 +652,39 @@ public final class BinderProxy implements IBinder {
private native boolean unlinkToDeathNative(DeathRecipient recipient, int flags);
/**
- * This list is to hold strong reference to the frozen state callbacks. The callbacks are only
- * weakly referenced by JNI so the strong references here are needed to keep the callbacks
- * around until the proxy is GC'ed.
+ * This map is to hold strong reference to the frozen state callbacks.
+ *
+ * The callbacks are only weakly referenced by JNI so the strong references here are needed to
+ * keep the callbacks around until the proxy is GC'ed.
+ *
+ * The key is the original callback passed into {@link #addFrozenStateChangeCallback}. The value
+ * is the wrapped callback created in {@link #addFrozenStateChangeCallback} to dispatch the
+ * calls on the desired executor.
*/
- private List<FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
- Collections.synchronizedList(new ArrayList<>());
+ private Map<FrozenStateChangeCallback, FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
+ Collections.synchronizedMap(new HashMap<>());
/**
* See {@link IBinder#addFrozenStateChangeCallback(FrozenStateChangeCallback)}
*/
- public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
+ public void addFrozenStateChangeCallback(Executor executor, FrozenStateChangeCallback callback)
throws RemoteException {
- addFrozenStateChangeCallbackNative(callback);
- mFrozenStateChangeCallbacks.add(callback);
+ FrozenStateChangeCallback wrappedCallback = (who, state) ->
+ executor.execute(() -> callback.onFrozenStateChanged(who, state));
+ addFrozenStateChangeCallbackNative(wrappedCallback);
+ mFrozenStateChangeCallbacks.put(callback, wrappedCallback);
}
/**
* See {@link IBinder#removeFrozenStateChangeCallback}
*/
- public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
- mFrozenStateChangeCallbacks.remove(callback);
- return removeFrozenStateChangeCallbackNative(callback);
+ public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback)
+ throws IllegalArgumentException {
+ FrozenStateChangeCallback wrappedCallback = mFrozenStateChangeCallbacks.remove(callback);
+ if (wrappedCallback == null) {
+ throw new IllegalArgumentException("callback not found");
+ }
+ return removeFrozenStateChangeCallbackNative(wrappedCallback);
}
private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback)
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 102bdd0b625c..c2e9260879a8 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -32,6 +32,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.sdk.Flags;
+import android.sysprop.BackportedFixesProperties;
import android.sysprop.DeviceProperties;
import android.sysprop.SocProperties;
import android.sysprop.TelephonyProperties;
@@ -1612,12 +1613,25 @@ public class Build {
* is not applicable on this device,
* otherwise {@link #BACKPORTED_FIX_STATUS_UNKNOWN}.
*/
-
@FlaggedApi(android.os.Flags.FLAG_API_FOR_BACKPORTED_FIXES)
public static @BackportedFixStatus int getBackportedFixStatus(long id) {
- // TODO: b/308461809 - query aliases from system prop
- // TODO: b/372518979 - use backported fix datastore.
- return BACKPORTED_FIX_STATUS_UNKNOWN;
+ if (id <= 0 || id > 1023) {
+ return BACKPORTED_FIX_STATUS_UNKNOWN;
+ }
+ return isBitSet(BackportedFixesProperties.alias_bitset(), (int) id)
+ ? BACKPORTED_FIX_STATUS_FIXED : BACKPORTED_FIX_STATUS_UNKNOWN;
+ }
+
+ private static boolean isBitSet(List<Long> bitsetLongArray, int bitIndex) {
+ // Because java.util.BitSet is not threadsafe do the calculations here instead.
+ if (bitIndex < 0) {
+ return false;
+ }
+ int arrayIndex = bitIndex >> 6;
+ if (bitsetLongArray.size() <= arrayIndex) {
+ return false;
+ }
+ return (bitsetLongArray.get(arrayIndex) & (1L << bitIndex)) != 0;
}
/**
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 99e7d166446e..05bd10b053fe 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -18,10 +18,12 @@ package android.os;
import static java.util.Objects.requireNonNull;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Size;
@@ -72,16 +74,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
/**
* Status when the Bundle can <b>assert</b> that the underlying Parcel DOES NOT contain
* Binder object(s).
- *
* @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int STATUS_BINDERS_NOT_PRESENT = 0;
/**
* Status when the Bundle can <b>assert</b> that there are Binder object(s) in the Parcel.
- *
* @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int STATUS_BINDERS_PRESENT = 1;
/**
@@ -94,9 +98,10 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
* object to the Bundle but it is not possible to assert this fact unless the Bundle is written
* to a Parcel.
* </p>
- *
* @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int STATUS_BINDERS_UNKNOWN = 2;
/** @hide */
@@ -417,6 +422,8 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
* Returns a status indicating whether the bundle contains any parcelled Binder objects.
* @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public @HasBinderStatus int hasBinders() {
if ((mFlags & FLAG_HAS_BINDERS_KNOWN) != 0) {
if ((mFlags & FLAG_HAS_BINDERS) != 0) {
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 7529ab9ab894..3e4d74546adc 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -31,7 +31,6 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import dalvik.annotation.optimization.NeverCompile;
-import dalvik.system.VMDebug;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
@@ -87,14 +86,20 @@ public final class MessageQueue {
// queue for async messages when inserting a message at the tail.
private int mAsyncMessageCount;
- /*
+ /**
* Select between two implementations of message queue. The legacy implementation is used
* by default as it provides maximum compatibility with applications and tests that
* reach into MessageQueue via the mMessages field. The concurrent implemmentation is used for
* system processes and provides a higher level of concurrency and higher enqueue throughput
* than the legacy implementation.
*/
- private boolean mUseConcurrent;
+ private final boolean mUseConcurrent;
+
+ /**
+ * Caches process-level checks that determine `mUseConcurrent`.
+ * This is to avoid redoing checks that shouldn't change during the process's lifetime.
+ */
+ private static Boolean sIsProcessAllowedToUseConcurrent = null;
@RavenwoodRedirect
private native static long nativeInit();
@@ -111,7 +116,35 @@ public final class MessageQueue {
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
MessageQueue(boolean quitAllowed) {
- mUseConcurrent = UserHandle.isCore(Process.myUid()) && !VMDebug.isDebuggingEnabled();
+ if (sIsProcessAllowedToUseConcurrent == null) {
+ // Concurrent mode modifies behavior that is observable via reflection and is commonly
+ // used by tests.
+ // For now, we limit it to system processes to avoid breaking apps and their tests.
+ boolean useConcurrent = UserHandle.isCore(Process.myUid());
+
+ // Some platform tests run in system UIDs.
+ // Use this awful heuristic to detect them.
+ if (useConcurrent) {
+ final String processName = Process.myProcessName();
+ if (processName.contains("test") || processName.contains("Test")) {
+ useConcurrent = false;
+ }
+ }
+
+ // We can lift this restriction in the future after we've made it possible for test
+ // authors to test Looper and MessageQueue without resorting to reflection.
+
+ // Holdback study.
+ if (useConcurrent && Flags.messageQueueForceLegacy()) {
+ useConcurrent = false;
+ }
+
+ sIsProcessAllowedToUseConcurrent = useConcurrent;
+ mUseConcurrent = useConcurrent;
+ } else {
+ mUseConcurrent = sIsProcessAllowedToUseConcurrent;
+ }
+
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
diff --git a/core/java/android/os/CpuHeadroomParams.java b/core/java/android/os/CpuHeadroomParams.java
new file mode 100644
index 000000000000..f0d4f7d8737f
--- /dev/null
+++ b/core/java/android/os/CpuHeadroomParams.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 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.os;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.os.health.SystemHealthManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Headroom request params used by {@link SystemHealthManager#getCpuHeadroom(CpuHeadroomParams)}.
+ */
+@FlaggedApi(Flags.FLAG_CPU_GPU_HEADROOMS)
+public final class CpuHeadroomParams {
+ final CpuHeadroomParamsInternal mInternal;
+
+ public CpuHeadroomParams() {
+ mInternal = new CpuHeadroomParamsInternal();
+ }
+
+ /** @hide */
+ @IntDef(flag = false, prefix = {"CPU_HEADROOM_CALCULATION_TYPE_"}, value = {
+ CPU_HEADROOM_CALCULATION_TYPE_MIN, // 0
+ CPU_HEADROOM_CALCULATION_TYPE_AVERAGE, // 1
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CpuHeadroomCalculationType {
+ }
+
+ /**
+ * Calculates the headroom based on minimum value over a device-defined window.
+ */
+ public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0;
+
+ /**
+ * Calculates the headroom based on average value over a device-defined window.
+ */
+ public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1;
+
+ /**
+ * Sets the headroom calculation type.
+ * <p>
+ *
+ * @throws IllegalArgumentException if the type is invalid.
+ */
+ public void setCalculationType(@CpuHeadroomCalculationType int calculationType) {
+ switch (calculationType) {
+ case CPU_HEADROOM_CALCULATION_TYPE_MIN:
+ case CPU_HEADROOM_CALCULATION_TYPE_AVERAGE:
+ mInternal.calculationType = (byte) calculationType;
+ return;
+ }
+ throw new IllegalArgumentException("Invalid calculation type: " + calculationType);
+ }
+
+ /**
+ * Gets the headroom calculation type.
+ * Default to {@link #CPU_HEADROOM_CALCULATION_TYPE_MIN} if not set.
+ */
+ public @CpuHeadroomCalculationType int getCalculationType() {
+ @CpuHeadroomCalculationType int validatedType = switch ((int) mInternal.calculationType) {
+ case CPU_HEADROOM_CALCULATION_TYPE_MIN, CPU_HEADROOM_CALCULATION_TYPE_AVERAGE ->
+ mInternal.calculationType;
+ default -> CPU_HEADROOM_CALCULATION_TYPE_MIN;
+ };
+ return validatedType;
+ }
+
+ /**
+ * @hide
+ */
+ public CpuHeadroomParamsInternal getInternal() {
+ return mInternal;
+ }
+}
diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl
new file mode 100644
index 000000000000..6cc4699a809e
--- /dev/null
+++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.os;
+
+import android.hardware.power.CpuHeadroomParams;
+
+/**
+ * Changes should be synced with match function of HintManagerService#CpuHeadroomCacheItem.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+parcelable CpuHeadroomParamsInternal {
+ boolean usesDeviceHeadroom = false;
+ CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN;
+ CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL;
+}
+
diff --git a/core/java/android/os/GpuHeadroomParams.java b/core/java/android/os/GpuHeadroomParams.java
new file mode 100644
index 000000000000..efb2a28ad2b5
--- /dev/null
+++ b/core/java/android/os/GpuHeadroomParams.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 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.os;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.os.health.SystemHealthManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Headroom request params used by {@link SystemHealthManager#getGpuHeadroom(GpuHeadroomParams)}.
+ */
+@FlaggedApi(Flags.FLAG_CPU_GPU_HEADROOMS)
+public final class GpuHeadroomParams {
+ final GpuHeadroomParamsInternal mInternal;
+
+ public GpuHeadroomParams() {
+ mInternal = new GpuHeadroomParamsInternal();
+ }
+
+ /** @hide */
+ @IntDef(flag = false, prefix = {"GPU_HEADROOM_CALCULATION_TYPE_"}, value = {
+ GPU_HEADROOM_CALCULATION_TYPE_MIN, // 0
+ GPU_HEADROOM_CALCULATION_TYPE_AVERAGE, // 1
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GpuHeadroomCalculationType {
+ }
+
+ /**
+ * Calculates the headroom based on minimum value over a device-defined window.
+ */
+ public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0;
+
+ /**
+ * Calculates the headroom based on average value over a device-defined window.
+ */
+ public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1;
+
+ /**
+ * Sets the headroom calculation type.
+ * <p>
+ *
+ * @throws IllegalArgumentException if the type is invalid.
+ */
+ public void setCalculationType(@GpuHeadroomCalculationType int calculationType) {
+ switch (calculationType) {
+ case GPU_HEADROOM_CALCULATION_TYPE_MIN:
+ case GPU_HEADROOM_CALCULATION_TYPE_AVERAGE:
+ mInternal.calculationType = (byte) calculationType;
+ return;
+ }
+ throw new IllegalArgumentException("Invalid calculation type: " + calculationType);
+ }
+
+ /**
+ * Gets the headroom calculation type.
+ * Default to {@link #GPU_HEADROOM_CALCULATION_TYPE_MIN} if not set.
+ */
+ public @GpuHeadroomCalculationType int getCalculationType() {
+ @GpuHeadroomCalculationType int validatedType = switch ((int) mInternal.calculationType) {
+ case GPU_HEADROOM_CALCULATION_TYPE_MIN, GPU_HEADROOM_CALCULATION_TYPE_AVERAGE ->
+ mInternal.calculationType;
+ default -> GPU_HEADROOM_CALCULATION_TYPE_MIN;
+ };
+ return validatedType;
+ }
+
+ /**
+ * @hide
+ */
+ public GpuHeadroomParamsInternal getInternal() {
+ return mInternal;
+ }
+}
diff --git a/core/java/android/os/GpuHeadroomParamsInternal.aidl b/core/java/android/os/GpuHeadroomParamsInternal.aidl
new file mode 100644
index 000000000000..20309e7673f2
--- /dev/null
+++ b/core/java/android/os/GpuHeadroomParamsInternal.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.os;
+
+import android.hardware.power.GpuHeadroomParams;
+
+/**
+ * Changes should be synced with match function of HintManagerService#GpuHeadroomCacheItem.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+parcelable GpuHeadroomParamsInternal {
+ GpuHeadroomParams.CalculationType calculationType = GpuHeadroomParams.CalculationType.MIN;
+}
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index a997f4c86704..8cfd32449537 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -25,6 +26,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
* Base interface for a remotable object, the core part of a lightweight
@@ -397,12 +399,31 @@ public interface IBinder {
@interface State {
}
+ /**
+ * Represents the frozen state of the remote process.
+ *
+ * While in this state, the remote process won't be able to receive and handle a
+ * transaction. Therefore, any asynchronous transactions will be buffered and delivered when
+ * the process is unfrozen, and any synchronous transactions will result in an error.
+ *
+ * Buffered transactions may be stale by the time that the process is unfrozen and handles
+ * them. To avoid overwhelming the remote process with stale events or overflowing their
+ * buffers, it's best to avoid sending binder transactions to a frozen process.
+ */
int STATE_FROZEN = 0;
+
+ /**
+ * Represents the unfrozen state of the remote process.
+ *
+ * In this state, the process hosting the object can execute and is not restricted
+ * by the freezer from using the CPU or responding to binder transactions.
+ */
int STATE_UNFROZEN = 1;
/**
* Interface for receiving a callback when the process hosting an IBinder
* has changed its frozen state.
+ *
* @param who The IBinder whose hosting process has changed state.
* @param state The latest state.
*/
@@ -427,16 +448,32 @@ public interface IBinder {
* <p>You will only receive state change notifications for remote binders, as local binders by
* definition can't be frozen without you being frozen too.</p>
*
+ * @param executor The executor on which to run the callback.
+ * @param callback The callback used to deliver state change notifications.
+ *
* <p>@throws {@link UnsupportedOperationException} if the kernel binder driver does not support
* this feature.
*/
@FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
- default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
+ default void addFrozenStateChangeCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull FrozenStateChangeCallback callback)
throws RemoteException {
throw new UnsupportedOperationException();
}
/**
+ * Same as {@link #addFrozenStateChangeCallback(Executor, FrozenStateChangeCallback)} except
+ * that callbacks are invoked on a binder thread.
+ *
+ * @hide
+ */
+ default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
+ throws RemoteException {
+ addFrozenStateChangeCallback(Runnable::run, callback);
+ }
+
+ /**
* Unregister a {@link FrozenStateChangeCallback}. The callback will no longer be invoked when
* the hosting process changes its frozen state.
*/
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index 73cdd5682f31..a043da9b7a36 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -17,7 +17,10 @@
package android.os;
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParamsInternal;
import android.os.IHintSession;
+import android.os.SessionCreationConfig;
import android.hardware.power.ChannelConfig;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
@@ -32,8 +35,8 @@ interface IHintManager {
* Throws UnsupportedOperationException if ADPF is not supported, and IllegalStateException
* if creation is supported but fails.
*/
- IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds,
- in long durationNanos, in SessionTag tag, out SessionConfig config);
+ IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag,
+ in SessionCreationConfig creationConfig, out SessionConfig config);
/**
* Get preferred rate limit in nanoseconds.
@@ -50,4 +53,13 @@ interface IHintManager {
*/
@nullable ChannelConfig getSessionChannel(in IBinder token);
oneway void closeSessionChannel();
+ float[] getCpuHeadroom(in CpuHeadroomParamsInternal params);
+ long getCpuHeadroomMinIntervalMillis();
+ float getGpuHeadroom(in GpuHeadroomParamsInternal params);
+ long getGpuHeadroomMinIntervalMillis();
+
+ /**
+ * Get Maximum number of graphics pipeline threads allowed per-app.
+ */
+ int getMaxGraphicsPipelineThreadsCount();
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 590ddb404b63..94259d7cf819 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -78,6 +78,9 @@ per-file PatternMatcher* = file:/PACKAGE_MANAGER_OWNERS
# PermissionEnforcer
per-file PermissionEnforcer.java = tweek@google.com, brufino@google.com
+# RemoteCallbackList
+per-file RemoteCallbackList.java = shayba@google.com
+
# ART
per-file ArtModuleServiceManager.java = file:platform/art:/OWNERS
@@ -86,6 +89,8 @@ per-file DdmSyncState.java = sanglardf@google.com, rpaquay@google.com
per-file DdmSyncStageUpdater.java = sanglardf@google.com, rpaquay@google.com
# PerformanceHintManager
+per-file CpuHeadroom*.aidl = file:/ADPF_OWNERS
+per-file GpuHeadroom*.aidl = file:/ADPF_OWNERS
per-file PerformanceHintManager.java = file:/ADPF_OWNERS
per-file WorkDuration.java = file:/ADPF_OWNERS
per-file IHintManager.aidl = file:/ADPF_OWNERS
@@ -125,3 +130,6 @@ per-file StatsServiceManager.java = file:/services/core/java/com/android/server/
# Dropbox
per-file DropBoxManager* = mwachens@google.com
+
+# Flags
+per-file flags.aconfig = file:/FF_LEADS_OWNERS
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index f7285523c01a..bf7116d6a05b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1371,7 +1371,6 @@ public final class Parcel {
writeInt(N);
if (DEBUG_ARRAY_MAP) {
RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
}
int startPos;
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index 224b10d0eaca..2b0042d653b1 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import com.android.internal.util.Preconditions;
@@ -106,7 +107,9 @@ public final class PerformanceHintManager {
* All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public static class Session implements Closeable {
- private long mNativeSessionPtr;
+ /** @hide */
+ @UnsupportedAppUsage
+ public long mNativeSessionPtr;
/** @hide */
public Session(long nativeSessionPtr) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 07fded19c799..9e7bf47ae83f 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1823,14 +1823,16 @@ public final class PowerManager {
}
/**
- * Returns the interactive state for a specific display, which may not be the same as the
- * global wakefulness (which is true when any display is awake).
+ * Returns true if the specified display is in an interactive state. This may not be the
+ * same as the global wakefulness (which is true when any display is interactive).
+ * @see #isInteractive()
*
- * @param displayId
- * @return whether the given display is present and interactive, or false
+ * @param displayId The Display ID to check for interactivity.
+ * @return True if the display is in an interactive state.
*
* @hide
*/
+ @TestApi
public boolean isInteractive(int displayId) {
return mInteractiveCache.query(displayId);
}
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 29ccb85c0bab..9435f4d59a2c 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -98,18 +98,6 @@ public abstract class PowerManagerInternal {
}
/**
- * Used by the window manager to override the screen brightness based on the
- * current foreground activity.
- *
- * This method must only be called by the window manager.
- *
- * @param brightness The overridden brightness, or Float.NaN to disable the override.
- * @param tag Source identifier of the app window that requests the override.
- */
- public abstract void setScreenBrightnessOverrideFromWindowManager(
- float brightness, CharSequence tag);
-
- /**
* Used by the window manager to override the user activity timeout based on the
* current foreground activity. It can only be used to make the timeout shorter
* than usual, not longer.
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 91c482faf7d7..4123209eb755 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -29,6 +30,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -134,6 +136,7 @@ public class RemoteCallbackList<E extends IInterface> {
private final @FrozenCalleePolicy int mFrozenCalleePolicy;
private final int mMaxQueueSize;
+ private final Executor mExecutor;
private final class Interface implements IBinder.DeathRecipient,
IBinder.FrozenStateChangeCallback {
@@ -197,7 +200,7 @@ public class RemoteCallbackList<E extends IInterface> {
void maybeSubscribeToFrozenCallback() throws RemoteException {
if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
try {
- mBinder.addFrozenStateChangeCallback(this);
+ mBinder.addFrozenStateChangeCallback(mExecutor, this);
} catch (UnsupportedOperationException e) {
// The kernel does not support frozen notifications. In this case we want to
// silently fall back to FROZEN_CALLEE_POLICY_UNSET. This is done by simply
@@ -211,7 +214,7 @@ public class RemoteCallbackList<E extends IInterface> {
if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
try {
mBinder.removeFrozenStateChangeCallback(this);
- } catch (UnsupportedOperationException e) {
+ } catch (UnsupportedOperationException | IllegalArgumentException e) {
// The kernel does not support frozen notifications. Ignore the error and move
// on.
}
@@ -237,6 +240,7 @@ public class RemoteCallbackList<E extends IInterface> {
private @FrozenCalleePolicy int mFrozenCalleePolicy;
private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
private InterfaceDiedCallback mInterfaceDiedCallback;
+ private Executor mExecutor;
/**
* Creates a Builder for {@link RemoteCallbackList}.
@@ -285,6 +289,18 @@ public class RemoteCallbackList<E extends IInterface> {
}
/**
+ * Sets the executor to be used when invoking callbacks asynchronously.
+ *
+ * This is only used when callbacks need to be invoked asynchronously, e.g. when the process
+ * hosting a callback becomes unfrozen. Callbacks that can be invoked immediately run on the
+ * same thread that calls {@link #broadcast} synchronously.
+ */
+ public @NonNull Builder setExecutor(@NonNull @CallbackExecutor Executor executor) {
+ mExecutor = executor;
+ return this;
+ }
+
+ /**
* For notifying when the process hosting a callback interface has died.
*
* @param <E> The remote callback interface type.
@@ -308,15 +324,21 @@ public class RemoteCallbackList<E extends IInterface> {
* @return The built {@link RemoteCallbackList} object.
*/
public @NonNull RemoteCallbackList<E> build() {
+ Executor executor = mExecutor;
+ if (executor == null && mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+ // TODO Throw an exception here once the existing API caller is updated to provide
+ // an executor.
+ executor = new HandlerExecutor(Handler.getMain());
+ }
if (mInterfaceDiedCallback != null) {
- return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize) {
+ return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor) {
@Override
public void onCallbackDied(E deadInterface, Object cookie) {
mInterfaceDiedCallback.onInterfaceDied(this, deadInterface, cookie);
}
};
}
- return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize);
+ return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor);
}
}
@@ -341,13 +363,23 @@ public class RemoteCallbackList<E extends IInterface> {
}
/**
+ * Returns the executor used when invoking callbacks asynchronously.
+ *
+ * @return The executor.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public @Nullable Executor getExecutor() {
+ return mExecutor;
+ }
+
+ /**
* Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to
* <pre>
* new RemoteCallbackList.Build(RemoteCallbackList.FROZEN_CALLEE_POLICY_UNSET).build()
* </pre>
*/
public RemoteCallbackList() {
- this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE);
+ this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE, null);
}
/**
@@ -362,10 +394,14 @@ public class RemoteCallbackList<E extends IInterface> {
* recipient's process is frozen. Once the limit is reached, the oldest callbacks would be
* dropped to keep the size under limit. Ignored except for
* {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
+ *
+ * @param executor The executor used when invoking callbacks asynchronously.
*/
- private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize) {
+ private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize,
+ @CallbackExecutor Executor executor) {
mFrozenCalleePolicy = frozenCalleePolicy;
mMaxQueueSize = maxQueueSize;
+ mExecutor = executor;
}
/**
diff --git a/core/java/android/os/SessionCreationConfig.aidl b/core/java/android/os/SessionCreationConfig.aidl
new file mode 100644
index 000000000000..cdc0ef461e0c
--- /dev/null
+++ b/core/java/android/os/SessionCreationConfig.aidl
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2024, 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.os;
+
+import android.hardware.power.SessionTag;
+import android.hardware.power.SessionMode;
+
+/** {@hide} */
+parcelable SessionCreationConfig {
+ /**
+ * List of tids to be included in the hint session.
+ */
+ int[] tids;
+
+ /**
+ * The initial target work duration of this hint session in nanoseconds.
+ */
+ long targetWorkDurationNanos;
+
+ /**
+ * List of the modes to be enabled upon session creation.
+ */
+ SessionMode[] modesToEnable;
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 4bc8fe0a974c..a1ede5fee3f3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3878,7 +3878,11 @@ public class UserManager {
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS})
+ @CachedProperty(api = "user_manager_user_data")
public UserInfo getUserInfo(@UserIdInt int userId) {
+ if (android.multiuser.Flags.cacheUserInfoReadOnly()) {
+ return UserManagerCache.getUserInfo(mService::getUserInfo, userId);
+ }
try {
return mService.getUserInfo(userId);
} catch (RemoteException re) {
@@ -3928,9 +3932,9 @@ public class UserManager {
final int callingUid = Binder.getCallingUid();
final int processUid = Process.myUid();
- if (Build.isDebuggable() && callingUid != processUid) {
- Log.w(TAG, "Uid " + processUid + " is fetching a copy of UserProperties on"
- + " behalf of callingUid " + callingUid + ". Possibly"
+ if (processUid == Process.SYSTEM_UID && callingUid != processUid) {
+ Log.w(TAG, "The System (uid " + processUid + ") is fetching a copy of"
+ + " UserProperties on behalf of callingUid " + callingUid + ". Possibly"
+ " it should carefully first clearCallingIdentity or perhaps use"
+ " UserManagerInternal.getUserProperties() instead?",
new Throwable());
@@ -5308,7 +5312,13 @@ public class UserManager {
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS}, conditional = true)
+ @CachedProperty(api = "user_manager_user_data")
public List<UserInfo> getProfiles(@UserIdInt int userId) {
+ if (android.multiuser.Flags.cacheProfilesReadOnly()) {
+ return UserManagerCache.getProfiles(
+ (Integer userIdentifier) -> mService.getProfiles(userIdentifier, false),
+ userId);
+ }
try {
return mService.getProfiles(userId, false /* enabledOnly */);
} catch (RemoteException re) {
@@ -6484,6 +6494,19 @@ public class UserManager {
}
/**
+ * This method is used to invalidate caches, when UserManagerService.mUsers
+ * {@link UserManagerService.UserData} is modified, including changes to {@link UserInfo}.
+ * In practice we determine modification by when that data is persisted, or scheduled to be
+ * presisted, to xml.
+ * @hide
+ */
+ public static final void invalidateCacheOnUserDataChanged() {
+ if (android.multiuser.Flags.cacheProfilesReadOnly()) {
+ UserManagerCache.invalidateProfiles();
+ }
+ }
+
+ /**
* Returns a serial number on this device for a given userId. User handles can be recycled
* when deleting and creating users, but serial numbers are not reused until the device is
* wiped.
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 0cffd9f990fd..0a0e80614fa7 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -18,6 +18,7 @@ package android.os;
import static android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS;
+import android.annotation.DurationMillisLong;
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
@@ -34,6 +35,7 @@ import android.hardware.vibrator.IVibrator;
import android.hardware.vibrator.V1_0.EffectStrength;
import android.hardware.vibrator.V1_3.Effect;
import android.net.Uri;
+import android.os.vibrator.BasicPwleSegment;
import android.os.vibrator.Flags;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
@@ -41,6 +43,7 @@ import android.os.vibrator.PwleSegment;
import android.os.vibrator.RampSegment;
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
+import android.os.vibrator.VibratorEnvelopeEffectInfo;
import android.os.vibrator.VibratorFrequencyProfileLegacy;
import android.util.MathUtils;
@@ -1483,6 +1486,15 @@ public abstract class VibrationEffect implements Parcelable {
public @interface PrimitiveType {
}
+ /** @hide */
+ @IntDef(prefix = { "DELAY_TYPE_" }, value = {
+ DELAY_TYPE_PAUSE,
+ DELAY_TYPE_RELATIVE_START_OFFSET,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DelayType {
+ }
+
/**
* Exception thrown when adding an element to a {@link Composition} that already ends in an
* indefinitely repeating effect.
@@ -1541,6 +1553,53 @@ public abstract class VibrationEffect implements Parcelable {
// Internally this maps to the HAL constant CompositePrimitive::LOW_TICK
public static final int PRIMITIVE_LOW_TICK = 8;
+ /**
+ * The delay represents a pause in the composition between the end of the previous primitive
+ * and the beginning of the next one.
+ *
+ * <p>The primitive will start after the requested pause after the last primitive ended.
+ * The actual time the primitive will be played depends on the previous primitive's actual
+ * duration on the device hardware. This enables the combination of primitives to create
+ * more complex effects based on how close to each other they'll play. Here is an example:
+ *
+ * <pre>
+ * VibrationEffect popEffect = VibrationEffect.startComposition()
+ * .addPrimitive(PRIMITIVE_QUICK_RISE)
+ * .addPrimitive(PRIMITIVE_CLICK, 0.7, 50, DELAY_TYPE_PAUSE)
+ * .compose()
+ * </pre>
+ */
+ @FlaggedApi(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public static final int DELAY_TYPE_PAUSE = 0;
+
+ /**
+ * The delay represents an offset before starting this primitive, relative to the start
+ * time of the previous primitive in the composition.
+ *
+ * <p>The primitive will start at the requested fixed time after the last primitive started,
+ * independently of that primitive's actual duration on the device hardware. This enables
+ * precise timings of primitives within a composition, ensuring they'll be played at the
+ * desired intervals. Here is an example:
+ *
+ * <pre>
+ * VibrationEffect.startComposition()
+ * .addPrimitive(PRIMITIVE_CLICK, 1.0)
+ * .addPrimitive(PRIMITIVE_TICK, 1.0, 20, DELAY_TYPE_RELATIVE_START_OFFSET)
+ * .addPrimitive(PRIMITIVE_THUD, 1.0, 80, DELAY_TYPE_RELATIVE_START_OFFSET)
+ * .compose()
+ * </pre>
+ *
+ * Will be performed on the device as follows:
+ *
+ * <pre>
+ * 0ms 20ms 100ms
+ * PRIMITIVE_CLICK---PRIMITIVE_TICK-----------PRIMITIVE_THUD
+ * </pre>
+ *
+ * <p>A primitive will be dropped from the composition if it overlaps with previous ones.
+ */
+ @FlaggedApi(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public static final int DELAY_TYPE_RELATIVE_START_OFFSET = 1;
private final ArrayList<VibrationEffectSegment> mSegments = new ArrayList<>();
private int mRepeatIndex = -1;
@@ -1656,16 +1715,38 @@ public abstract class VibrationEffect implements Parcelable {
/**
* Add a haptic primitive to the end of the current composition.
*
+ * <p>Similar to {@link #addPrimitive(int, float, int, int)}, but default
+ * delay type applied is {@link #DELAY_TYPE_PAUSE}.
+ *
* @param primitiveId The primitive to add
* @param scale The scale to apply to the intensity of the primitive.
- * @param delay The amount of time in milliseconds to wait before playing this primitive,
- * starting at the time the previous element in this composition is finished.
+ * @param delay The amount of time in milliseconds to wait between the end of the last
+ * primitive and the beginning of this one (i.e. a pause in the composition).
* @return This {@link Composition} object to enable adding multiple elements in one chain.
*/
@NonNull
public Composition addPrimitive(@PrimitiveType int primitiveId,
@FloatRange(from = 0f, to = 1f) float scale, @IntRange(from = 0) int delay) {
- PrimitiveSegment primitive = new PrimitiveSegment(primitiveId, scale, delay);
+ return addPrimitive(primitiveId, scale, delay, PrimitiveSegment.DEFAULT_DELAY_TYPE);
+ }
+
+ /**
+ * Add a haptic primitive to the end of the current composition.
+ *
+ * @param primitiveId The primitive to add
+ * @param scale The scale to apply to the intensity of the primitive.
+ * @param delay The amount of time in milliseconds to wait before playing this primitive,
+ * as defined by the given {@code delayType}.
+ * @param delayType The type of delay to be applied, e.g. a pause between last primitive and
+ * this one or a start offset.
+ * @return This {@link Composition} object to enable adding multiple elements in one chain.
+ */
+ @FlaggedApi(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ @NonNull
+ public Composition addPrimitive(@PrimitiveType int primitiveId,
+ @FloatRange(from = 0f, to = 1f) float scale, @IntRange(from = 0) int delay,
+ @DelayType int delayType) {
+ PrimitiveSegment primitive = new PrimitiveSegment(primitiveId, scale, delay, delayType);
primitive.validate();
return addSegment(primitive);
}
@@ -1733,52 +1814,20 @@ public abstract class VibrationEffect implements Parcelable {
default -> Integer.toString(id);
};
}
- }
-
- /**
- * Start building a waveform vibration.
- *
- * <p>The waveform envelope builder offers more flexibility for creating waveform effects,
- * allowing control over vibration amplitude and frequency via smooth transitions between
- * values. The waveform will start the first transition from the vibrator off state, using
- * the same frequency of the first control point. To provide a different initial vibration
- * frequency, use {@link #startWaveformEnvelope(float)}.
- *
- * <p>Note: To check whether waveform envelope effects are supported, use
- * {@link Vibrator#areEnvelopeEffectsSupported()}.
- *
- * @see VibrationEffect.WaveformEnvelopeBuilder
- */
- @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
- @NonNull
- public static VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope() {
- return new WaveformEnvelopeBuilder();
- }
- /**
- * Start building a waveform vibration with an initial frequency.
- *
- * <p>The waveform envelope builder offers more flexibility for creating waveform effects,
- * allowing control over vibration amplitude and frequency via smooth transitions between
- * values.
- *
- * <p>This is the same as {@link #startWaveformEnvelope()}, but the waveform will start
- * vibrating at given frequency, in hertz, while it transitions to the new amplitude and
- * frequency of the first control point.
- *
- * <p>Note: To check whether waveform envelope effects are supported, use
- * {@link Vibrator#areEnvelopeEffectsSupported()}.
- *
- * @param initialFrequencyHz The starting frequency of the vibration, in hertz. Must be greater
- * than zero.
- *
- * @see VibrationEffect.WaveformEnvelopeBuilder
- */
- @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
- @NonNull
- public static VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(
- @FloatRange(from = 0) float initialFrequencyHz) {
- return new WaveformEnvelopeBuilder(initialFrequencyHz);
+ /**
+ * Convert the delay type to a human readable string for debugging.
+ * @param type The delay type to convert
+ * @return The delay type in a human readable format.
+ * @hide
+ */
+ public static String delayTypeToString(@DelayType int type) {
+ return switch (type) {
+ case DELAY_TYPE_PAUSE -> "PAUSE";
+ case DELAY_TYPE_RELATIVE_START_OFFSET -> "START_OFFSET";
+ default -> Integer.toString(type);
+ };
+ }
}
/**
@@ -1792,13 +1841,15 @@ public abstract class VibrationEffect implements Parcelable {
* 100ms, holds that state for 200ms, and then ramps back down over 100ms:
*
* <pre>{@code
- * VibrationEffect effect = VibrationEffect.startWaveformEnvelope()
+ * VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
* .addControlPoint(1.0f, 120f, 100)
* .addControlPoint(1.0f, 120f, 200)
* .addControlPoint(0.0f, 120f, 100)
* .build();
* }</pre>
*
+ * <p>The builder automatically starts all effects at 0 amplitude.
+ *
* <p>It is crucial to ensure that the frequency range used in your effect is compatible with
* the device's capabilities. The framework will not play any frequencies that fall partially
* or completely outside the device's supported range. It will also not attempt to correct or
@@ -1819,27 +1870,55 @@ public abstract class VibrationEffect implements Parcelable {
*
* <p>You can use the following APIs to obtain these limits:
* <ul>
- * <li>Maximum envelope control points: {@link Vibrator#getMaxEnvelopeEffectSize()}</li>
+ * <li>Maximum envelope control points: {@link VibratorEnvelopeEffectInfo#getMaxSize()}
* <li>Minimum control point duration:
- * {@link Vibrator#getMinEnvelopeEffectControlPointDurationMillis()}</li>
+ * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}
* <li>Maximum control point duration:
- * {@link Vibrator#getMaxEnvelopeEffectControlPointDurationMillis()}</li>
- * <li>Maximum total effect duration: {@link Vibrator#getMaxEnvelopeEffectDurationMillis()}</li>
+ * {@link VibratorEnvelopeEffectInfo#getMaxControlPointDurationMillis()}
+ * <li>Maximum total effect duration: {@link VibratorEnvelopeEffectInfo#getMaxDurationMillis()}
* </ul>
- *
- * @see VibrationEffect#startWaveformEnvelope()
*/
@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public static final class WaveformEnvelopeBuilder {
private ArrayList<PwleSegment> mSegments = new ArrayList<>();
private float mLastAmplitude = 0f;
- private float mLastFrequencyHz = 0f;
+ private float mLastFrequencyHz = Float.NaN;
+
+ public WaveformEnvelopeBuilder() {}
+
+ /**
+ * Sets the initial frequency for the waveform in Hertz.
+ *
+ * <p>The effect will start vibrating at this frequency when it transitions to the
+ * amplitude and frequency defined by the first control point.
+ *
+ * <p>The frequency must be greater than zero and within the supported range. To determine
+ * the supported range, use {@link Vibrator#getFrequencyProfile()}. Creating
+ * effects using frequencies outside this range will result in the vibration not playing.
+ *
+ * @param initialFrequencyHz The starting frequency of the vibration, in Hz. Must be
+ * greater than zero.
+ */
+ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @SuppressWarnings("MissingGetterMatchingBuilder")// No getter to initial frequency once set.
+ @NonNull
+ public WaveformEnvelopeBuilder setInitialFrequencyHz(
+ @FloatRange(from = 0) float initialFrequencyHz) {
- private WaveformEnvelopeBuilder() {}
+ if (mSegments.isEmpty()) {
+ mLastFrequencyHz = initialFrequencyHz;
+ } else {
+ PwleSegment firstSegment = mSegments.getFirst();
+ mSegments.set(0, new PwleSegment(
+ firstSegment.getStartAmplitude(),
+ firstSegment.getEndAmplitude(),
+ initialFrequencyHz, // Update start frequency
+ firstSegment.getEndFrequencyHz(),
+ firstSegment.getDuration()));
+ }
- private WaveformEnvelopeBuilder(float initialFrequency) {
- mLastFrequencyHz = initialFrequency;
+ return this;
}
/**
@@ -1850,35 +1929,34 @@ public abstract class VibrationEffect implements Parcelable {
* perceived intensity. It's determined by the actuator response curve.
*
* <p>Frequency must be greater than zero and within the supported range. To determine
- * the supported range, use {@link Vibrator#getFrequencyProfile()}. This method returns a
- * {@link android.os.vibrator.VibratorFrequencyProfile} object, which contains the
- * minimum and maximum frequencies, among other frequency-related information. Creating
+ * the supported range, use {@link Vibrator#getFrequencyProfile()}. Creating
* effects using frequencies outside this range will result in the vibration not playing.
*
* <p>Time specifies the duration (in milliseconds) for the vibrator to smoothly transition
* from the previous control point to this new one. It must be greater than zero. To
* transition as quickly as possible, use
- * {@link Vibrator#getMinEnvelopeEffectControlPointDurationMillis()}.
+ * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}.
*
- * @param amplitude The amplitude value between 0 and 1, inclusive. 0 represents the
- * vibrator being off, and 1 represents the maximum achievable amplitude
- * at this frequency.
- * @param frequencyHz The frequency in Hz, must be greater than zero.
- * @param timeMillis The transition time in milliseconds.
+ * @param amplitude The amplitude value between 0 and 1, inclusive. 0 represents the
+ * vibrator being off, and 1 represents the maximum achievable
+ * amplitude
+ * at this frequency.
+ * @param frequencyHz The frequency in Hz, must be greater than zero.
+ * @param durationMillis The transition time in milliseconds.
*/
@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
@SuppressWarnings("MissingGetterMatchingBuilder") // No getters to segments once created.
@NonNull
public WaveformEnvelopeBuilder addControlPoint(
@FloatRange(from = 0, to = 1) float amplitude,
- @FloatRange(from = 0) float frequencyHz, int timeMillis) {
+ @FloatRange(from = 0) float frequencyHz, @DurationMillisLong long durationMillis) {
- if (mLastFrequencyHz == 0) {
+ if (Float.isNaN(mLastFrequencyHz)) {
mLastFrequencyHz = frequencyHz;
}
mSegments.add(new PwleSegment(mLastAmplitude, amplitude, mLastFrequencyHz, frequencyHz,
- timeMillis));
+ durationMillis));
mLastAmplitude = amplitude;
mLastFrequencyHz = frequencyHz;
@@ -1894,6 +1972,7 @@ public abstract class VibrationEffect implements Parcelable {
* calling this method again.
*
* @return The {@link VibrationEffect} resulting from the list of control points.
+ * @throws IllegalStateException if no control points were added to the builder.
*/
@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
@NonNull
@@ -1909,6 +1988,168 @@ public abstract class VibrationEffect implements Parcelable {
}
/**
+ * A builder for waveform effects defined by their envelope, designed to provide a consistent
+ * haptic perception across devices with varying capabilities.
+ *
+ * <p>This builder simplifies the creation of waveform effects by automatically adapting them
+ * to different devices based on their capabilities. Effects are defined by control points
+ * specifying target vibration intensity and sharpness, along with durations to reach those
+ * targets. The vibrator will smoothly transition between these control points.
+ *
+ * <p><b>Intensity:</b> Defines the overall strength of the vibration, ranging from
+ * 0 (off) to 1 (maximum achievable strength). Higher values result in stronger
+ * vibrations. Supported intensity values guarantee sensitivity levels (SL) above
+ * 10 dB SL to ensure human perception.
+ *
+ * <p><b>Sharpness:</b> Defines the crispness of the vibration, ranging from 0 to 1.
+ * Lower values produce smoother vibrations, while higher values create a sharper,
+ * more snappy sensation. Sharpness is mapped to its equivalent frequency within
+ * the device's supported frequency range.
+ *
+ * <p>While this builder handles most of the adaptation logic, it does come with some
+ * limitations:
+ * <ul>
+ * <li>It may not use the full range of frequencies</li>
+ * <li>It's restricted to a frequency range that can generate output of at least 10 db
+ * SL</li>
+ * <li>Effects must end with a zero intensity control point. Failure to end at a zero
+ * intensity control point will result in an {@link IllegalStateException}.</li>
+ * </ul>
+ *
+ * <p>The builder automatically starts all effects at 0 intensity.
+ *
+ * <p>To avoid these limitations and to have more control over the effects output, use
+ * {@link WaveformEnvelopeBuilder}, where direct amplitude and frequency values can be used.
+ *
+ * <p>For optimal cross-device consistency, it's recommended to limit the number of control
+ * points to a maximum of 16. However this is not mandatory, and if a pattern exceeds the
+ * maximum number of allowed control points, the framework will automatically break down the
+ * effect to ensure it plays correctly.
+ *
+ * <p>For example, the following code creates a vibration effect that ramps up the intensity
+ * from a low-pitched to a high-pitched strong vibration over 500ms and then ramps it down to
+ * 0 (off) over 100ms:
+ *
+ * <pre>{@code
+ * VibrationEffect effect = new VibrationEffect.BasicEnvelopeBuilder()
+ * .setInitialSharpness(0.0f)
+ * .addControlPoint(1.0f, 1.0f, 500)
+ * .addControlPoint(0.0f, 1.0f, 100)
+ * .build();
+ * }</pre>
+ */
+ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public static final class BasicEnvelopeBuilder {
+
+ private ArrayList<BasicPwleSegment> mSegments = new ArrayList<>();
+ private float mLastIntensity = 0f;
+ private float mLastSharpness = Float.NaN;
+
+ public BasicEnvelopeBuilder() {}
+
+ /**
+ * Sets the initial sharpness for the basic envelope effect.
+ *
+ * <p>The effect will start vibrating at this sharpness when it transitions to the
+ * intensity and sharpness defined by the first control point.
+ *
+ * <p> The sharpness defines the crispness of the vibration, ranging from 0 to 1. Lower
+ * values translate to smoother vibrations, while higher values create a sharper more snappy
+ * sensation. This value is mapped to the supported frequency range of the device.
+ *
+ * @param initialSharpness The starting sharpness of the vibration in the range of [0, 1].
+ */
+ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @SuppressWarnings("MissingGetterMatchingBuilder")// No getter to initial sharpness once set.
+ @NonNull
+ public BasicEnvelopeBuilder setInitialSharpness(
+ @FloatRange(from = 0, to = 1) float initialSharpness) {
+
+ if (mSegments.isEmpty()) {
+ mLastSharpness = initialSharpness;
+ } else {
+ BasicPwleSegment firstSegment = mSegments.getFirst();
+ mSegments.set(0, new BasicPwleSegment(
+ firstSegment.getStartIntensity(),
+ firstSegment.getEndIntensity(),
+ initialSharpness, // Update start sharpness
+ firstSegment.getEndSharpness(),
+ firstSegment.getDuration()));
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a new control point to the end of this waveform envelope.
+ *
+ * <p>Intensity defines the overall strength of the vibration, ranging from 0 (off) to 1
+ * (maximum achievable strength). Higher values translate to stronger vibrations.
+ *
+ * <p>Sharpness defines the crispness of the vibration, ranging from 0 to 1. Lower
+ * values translate to smoother vibrations, while higher values create a sharper more snappy
+ * sensation. This value is mapped to the supported frequency range of the device.
+ *
+ * <p>Time specifies the duration (in milliseconds) for the vibrator to smoothly transition
+ * from the previous control point to this new one. It must be greater than zero. To
+ * transition as quickly as possible, use
+ * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}.
+ *
+ * @param intensity The target vibration intensity, ranging from 0 (off) to 1 (maximum
+ * strength).
+ * @param sharpness The target sharpness, ranging from 0 (smoothest) to 1 (sharpest).
+ * @param durationMillis The transition time in milliseconds.
+ */
+ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @SuppressWarnings("MissingGetterMatchingBuilder") // No getters to segments once created.
+ @NonNull
+ public BasicEnvelopeBuilder addControlPoint(
+ @FloatRange(from = 0, to = 1) float intensity,
+ @FloatRange(from = 0, to = 1) float sharpness,
+ @DurationMillisLong long durationMillis) {
+
+ if (Float.isNaN(mLastSharpness)) {
+ mLastSharpness = sharpness;
+ }
+
+ mSegments.add(new BasicPwleSegment(mLastIntensity, intensity, mLastSharpness, sharpness,
+ durationMillis));
+
+ mLastIntensity = intensity;
+ mLastSharpness = sharpness;
+
+ return this;
+ }
+
+ /**
+ * Build the waveform as a single {@link VibrationEffect}.
+ *
+ * <p>The {@link BasicEnvelopeBuilder} object is still valid after this call, so you can
+ * continue adding more primitives to it and generating more {@link VibrationEffect}s by
+ * calling this method again.
+ *
+ * @return The {@link VibrationEffect} resulting from the list of control points.
+ * @throws IllegalStateException if the last control point does not end at zero intensity.
+ */
+ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @NonNull
+ public VibrationEffect build() {
+ if (mSegments.isEmpty()) {
+ throw new IllegalStateException(
+ "BasicEnvelopeBuilder must have at least one control point to build.");
+ }
+ if (mSegments.getLast().getEndIntensity() != 0) {
+ throw new IllegalStateException(
+ "Basic envelope effects must end at a zero intensity control point.");
+ }
+ VibrationEffect effect = new Composed(mSegments, /* repeatIndex= */ -1);
+ effect.validate();
+ return effect;
+ }
+
+ }
+
+ /**
* A builder for waveform haptic effects.
*
* <p>Waveform vibrations constitute of one or more timed transitions to new sets of vibration
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 53f8a9267499..86209140ce51 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -35,6 +35,7 @@ import android.media.AudioAttributes;
import android.os.vibrator.Flags;
import android.os.vibrator.VendorVibrationSession;
import android.os.vibrator.VibrationConfig;
+import android.os.vibrator.VibratorEnvelopeEffectInfo;
import android.os.vibrator.VibratorFrequencyProfile;
import android.os.vibrator.VibratorFrequencyProfileLegacy;
import android.util.Log;
@@ -137,6 +138,9 @@ public abstract class Vibrator {
@Nullable
private volatile VibrationConfig mVibrationConfig;
+ private VibratorFrequencyProfile mVibratorFrequencyProfile;
+ private VibratorEnvelopeEffectInfo mVibratorEnvelopeEffectInfo;
+
/**
* @hide to prevent subclassing from outside of the framework
*/
@@ -351,7 +355,11 @@ public abstract class Vibrator {
return null;
}
- return new VibratorFrequencyProfile(frequencyProfile);
+ if (mVibratorFrequencyProfile == null) {
+ mVibratorFrequencyProfile = new VibratorFrequencyProfile(frequencyProfile);
+ }
+
+ return mVibratorFrequencyProfile;
}
/**
@@ -383,70 +391,28 @@ public abstract class Vibrator {
}
/**
- * Retrieves the maximum duration supported for an envelope effect, in milliseconds.
- *
- * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
- * this value will be positive. Devices with envelope effects capabilities guarantees a
- * maximum duration equivalent to the product of {@link #getMaxEnvelopeEffectSize()} and
- * {@link #getMaxEnvelopeEffectControlPointDurationMillis()}. If the device does not support
- * envelope effects, this method will return 0.
- *
- * @return The maximum duration (in milliseconds) allowed for an envelope effect, or 0 if
- * envelope effects are not supported.
- */
- @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
- public int getMaxEnvelopeEffectDurationMillis() {
- return getInfo().getMaxEnvelopeEffectDurationMillis();
- }
-
- /**
- * Retrieves the maximum number of control points supported for an envelope effect.
- *
- * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
- * this value will be positive. Devices with envelope effects capabilities guarantee support
- * for a minimum of 16 control points. If the device does not support envelope effects,
- * this method will return 0.
+ * Retrieves the vibrator's capabilities and limitations for envelope effects.
*
- * @return the maximum number of control points allowed for an envelope effect, or 0 if
- * envelope effects are not supported.
- */
- @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
- public int getMaxEnvelopeEffectSize() {
- return getInfo().getMaxEnvelopeEffectSize();
- }
-
- /**
- * Retrieves the minimum duration supported between two control points within an envelope
- * effect, in milliseconds.
+ * <p>These parameters can be used with {@link VibrationEffect.WaveformEnvelopeBuilder}
+ * to create custom envelope effects.
*
- * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
- * this value will be positive. Devices with envelope effects capabilities guarantee
- * support for durations down to at least 20 milliseconds. If the device does
- * not support envelope effects, this method will return 0.
+ * @return The vibrator's envelope effect information, or null if not supported. If this
+ * vibrator is a composite of multiple physical devices then this will return a profile
+ * supported in all devices, or null if the intersection is empty or not available.
*
- * @return the minimum allowed duration between two control points in an envelope effect,
- * or 0 if envelope effects are not supported.
+ * @see VibrationEffect.WaveformEnvelopeBuilder
*/
@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
- public int getMinEnvelopeEffectControlPointDurationMillis() {
- return getInfo().getMinEnvelopeEffectControlPointDurationMillis();
- }
+ @NonNull
+ public VibratorEnvelopeEffectInfo getEnvelopeEffectInfo() {
+ if (mVibratorEnvelopeEffectInfo == null) {
+ mVibratorEnvelopeEffectInfo = new VibratorEnvelopeEffectInfo(
+ getInfo().getMaxEnvelopeEffectSize(),
+ getInfo().getMinEnvelopeEffectControlPointDurationMillis(),
+ getInfo().getMaxEnvelopeEffectControlPointDurationMillis());
+ }
- /**
- * Retrieves the maximum duration supported between two control points within an envelope
- * effect, in milliseconds.
- *
- * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
- * this value will be positive. Devices with envelope effects capabilities guarantee support
- * for durations up to at least 1 second. If the device does not support envelope effects,
- * this method will return 0.
- *
- * @return the maximum allowed duration between two control points in an envelope effect,
- * or 0 if envelope effects are not supported.
- */
- @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
- public int getMaxEnvelopeEffectControlPointDurationMillis() {
- return getInfo().getMaxEnvelopeEffectControlPointDurationMillis();
+ return mVibratorEnvelopeEffectInfo;
}
/**
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 9dec8673f019..84325a4ac70b 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -121,7 +121,7 @@ public class VibratorInfo implements Parcelable {
* @param qFactor The vibrator quality factor.
* @param frequencyProfileLegacy The description of the vibrator supported frequencies and max
* amplitude mappings.
- * @param frequencyProfile The description of the vibrator supported frequencies and
+ * @param frequencyProfile The description of the vibrator supported frequencies and
* output acceleration mappings.
* @param maxEnvelopeEffectSize The maximum number of control points supported for an
* envelope effect.
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index d9db28e0b3c3..e5340a70acec 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -4,6 +4,15 @@ container: "system"
# keep-sorted start block=yes newline_separated=yes
flag {
+ # Holdback study for concurrent MessageQueue.
+ # Do not promote beyond trunkfood.
+ namespace: "system_performance"
+ name: "message_queue_force_legacy"
+ description: "Whether to holdback concurrent MessageQueue (force legacy)."
+ bug: "336880969"
+}
+
+flag {
name: "adpf_gpu_report_actual_work_duration"
is_exported: true
namespace: "game"
@@ -12,6 +21,15 @@ flag {
}
flag {
+ name: "adpf_graphics_pipeline"
+ is_exported: true
+ namespace: "game"
+ description: "Guards use of SessionCreationConfig and Graphics Pipeline mode"
+ is_fixed_read_only: true
+ bug: "367803904"
+}
+
+flag {
name: "adpf_hwui_gpu"
namespace: "game"
description: "Guards use of the FMQ channel for ADPF"
@@ -66,6 +84,14 @@ flag {
}
flag {
+ name: "adpf_use_load_hints"
+ namespace: "game"
+ description: "Guards use of the ADPF public load hints behind a readonly flag"
+ is_fixed_read_only: true
+ bug: "367803904"
+}
+
+flag {
name: "allow_consentless_bugreport_delegated_consent"
namespace: "crumpet"
description: "Allow privileged apps to call bugreport generation without enforcing user consent and delegate it to the calling app instead"
@@ -148,6 +174,13 @@ flag {
}
flag {
+ name: "cpu_gpu_headrooms"
+ namespace: "game"
+ description: "Feature flag for adding CPU/GPU headroom API"
+ bug: "346604998"
+}
+
+flag {
name: "disallow_cellular_null_ciphers_restriction"
namespace: "cellular_security"
description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices."
@@ -179,6 +212,17 @@ flag {
}
flag {
+ name: "material_colors_10_2024"
+ namespace: "systemui"
+ description: "Adding new Material Tokens as of October 2024"
+ bug: "376195115"
+ is_exported: true
+ metadata {
+ purpose: PURPOSE_FEATURE
+ }
+}
+
+flag {
name: "message_queue_tail_tracking"
namespace: "system_performance"
description: "track tail of message queue."
@@ -253,6 +297,15 @@ flag {
flag {
namespace: "system_performance"
+ name: "enable_has_binders"
+ is_exported: true
+ description: "Add hasBinders to Public API under a flag."
+ is_fixed_read_only: true
+ bug: "330345513"
+}
+
+flag {
+ namespace: "system_performance"
name: "perfetto_sdk_tracing"
description: "Tracing using Perfetto SDK."
bug: "303199244"
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index deabfed365a6..4db9bc333e2b 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -17,6 +17,7 @@
package android.os.health;
import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
@@ -25,6 +26,11 @@ import android.content.Context;
import android.os.BatteryStats;
import android.os.Build;
import android.os.Bundle;
+import android.os.CpuHeadroomParams;
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParams;
+import android.os.GpuHeadroomParamsInternal;
+import android.os.IHintManager;
import android.os.IPowerStatsService;
import android.os.OutcomeReceiver;
import android.os.PowerMonitor;
@@ -68,6 +74,8 @@ public class SystemHealthManager {
private final IBatteryStats mBatteryStats;
@Nullable
private final IPowerStatsService mPowerStats;
+ @Nullable
+ private final IHintManager mHintManager;
private List<PowerMonitor> mPowerMonitorsInfo;
private final Object mPowerMonitorsLock = new Object();
private static final long TAKE_UID_SNAPSHOT_TIMEOUT_MILLIS = 10_000;
@@ -88,14 +96,111 @@ public class SystemHealthManager {
public SystemHealthManager() {
this(IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME)),
IPowerStatsService.Stub.asInterface(
- ServiceManager.getService(Context.POWER_STATS_SERVICE)));
+ ServiceManager.getService(Context.POWER_STATS_SERVICE)),
+ IHintManager.Stub.asInterface(
+ ServiceManager.getService(Context.PERFORMANCE_HINT_SERVICE)));
}
/** {@hide} */
public SystemHealthManager(@NonNull IBatteryStats batteryStats,
- @Nullable IPowerStatsService powerStats) {
+ @Nullable IPowerStatsService powerStats, @Nullable IHintManager hintManager) {
mBatteryStats = batteryStats;
mPowerStats = powerStats;
+ mHintManager = hintManager;
+ }
+
+ /**
+ * Provides an estimate of global available CPU headroom of the calling thread.
+ * <p>
+ *
+ * @param params params to customize the CPU headroom calculation, null to use default params.
+ * @return a single value a {@code Float.NaN} if it's temporarily unavailable.
+ * A valid value is ranged from [0, 100], where 0 indicates no more CPU resources can be
+ * granted.
+ * @throws UnsupportedOperationException if the API is unsupported or the request params can't
+ * be served.
+ */
+ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+ public @FloatRange(from = 0f, to = 100f) float getCpuHeadroom(
+ @Nullable CpuHeadroomParams params) {
+ if (mHintManager == null) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return mHintManager.getCpuHeadroom(
+ params != null ? params.getInternal() : new CpuHeadroomParamsInternal())[0];
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+
+
+ /**
+ * Provides an estimate of global available GPU headroom of the device.
+ * <p>
+ *
+ * @param params params to customize the GPU headroom calculation, null to use default params.
+ * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable.
+ * A valid value is ranged from [0, 100], where 0 indicates no more GPU resources can be
+ * granted.
+ * @throws UnsupportedOperationException if the API is unsupported or the request params can't
+ * be served.
+ */
+ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+ public @FloatRange(from = 0f, to = 100f) float getGpuHeadroom(
+ @Nullable GpuHeadroomParams params) {
+ if (mHintManager == null) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return mHintManager.getGpuHeadroom(
+ params != null ? params.getInternal() : new GpuHeadroomParamsInternal());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Minimum polling interval for calling {@link #getCpuHeadroom(CpuHeadroomParams)} in
+ * milliseconds.
+ * <p>
+ * The {@link #getCpuHeadroom(CpuHeadroomParams)} API may return cached result if called more
+ * frequent than the interval.
+ *
+ * @throws UnsupportedOperationException if the API is unsupported.
+ */
+ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+ public long getCpuHeadroomMinIntervalMillis() {
+ if (mHintManager == null) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return mHintManager.getCpuHeadroomMinIntervalMillis();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Minimum polling interval for calling {@link #getGpuHeadroom(GpuHeadroomParams)} in
+ * milliseconds.
+ * <p>
+ * The {@link #getGpuHeadroom(GpuHeadroomParams)} API may return cached result if called more
+ * frequent than the interval.
+ *
+ * @throws UnsupportedOperationException if the API is unsupported.
+ */
+ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+ public long getGpuHeadroomMinIntervalMillis() {
+ if (mHintManager == null) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return mHintManager.getGpuHeadroomMinIntervalMillis();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
/**
@@ -261,7 +366,7 @@ public class SystemHealthManager {
mPowerMonitorsInfo = result;
}
if (executor != null) {
- executor.execute(()-> onResult.accept(result));
+ executor.execute(() -> onResult.accept(result));
} else {
onResult.accept(result);
}
diff --git a/core/java/android/os/vibrator/BasicPwleSegment.java b/core/java/android/os/vibrator/BasicPwleSegment.java
new file mode 100644
index 000000000000..ed68173404a1
--- /dev/null
+++ b/core/java/android/os/vibrator/BasicPwleSegment.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2024 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.os.vibrator;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.VibrationEffect;
+import android.os.VibratorInfo;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * A {@link VibrationEffectSegment} that represents a smooth transition from the starting
+ * intensity and sharpness to new values over a specified duration.
+ *
+ * <p>The intensity and sharpness are expressed by float values in the range [0, 1], where
+ * intensity represents the user-perceived strength of the vibration, while sharpness represents
+ * the crispness of the vibration.
+ *
+ * @hide
+ */
+@TestApi
+@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+public final class BasicPwleSegment extends VibrationEffectSegment {
+ private final float mStartIntensity;
+ private final float mEndIntensity;
+ private final float mStartSharpness;
+ private final float mEndSharpness;
+ private final long mDuration;
+
+ BasicPwleSegment(@NonNull Parcel in) {
+ this(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat(), in.readLong());
+ }
+
+ /** @hide */
+ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public BasicPwleSegment(float startIntensity, float endIntensity, float startSharpness,
+ float endSharpness, long duration) {
+ mStartIntensity = startIntensity;
+ mEndIntensity = endIntensity;
+ mStartSharpness = startSharpness;
+ mEndSharpness = endSharpness;
+ mDuration = duration;
+ }
+
+ public float getStartIntensity() {
+ return mStartIntensity;
+ }
+
+ public float getEndIntensity() {
+ return mEndIntensity;
+ }
+
+ public float getStartSharpness() {
+ return mStartSharpness;
+ }
+
+ public float getEndSharpness() {
+ return mEndSharpness;
+ }
+
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof BasicPwleSegment)) {
+ return false;
+ }
+ BasicPwleSegment other = (BasicPwleSegment) o;
+ return Float.compare(mStartIntensity, other.mStartIntensity) == 0
+ && Float.compare(mEndIntensity, other.mEndIntensity) == 0
+ && Float.compare(mStartSharpness, other.mStartSharpness) == 0
+ && Float.compare(mEndSharpness, other.mEndSharpness) == 0
+ && mDuration == other.mDuration;
+ }
+
+ /** @hide */
+ @Override
+ public boolean areVibrationFeaturesSupported(@NonNull VibratorInfo vibratorInfo) {
+ return vibratorInfo.areEnvelopeEffectsSupported();
+ }
+
+ /** @hide */
+ @Override
+ public boolean isHapticFeedbackCandidate() {
+ return true;
+ }
+
+ /** @hide */
+ @Override
+ public void validate() {
+ Preconditions.checkArgumentInRange(mStartSharpness, 0f, 1f, "startSharpness");
+ Preconditions.checkArgumentInRange(mEndSharpness, 0f, 1f, "endSharpness");
+ Preconditions.checkArgumentInRange(mStartIntensity, 0f, 1f, "startIntensity");
+ Preconditions.checkArgumentInRange(mEndIntensity, 0f, 1f, "endIntensity");
+ Preconditions.checkArgumentPositive(mDuration, "Time must be greater than zero.");
+ }
+
+ /** @hide */
+ @NonNull
+ @Override
+ public BasicPwleSegment resolve(int defaultAmplitude) {
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
+ @Override
+ public BasicPwleSegment scale(float scaleFactor) {
+ float newStartIntensity = VibrationEffect.scale(mStartIntensity, scaleFactor);
+ float newEndIntensity = VibrationEffect.scale(mEndIntensity, scaleFactor);
+ if (Float.compare(mStartIntensity, newStartIntensity) == 0
+ && Float.compare(mEndIntensity, newEndIntensity) == 0) {
+ return this;
+ }
+ return new BasicPwleSegment(newStartIntensity, newEndIntensity, mStartSharpness,
+ mEndSharpness,
+ mDuration);
+ }
+
+ /** @hide */
+ @NonNull
+ @Override
+ public BasicPwleSegment scaleLinearly(float scaleFactor) {
+ float newStartIntensity = VibrationEffect.scaleLinearly(mStartIntensity, scaleFactor);
+ float newEndIntensity = VibrationEffect.scaleLinearly(mEndIntensity, scaleFactor);
+ if (Float.compare(mStartIntensity, newStartIntensity) == 0
+ && Float.compare(mEndIntensity, newEndIntensity) == 0) {
+ return this;
+ }
+ return new BasicPwleSegment(newStartIntensity, newEndIntensity, mStartSharpness,
+ mEndSharpness,
+ mDuration);
+ }
+
+ /** @hide */
+ @NonNull
+ @Override
+ public BasicPwleSegment applyEffectStrength(int effectStrength) {
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mStartIntensity, mEndIntensity, mStartSharpness, mEndSharpness,
+ mDuration);
+ }
+
+ @Override
+ public String toString() {
+ return "BasicPwle{startIntensity=" + mStartIntensity
+ + ", endIntensity=" + mEndIntensity
+ + ", startSharpness=" + mStartSharpness
+ + ", endSharpness=" + mEndSharpness
+ + ", duration=" + mDuration
+ + "}";
+ }
+
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ return String.format(Locale.US, "Pwle=%dms(intensity=%.2f @ %.2f to %.2f @ %.2f)",
+ mDuration,
+ mStartIntensity,
+ mStartSharpness,
+ mEndIntensity,
+ mEndSharpness);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(PARCEL_TOKEN_PWLE);
+ dest.writeFloat(mStartIntensity);
+ dest.writeFloat(mEndIntensity);
+ dest.writeFloat(mStartSharpness);
+ dest.writeFloat(mEndSharpness);
+ dest.writeLong(mDuration);
+ }
+
+ @NonNull
+ public static final Creator<BasicPwleSegment> CREATOR =
+ new Creator<BasicPwleSegment>() {
+ @Override
+ public BasicPwleSegment createFromParcel(Parcel in) {
+ // Skip the type token
+ in.readInt();
+ return new BasicPwleSegment(in);
+ }
+
+ @Override
+ public BasicPwleSegment[] newArray(int size) {
+ return new BasicPwleSegment[size];
+ }
+ };
+}
diff --git a/core/java/android/os/vibrator/PrimitiveSegment.java b/core/java/android/os/vibrator/PrimitiveSegment.java
index 91653edd1ba5..889d735c1d39 100644
--- a/core/java/android/os/vibrator/PrimitiveSegment.java
+++ b/core/java/android/os/vibrator/PrimitiveSegment.java
@@ -26,6 +26,7 @@ import android.os.VibratorInfo;
import com.android.internal.util.Preconditions;
+import java.util.Locale;
import java.util.Objects;
/**
@@ -43,19 +44,29 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
/** @hide */
public static final int DEFAULT_DELAY_MILLIS = 0;
+ /** @hide */
+ public static final int DEFAULT_DELAY_TYPE = VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+
private final int mPrimitiveId;
private final float mScale;
private final int mDelay;
+ private final int mDelayType;
PrimitiveSegment(@NonNull Parcel in) {
- this(in.readInt(), in.readFloat(), in.readInt());
+ this(in.readInt(), in.readFloat(), in.readInt(), in.readInt());
}
/** @hide */
public PrimitiveSegment(int id, float scale, int delay) {
+ this(id, scale, delay, DEFAULT_DELAY_TYPE);
+ }
+
+ /** @hide */
+ public PrimitiveSegment(int id, float scale, int delay, int delayType) {
mPrimitiveId = id;
mScale = scale;
mDelay = delay;
+ mDelayType = delayType;
}
public int getPrimitiveId() {
@@ -70,6 +81,11 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
return mDelay;
}
+ /** @hide */
+ public int getDelayType() {
+ return mDelayType;
+ }
+
@Override
public long getDuration() {
return -1;
@@ -112,8 +128,7 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
if (Float.compare(mScale, newScale) == 0) {
return this;
}
-
- return new PrimitiveSegment(mPrimitiveId, newScale, mDelay);
+ return new PrimitiveSegment(mPrimitiveId, newScale, mDelay, mDelayType);
}
/** @hide */
@@ -124,8 +139,7 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
if (Float.compare(mScale, newScale) == 0) {
return this;
}
-
- return new PrimitiveSegment(mPrimitiveId, newScale, mDelay);
+ return new PrimitiveSegment(mPrimitiveId, newScale, mDelay, mDelayType);
}
/** @hide */
@@ -142,6 +156,7 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
VibrationEffect.Composition.PRIMITIVE_LOW_TICK, "primitiveId");
Preconditions.checkArgumentInRange(mScale, 0f, 1f, "scale");
VibrationEffectSegment.checkDurationArgument(mDelay, "delay");
+ Preconditions.checkArgument(isValidDelayType(mDelayType), "delayType");
}
@Override
@@ -150,6 +165,7 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
dest.writeInt(mPrimitiveId);
dest.writeFloat(mScale);
dest.writeInt(mDelay);
+ dest.writeInt(mDelayType);
}
@Override
@@ -163,14 +179,16 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
+ "primitive=" + VibrationEffect.Composition.primitiveToString(mPrimitiveId)
+ ", scale=" + mScale
+ ", delay=" + mDelay
+ + ", delayType=" + VibrationEffect.Composition.delayTypeToString(mDelayType)
+ '}';
}
/** @hide */
@Override
public String toDebugString() {
- return String.format("Primitive=%s(scale=%.2f, delay=%dms)",
- VibrationEffect.Composition.primitiveToString(mPrimitiveId), mScale, mDelay);
+ return String.format(Locale.ROOT, "Primitive=%s(scale=%.2f, %s=%dms)",
+ VibrationEffect.Composition.primitiveToString(mPrimitiveId), mScale,
+ toDelayTypeDebugString(mDelayType), mDelay);
}
@Override
@@ -180,12 +198,28 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
PrimitiveSegment that = (PrimitiveSegment) o;
return mPrimitiveId == that.mPrimitiveId
&& Float.compare(that.mScale, mScale) == 0
- && mDelay == that.mDelay;
+ && mDelay == that.mDelay
+ && mDelayType == that.mDelayType;
}
@Override
public int hashCode() {
- return Objects.hash(mPrimitiveId, mScale, mDelay);
+ return Objects.hash(mPrimitiveId, mScale, mDelay, mDelayType);
+ }
+
+ private static boolean isValidDelayType(int delayType) {
+ return switch (delayType) {
+ case VibrationEffect.Composition.DELAY_TYPE_PAUSE,
+ VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET -> true;
+ default -> false;
+ };
+ }
+
+ private static String toDelayTypeDebugString(int delayType) {
+ return switch (delayType) {
+ case VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET -> "startOffset";
+ default -> "pause";
+ };
}
@NonNull
diff --git a/core/java/android/os/vibrator/PwlePoint.java b/core/java/android/os/vibrator/PwlePoint.java
index ea3ae6c4649d..4be5c681f708 100644
--- a/core/java/android/os/vibrator/PwlePoint.java
+++ b/core/java/android/os/vibrator/PwlePoint.java
@@ -63,4 +63,12 @@ public final class PwlePoint {
public int hashCode() {
return Objects.hash(mAmplitude, mFrequencyHz, mTimeMillis);
}
+
+ @Override
+ public String toString() {
+ return "PwlePoint{amplitude=" + mAmplitude
+ + ", frequency=" + mFrequencyHz
+ + ", time=" + mTimeMillis
+ + "}";
+ }
}
diff --git a/core/java/android/os/vibrator/PwleSegment.java b/core/java/android/os/vibrator/PwleSegment.java
index 9074bde19321..942b7b3e524d 100644
--- a/core/java/android/os/vibrator/PwleSegment.java
+++ b/core/java/android/os/vibrator/PwleSegment.java
@@ -44,16 +44,16 @@ public final class PwleSegment extends VibrationEffectSegment {
private final float mStartFrequencyHz;
private final float mEndAmplitude;
private final float mEndFrequencyHz;
- private final int mDuration;
+ private final long mDuration;
PwleSegment(@android.annotation.NonNull Parcel in) {
- this(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat(), in.readInt());
+ this(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat(), in.readLong());
}
/** @hide */
@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public PwleSegment(float startAmplitude, float endAmplitude, float startFrequencyHz,
- float endFrequencyHz, int duration) {
+ float endFrequencyHz, long duration) {
mStartAmplitude = startAmplitude;
mEndAmplitude = endAmplitude;
mStartFrequencyHz = startFrequencyHz;
@@ -213,7 +213,7 @@ public final class PwleSegment extends VibrationEffectSegment {
dest.writeFloat(mEndAmplitude);
dest.writeFloat(mStartFrequencyHz);
dest.writeFloat(mEndFrequencyHz);
- dest.writeInt(mDuration);
+ dest.writeLong(mDuration);
}
@android.annotation.NonNull
diff --git a/core/java/android/os/vibrator/VibrationEffectSegment.java b/core/java/android/os/vibrator/VibrationEffectSegment.java
index b934e11415d1..325a058e3aa3 100644
--- a/core/java/android/os/vibrator/VibrationEffectSegment.java
+++ b/core/java/android/os/vibrator/VibrationEffectSegment.java
@@ -47,6 +47,7 @@ public abstract class VibrationEffectSegment implements Parcelable {
static final int PARCEL_TOKEN_STEP = 3;
static final int PARCEL_TOKEN_RAMP = 4;
static final int PARCEL_TOKEN_PWLE = 5;
+ static final int PARCEL_TOKEN_BASIC_PWLE = 6;
/** Prevent subclassing from outside of this package */
VibrationEffectSegment() {
@@ -228,7 +229,12 @@ public abstract class VibrationEffectSegment implements Parcelable {
if (Flags.normalizedPwleEffects()) {
return new PwleSegment(in);
}
- // Fall through if the flag is not enabled.
+ // Fall through to default if the flag is not enabled.
+ case PARCEL_TOKEN_BASIC_PWLE:
+ if (Flags.normalizedPwleEffects()) {
+ return new BasicPwleSegment(in);
+ }
+ // Fall through to default if the flag is not enabled.
default:
throw new IllegalStateException(
"Unexpected vibration event type token in parcel.");
diff --git a/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java
new file mode 100644
index 000000000000..afaab55f4ed4
--- /dev/null
+++ b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2024 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.os.vibrator;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.VibrationEffect;
+
+import java.util.Objects;
+
+/**
+ * Provides information about the vibrator hardware capabilities and limitations regarding
+ * waveform envelope effects. This includes:
+ * <ul>
+ * <li>Maximum number of control points supported.
+ * <li>Minimum and maximum duration for individual segments.
+ * <li>Maximum total duration for an envelope effect.
+ * </ul>
+ *
+ * <p>This information can be used to help construct waveform envelope effects with
+ * {@link VibrationEffect.WaveformEnvelopeBuilder}. When designing these effects, it is also
+ * recommended to check the {@link VibratorFrequencyProfile} for information about the supported
+ * frequency range and the vibrator's output response.
+ *
+ * @see VibrationEffect.WaveformEnvelopeBuilder
+ * @see VibratorFrequencyProfile
+ */
+@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+public final class VibratorEnvelopeEffectInfo implements Parcelable {
+ private final int mMaxSize;
+ private final long mMinControlPointDurationMillis;
+ private final long mMaxControlPointDurationMillis;
+
+ VibratorEnvelopeEffectInfo(Parcel in) {
+ mMaxSize = in.readInt();
+ mMinControlPointDurationMillis = in.readLong();
+ mMaxControlPointDurationMillis = in.readLong();
+ }
+
+ /**
+ * Default constructor.
+ *
+ * @param maxSize The maximum number of control points supported for an
+ * envelope effect.
+ * @param minControlPointDurationMillis The minimum duration supported between two control
+ * points within an envelope effect.
+ * @param maxControlPointDurationMillis The maximum duration supported between two control
+ * points within an envelope effect.
+ * @hide
+ */
+ public VibratorEnvelopeEffectInfo(int maxSize,
+ long minControlPointDurationMillis,
+ long maxControlPointDurationMillis) {
+ mMaxSize = maxSize;
+ mMinControlPointDurationMillis = minControlPointDurationMillis;
+ mMaxControlPointDurationMillis = maxControlPointDurationMillis;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mMaxSize);
+ dest.writeLong(mMinControlPointDurationMillis);
+ dest.writeLong(mMaxControlPointDurationMillis);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof VibratorEnvelopeEffectInfo)) {
+ return false;
+ }
+ VibratorEnvelopeEffectInfo other = (VibratorEnvelopeEffectInfo) o;
+ return mMaxSize == other.mMaxSize
+ && mMinControlPointDurationMillis == other.mMinControlPointDurationMillis
+ && mMaxControlPointDurationMillis == other.mMaxControlPointDurationMillis;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMaxSize,
+ mMinControlPointDurationMillis,
+ mMaxControlPointDurationMillis);
+ }
+
+ @Override
+ public String toString() {
+ return "VibratorEnvelopeEffectInfo{"
+ + ", mMaxSize=" + mMaxSize
+ + ", mMinControlPointDurationMillis=" + mMinControlPointDurationMillis
+ + ", mMaxControlPointDurationMillis=" + mMaxControlPointDurationMillis
+ + '}';
+ }
+
+ @NonNull
+ public static final Creator<VibratorEnvelopeEffectInfo> CREATOR =
+ new Creator<VibratorEnvelopeEffectInfo>() {
+ @Override
+ public VibratorEnvelopeEffectInfo createFromParcel(Parcel in) {
+ return new VibratorEnvelopeEffectInfo(in);
+ }
+
+ @Override
+ public VibratorEnvelopeEffectInfo[] newArray(int size) {
+ return new VibratorEnvelopeEffectInfo[size];
+ }
+ };
+
+ /**
+ * Retrieves the maximum duration supported for an envelope effect, in milliseconds.
+ *
+ * <p>If the device supports envelope effects
+ * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+ * positive. Devices with envelope effects capabilities guarantees a maximum duration
+ * equivalent to the product of {@link #getMaxSize()} and
+ * {@link #getMaxControlPointDurationMillis()}. If the device does not support
+ * envelope effects, this method will return 0.
+ *
+ * @return The maximum duration (in milliseconds) allowed for an envelope effect, or 0 if
+ * envelope effects are not supported.
+ */
+ public long getMaxDurationMillis() {
+ return mMaxSize * mMaxControlPointDurationMillis;
+ }
+
+ /**
+ * Retrieves the maximum number of control points supported for an envelope effect.
+ *
+ * <p>If the device supports envelope effects
+ * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+ * positive. Devices with envelope effects capabilities guarantee support for a minimum of
+ * 16 control points. If the device does not support envelope effects, this method will
+ * return 0.
+ *
+ * @return the maximum number of control points allowed for an envelope effect, or 0 if
+ * envelope effects are not supported.
+ */
+ public int getMaxSize() {
+ return mMaxSize;
+ }
+
+ /**
+ * Retrieves the minimum duration supported between two control points within an envelope
+ * effect, in milliseconds.
+ *
+ * <p>If the device supports envelope effects
+ * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+ * positive. Devices with envelope effects capabilities guarantee support for durations down
+ * to at least 20 milliseconds. If the device does not support envelope effects,
+ * this method will return 0.
+ *
+ * @return the minimum allowed duration between two control points in an envelope effect,
+ * or 0 if envelope effects are not supported.
+ */
+ public long getMinControlPointDurationMillis() {
+ return mMinControlPointDurationMillis;
+ }
+
+ /**
+ * Retrieves the maximum duration supported between two control points within an envelope
+ * effect, in milliseconds.
+ *
+ * <p>If the device supports envelope effects
+ * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+ * positive. Devices with envelope effects capabilities guarantee support for durations up to
+ * at least 1 second. If the device does not support envelope effects, this method
+ * will return 0.
+ *
+ * @return the maximum allowed duration between two control points in an envelope effect,
+ * or 0 if envelope effects are not supported.
+ */
+ public long getMaxControlPointDurationMillis() {
+ return mMaxControlPointDurationMillis;
+ }
+}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 33040be7c0fb..55ba4afc9c68 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -383,7 +383,7 @@ flag {
bug: "363318732"
}
-flag{
+flag {
name: "note_op_batching_enabled"
is_fixed_read_only: true
is_exported: true
@@ -391,3 +391,48 @@ flag{
description: "Batch noteOperations on the client to reduce binder call volume"
bug: "366013082"
}
+
+flag {
+ name: "supervision_role_permission_update_enabled"
+ is_fixed_read_only: true
+ is_exported: true
+ namespace: "supervision"
+ description: "This flag is used to enable all the remaining permissions required to the supervision role"
+ bug: "367333883"
+}
+
+flag {
+ name: "permission_request_short_circuit_enabled"
+ is_fixed_read_only: true
+ is_exported: true
+ namespace: "permissions"
+ description: "This flag is used to short circuit the request for permananently denied permissions"
+ bug: "378923900"
+}
+
+flag {
+ name: "check_op_overload_api_enabled"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Add new checkOp APIs that accept attributionTag"
+ bug: "240617242"
+}
+
+flag {
+ name: "device_policy_management_role_split_create_managed_profile_enabled"
+ is_fixed_read_only: true
+ is_exported: true
+ namespace: "enterprise"
+ description: "Gives the device policy management role the ability to create a managed profile using new APIs"
+ bug: "375382324"
+}
+
+flag {
+ name: "use_profile_labels_for_default_app_section_titles"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "profile_experiences"
+ description: "Use profile labels from UserManager for default app section titles to allow partner customization"
+ bug: "358369931"
+}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 1b289fdabbd1..99ff38b43adc 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3151,7 +3151,7 @@ public final class ContactsContract {
* {@link #DEFAULT_ACCOUNT_STATE_CLOUD} or
* {@link #DEFAULT_ACCOUNT_STATE_SIM}, or null otherwise.
*/
- public DefaultAccountAndState(@DefaultAccountState int state,
+ private DefaultAccountAndState(@DefaultAccountState int state,
@Nullable Account account) {
if (!isValidDefaultAccountState(state)) {
throw new IllegalArgumentException("Invalid default account state.");
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d2a20b65c1ee..d5b525884ac1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6271,6 +6271,14 @@ public final class Settings {
public static final String TOUCHPAD_TAP_DRAGGING = "touchpad_tap_dragging";
/**
+ * Whether to enable three finger tap customization on touchpads.
+ *
+ * @hide
+ */
+ public static final String TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION =
+ "touchpad_three_finger_tap_customization";
+
+ /**
* Whether to enable a right-click zone on touchpads.
*
* When set to 1, pressing to click in a section on the right-hand side of the touchpad will
@@ -6395,27 +6403,6 @@ public final class Settings {
public static final String SCREEN_FLASH_NOTIFICATION_COLOR =
"screen_flash_notification_color_global";
-
- /**
- * A semi-colon separated list of Bluetooth hearing devices' local ambient volume.
- * Each entry is encoded as a key=value list, separated by commas. Ex:
- *
- * "addr=XX:XX:XX:00:11,ambient=20,group_ambient=30;addr=XX:XX:XX:00:22,ambient=50"
- *
- * The following keys are supported:
- * <pre>
- * addr (String)
- * ambient (int)
- * group_ambient (int)
- * control_expanded (boolean)
- * </pre>
- *
- * Each entry must contains "addr" attribute, otherwise it'll be ignored.
- * @hide
- */
- public static final String HEARING_DEVICE_LOCAL_AMBIENT_VOLUME =
- "hearing_device_local_ambient_volume";
-
/**
* IMPORTANT: If you add a new public settings you also have to add it to
* PUBLIC_SETTINGS below. If the new setting is hidden you have to add
@@ -6560,7 +6547,6 @@ public final class Settings {
PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE);
PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING);
PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON);
- PRIVATE_SETTINGS.add(HEARING_DEVICE_LOCAL_AMBIENT_VOLUME);
}
/**
@@ -11013,6 +10999,25 @@ public final class Settings {
"emergency_gesture_ui_last_started_millis";
/**
+ * Whether double tap the power button gesture is enabled.
+ *
+ * @hide
+ */
+ @Readable
+ public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED =
+ "double_tap_power_button_gesture_enabled";
+
+ /**
+ * Double tap power button gesture behavior.
+ * 0 = Camera launch
+ * 1 = Wallet launch
+ * @hide
+ */
+ @Readable
+ public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE =
+ "double_tap_power_button_gesture";
+
+ /**
* Whether the camera launch gesture to double tap the power button when the screen is off
* should be disabled.
*
@@ -18138,6 +18143,44 @@ public final class Settings {
public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side";
/**
+ * A semi-colon separated list of Bluetooth hearing devices' local ambient volume data.
+ * Each entry is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "addr=XX:XX:XX:00:11,ambient=20,group_ambient=30;addr=XX:XX:XX:00:22,ambient=50"
+ *
+ * The following keys are supported:
+ * <pre>
+ * addr (String)
+ * ambient (int)
+ * group_ambient (int)
+ * control_expanded (boolean)
+ * </pre>
+ *
+ * Each entry must contains "addr" attribute, otherwise it'll be ignored.
+ * @hide
+ */
+ public static final String HEARING_DEVICE_LOCAL_AMBIENT_VOLUME =
+ "hearing_device_local_ambient_volume";
+
+ /**
+ * A semi-colon separated list of Bluetooth hearing devices' notification data.
+ * Each entry is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "addr=XX:XX:XX:00:11,input_changes=1"
+ *
+ * The following keys are supported:
+ * <pre>
+ * addr (String)
+ * input_changes (boolean)
+ * </pre>
+ *
+ * Each entry must contains "addr" attribute, otherwise it'll be ignored.
+ * @hide
+ */
+ public static final String HEARING_DEVICE_LOCAL_NOTIFICATION =
+ "hearing_device_local_notification";
+
+ /**
* Global settings that shouldn't be persisted.
*
* @hide
@@ -20438,6 +20481,29 @@ public final class Settings {
* @hide
*/
public static final String AUTO_BEDTIME_MODE = "auto_bedtime_mode";
+
+ /**
+ * Indicates that all elements of the system status tray on wear should be rendered
+ * by default wear system.
+ *
+ * @hide
+ */
+ public static final int STATUS_TRAY_CONFIGURATION_DEFAULT = 0;
+
+ /**
+ * Indicates that all elements of the system status tray on wear should be hidden.
+ *
+ * @hide
+ */
+ public static final int STATUS_TRAY_CONFIGURATION_SYSTEM_HIDDEN = 1;
+
+ /**
+ * Configuration of system status tray in wear.
+ *
+ * @hide
+ */
+ public static final String WEAR_SYSTEM_STATUS_TRAY_CONFIGURATION =
+ "wear_system_status_tray_configuration";
}
}
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
index 6f3e3d8f0d3b..0302fafd2f6c 100644
--- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
@@ -16,20 +16,30 @@
package android.security.advancedprotection;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.content.Intent;
import android.os.Binder;
import android.os.RemoteException;
import android.security.Flags;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -45,6 +55,139 @@ import java.util.concurrent.Executor;
public final class AdvancedProtectionManager {
private static final String TAG = "AdvancedProtectionMgr";
+ /**
+ * Advanced Protection's identifier for setting policies or restrictions in DevicePolicyManager.
+ *
+ * @hide */
+ public static final String ADVANCED_PROTECTION_SYSTEM_ENTITY =
+ "android.security.advancedprotection";
+
+ /**
+ * Feature identifier for disallowing 2G.
+ *
+ * @hide */
+ @SystemApi
+ public static final String FEATURE_ID_DISALLOW_CELLULAR_2G =
+ "android.security.advancedprotection.feature_disallow_2g";
+
+ /**
+ * Feature identifier for disallowing install of unknown sources.
+ *
+ * @hide */
+ @SystemApi
+ public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES =
+ "android.security.advancedprotection.feature_disallow_install_unknown_sources";
+
+ /**
+ * Feature identifier for disallowing USB.
+ *
+ * @hide */
+ @SystemApi
+ public static final String FEATURE_ID_DISALLOW_USB =
+ "android.security.advancedprotection.feature_disallow_usb";
+
+ /**
+ * Feature identifier for disallowing WEP.
+ *
+ * @hide */
+ @SystemApi
+ public static final String FEATURE_ID_DISALLOW_WEP =
+ "android.security.advancedprotection.feature_disallow_wep";
+
+ /**
+ * Feature identifier for enabling MTE.
+ *
+ * @hide */
+ @SystemApi
+ public static final String FEATURE_ID_ENABLE_MTE =
+ "android.security.advancedprotection.feature_enable_mte";
+
+ /** @hide */
+ @StringDef(prefix = { "FEATURE_ID_" }, value = {
+ FEATURE_ID_DISALLOW_CELLULAR_2G,
+ FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ FEATURE_ID_DISALLOW_USB,
+ FEATURE_ID_DISALLOW_WEP,
+ FEATURE_ID_ENABLE_MTE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FeatureId {}
+
+ private static final Set<String> ALL_FEATURE_IDS = Set.of(
+ FEATURE_ID_DISALLOW_CELLULAR_2G,
+ FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ FEATURE_ID_DISALLOW_USB,
+ FEATURE_ID_DISALLOW_WEP,
+ FEATURE_ID_ENABLE_MTE);
+
+ /**
+ * Activity Action: Show a dialog with disabled by advanced protection message.
+ * <p> If a user action or a setting toggle is disabled by advanced protection, this dialog can
+ * be triggered to let the user know about this.
+ * <p>
+ * Input:
+ * <p>{@link #EXTRA_SUPPORT_DIALOG_FEATURE}: The feature identifier.
+ * <p>{@link #EXTRA_SUPPORT_DIALOG_TYPE}: The type of the action.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide */
+ @SystemApi
+ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+ @FlaggedApi(android.security.Flags.FLAG_AAPM_API)
+ public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG =
+ "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG";
+
+ /**
+ * A string extra used with {@link #createSupportIntent} to identify the feature that needs to
+ * show a support dialog explaining it was disabled by advanced protection.
+ *
+ * @hide */
+ @FeatureId
+ @SystemApi
+ public static final String EXTRA_SUPPORT_DIALOG_FEATURE =
+ "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE";
+
+ /**
+ * A string extra used with {@link #createSupportIntent} to identify the type of the action that
+ * needs to be explained in the support dialog.
+ *
+ * @hide */
+ @SupportDialogType
+ @SystemApi
+ public static final String EXTRA_SUPPORT_DIALOG_TYPE =
+ "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE";
+
+ /**
+ * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user performed an action that was
+ * blocked by advanced protection.
+ *
+ * @hide */
+ @SystemApi
+ public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION =
+ "android.security.advancedprotection.type_blocked_interaction";
+
+ /**
+ * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user pressed on a setting toggle
+ * that was disabled by advanced protection.
+ *
+ * @hide */
+ @SystemApi
+ public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING =
+ "android.security.advancedprotection.type_disabled_setting";
+
+ /** @hide */
+ @StringDef(prefix = { "SUPPORT_DIALOG_TYPE_" }, value = {
+ SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION,
+ SUPPORT_DIALOG_TYPE_DISABLED_SETTING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SupportDialogType {}
+
+ private static final Set<String> ALL_SUPPORT_DIALOG_TYPES = Set.of(
+ SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION,
+ SUPPORT_DIALOG_TYPE_DISABLED_SETTING);
+
private final ConcurrentHashMap<Callback, IAdvancedProtectionCallback>
mCallbackMap = new ConcurrentHashMap<>();
@@ -138,7 +281,7 @@ public final class AdvancedProtectionManager {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+ @RequiresPermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
public void setAdvancedProtectionEnabled(boolean enabled) {
try {
mService.setAdvancedProtectionEnabled(enabled);
@@ -154,7 +297,7 @@ public final class AdvancedProtectionManager {
*/
@SystemApi
@NonNull
- @RequiresPermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+ @RequiresPermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
public List<AdvancedProtectionFeature> getAdvancedProtectionFeatures() {
try {
return mService.getAdvancedProtectionFeatures();
@@ -164,6 +307,43 @@ public final class AdvancedProtectionManager {
}
/**
+ * Called by a feature to display a support dialog when a feature was disabled by advanced
+ * protection. This returns an intent that can be used with
+ * {@link Context#startActivity(Intent)} to display the dialog.
+ *
+ * <p>Note that this method doesn't check if the feature is actually disabled, i.e. this method
+ * will always return an intent.
+ *
+ * @param featureId The feature identifier.
+ * @param type The type of the feature describing the action that needs to be explained
+ * in the dialog or null for default explanation.
+ * @return Intent An intent to be used to start the dialog-activity that explains a feature was
+ * disabled by advanced protection.
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Intent createSupportIntent(@NonNull @FeatureId String featureId,
+ @Nullable @SupportDialogType String type) {
+ Objects.requireNonNull(featureId);
+ if (!ALL_FEATURE_IDS.contains(featureId)) {
+ throw new IllegalArgumentException(featureId + " is not a valid feature ID. See"
+ + " FEATURE_ID_* APIs.");
+ }
+ if (type != null && !ALL_SUPPORT_DIALOG_TYPES.contains(type)) {
+ throw new IllegalArgumentException(type + " is not a valid type. See"
+ + " SUPPORT_DIALOG_TYPE_* APIs.");
+ }
+
+ Intent intent = new Intent(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG);
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRA_SUPPORT_DIALOG_FEATURE, featureId);
+ if (type != null) {
+ intent.putExtra(EXTRA_SUPPORT_DIALOG_TYPE, type);
+ }
+ return intent;
+ }
+
+ /**
* A callback class for monitoring changes to Advanced Protection state
*
* <p>To register a callback, implement this interface, and register it with
diff --git a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
index 68307632027a..1939f829c700 100644
--- a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
+++ b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
@@ -31,8 +31,8 @@ interface IAdvancedProtectionService {
void registerAdvancedProtectionCallback(IAdvancedProtectionCallback callback);
@EnforcePermission("QUERY_ADVANCED_PROTECTION_MODE")
void unregisterAdvancedProtectionCallback(IAdvancedProtectionCallback callback);
- @EnforcePermission("SET_ADVANCED_PROTECTION_MODE")
+ @EnforcePermission("MANAGE_ADVANCED_PROTECTION_MODE")
void setAdvancedProtectionEnabled(boolean enabled);
- @EnforcePermission("SET_ADVANCED_PROTECTION_MODE")
+ @EnforcePermission("MANAGE_ADVANCED_PROTECTION_MODE")
List<AdvancedProtectionFeature> getAdvancedProtectionFeatures();
} \ No newline at end of file
diff --git a/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java
new file mode 100644
index 000000000000..75abd5fa4bb0
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2024 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.authenticationpolicy;
+
+import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE;
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * AuthenticationPolicyManager is a centralized interface for managing authentication related
+ * policies on the device. This includes device locking capabilities to protect users in "at risk"
+ * environments.
+ *
+ * AuthenticationPolicyManager is designed to protect Android users by integrating with apps and
+ * key system components, such as the lock screen. It is not related to enterprise control surfaces
+ * and does not offer additional administrative controls.
+ *
+ * <p>
+ * To use this class, call {@link #enableSecureLockDevice} to enable secure lock on the device.
+ * This will require the caller to have the
+ * {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission.
+ *
+ * <p>
+ * To disable secure lock on the device, call {@link #disableSecureLockDevice}. This will require
+ * the caller to have the {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_SECURE_LOCKDOWN)
+@SystemService(Context.AUTHENTICATION_POLICY_SERVICE)
+public final class AuthenticationPolicyManager {
+ private static final String TAG = "AuthenticationPolicyManager";
+
+ @NonNull private final IAuthenticationPolicyService mAuthenticationPolicyService;
+ @NonNull private final Context mContext;
+
+ /**
+ * Error result code for {@link #enableSecureLockDevice} and {@link
+ * #disableSecureLockDevice}.
+ *
+ * Secure lock device request status unknown.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final int ERROR_UNKNOWN = 0;
+
+ /**
+ * Success result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+ *
+ * Secure lock device request successful.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final int SUCCESS = 1;
+
+ /**
+ * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+ *
+ * Secure lock device is unsupported.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final int ERROR_UNSUPPORTED = 2;
+
+
+ /**
+ * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+ *
+ * Invalid secure lock device request params provided.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final int ERROR_INVALID_PARAMS = 3;
+
+
+ /**
+ * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+ *
+ * Secure lock device is unavailable because there are no biometrics enrolled on the device.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4;
+
+ /**
+ * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+ *
+ * Secure lock device is unavailable because the device has no biometric hardware or the
+ * biometric sensors do not meet
+ * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5;
+
+ /**
+ * Error result code for {@link #enableSecureLockDevice}.
+ *
+ * Secure lock is already enabled.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public static final int ERROR_ALREADY_ENABLED = 6;
+
+ /**
+ * Communicates the current status of a request to enable secure lock on the device.
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"ENABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = {
+ ERROR_UNKNOWN,
+ SUCCESS,
+ ERROR_UNSUPPORTED,
+ ERROR_INVALID_PARAMS,
+ ERROR_NO_BIOMETRICS_ENROLLED,
+ ERROR_INSUFFICIENT_BIOMETRICS,
+ ERROR_ALREADY_ENABLED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EnableSecureLockDeviceRequestStatus {}
+
+ /**
+ * Communicates the current status of a request to disable secure lock on the device.
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"DISABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = {
+ ERROR_UNKNOWN,
+ SUCCESS,
+ ERROR_UNSUPPORTED,
+ ERROR_INVALID_PARAMS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DisableSecureLockDeviceRequestStatus {}
+
+ /** @hide */
+ public AuthenticationPolicyManager(@NonNull Context context,
+ @NonNull IAuthenticationPolicyService authenticationPolicyService) {
+ mContext = context;
+ mAuthenticationPolicyService = authenticationPolicyService;
+ }
+
+ /**
+ * Called by a privileged component to remotely enable secure lock on the device.
+ *
+ * Secure lock is an enhanced security state that restricts access to sensitive data (app
+ * notifications, widgets, quick settings, assistant, etc) and requires multi-factor
+ * authentication for device entry, such as
+ * {@link android.hardware.biometrics.BiometricManager.Authenticators#DEVICE_CREDENTIAL} and
+ * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}.
+ *
+ * If secure lock is already enabled when this method is called, it will return
+ * {@link ERROR_ALREADY_ENABLED}.
+ *
+ * @param params EnableSecureLockDeviceParams for caller to supply params related to the secure
+ * lock device request
+ * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the secure lock
+ * device request
+ *
+ * @hide
+ */
+ @EnableSecureLockDeviceRequestStatus
+ @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE)
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public int enableSecureLockDevice(@NonNull EnableSecureLockDeviceParams params) {
+ try {
+ return mAuthenticationPolicyService.enableSecureLockDevice(params);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Called by a privileged component to disable secure lock on the device.
+ *
+ * If secure lock is already disabled when this method is called, it will return
+ * {@link SUCCESS}.
+ *
+ * @param params @DisableSecureLockDeviceParams for caller to supply params related to the
+ * secure lock device request
+ * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the secure lock
+ * device request
+ *
+ * @hide
+ */
+ @DisableSecureLockDeviceRequestStatus
+ @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE)
+ @SystemApi
+ @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+ public int disableSecureLockDevice(@NonNull DisableSecureLockDeviceParams params) {
+ try {
+ return mAuthenticationPolicyService.disableSecureLockDevice(params);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl
new file mode 100644
index 000000000000..81f7726a500c
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 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.authenticationpolicy;
+
+/**
+ * @hide
+ */
+parcelable DisableSecureLockDeviceParams; \ No newline at end of file
diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java
new file mode 100644
index 000000000000..64a3f0f60f96
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 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.authenticationpolicy;
+
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Parameters related to a request to disable secure lock on the device.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_SECURE_LOCKDOWN)
+public final class DisableSecureLockDeviceParams implements Parcelable {
+
+ /**
+ * Client message associated with the request to disable secure lock on the device. This message
+ * will be shown on the device when secure lock mode is disabled.
+ */
+ private final @NonNull String mMessage;
+
+ /**
+ * Creates DisableSecureLockDeviceParams with the given params.
+ *
+ * @param message Allows clients to pass in a message with information about the request to
+ * disable secure lock on the device. This message will be shown to the user when
+ * secure lock mode is disabled. If an empty string is provided, it will default
+ * to a system-defined string (e.g. "Secure lock mode has been disabled.")
+ */
+ public DisableSecureLockDeviceParams(@NonNull String message) {
+ mMessage = message;
+ }
+
+ private DisableSecureLockDeviceParams(@NonNull Parcel in) {
+ mMessage = Objects.requireNonNull(in.readString8());
+ }
+
+ public static final @NonNull Creator<DisableSecureLockDeviceParams> CREATOR =
+ new Creator<DisableSecureLockDeviceParams>() {
+ @Override
+ public DisableSecureLockDeviceParams createFromParcel(Parcel in) {
+ return new DisableSecureLockDeviceParams(in);
+ }
+
+ @Override
+ public DisableSecureLockDeviceParams[] newArray(int size) {
+ return new DisableSecureLockDeviceParams[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mMessage);
+ }
+}
diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl
new file mode 100644
index 000000000000..9e496f82ec69
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 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.authenticationpolicy;
+
+/**
+ * @hide
+ */
+parcelable EnableSecureLockDeviceParams; \ No newline at end of file
diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java
new file mode 100644
index 000000000000..1d727727ce37
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 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.authenticationpolicy;
+
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+
+/**
+ * Parameters related to a request to enable secure lock on the device.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_SECURE_LOCKDOWN)
+public final class EnableSecureLockDeviceParams implements Parcelable {
+
+ /**
+ * Client message associated with the request to enable secure lock on the device. This message
+ * will be shown on the device when secure lock mode is enabled.
+ */
+ private final @NonNull String mMessage;
+
+ /**
+ * Creates EnableSecureLockDeviceParams with the given params.
+ *
+ * @param message Allows clients to pass in a message with information about the request to
+ * enable secure lock on the device. This message will be shown to the user when
+ * secure lock mode is enabled. If an empty string is provided, it will default
+ * to a system-defined string (e.g. "Device is securely locked remotely.")
+ */
+ public EnableSecureLockDeviceParams(@NonNull String message) {
+ mMessage = message;
+ }
+
+ private EnableSecureLockDeviceParams(@NonNull Parcel in) {
+ mMessage = Objects.requireNonNull(in.readString8());
+ }
+
+ public static final @NonNull Creator<EnableSecureLockDeviceParams> CREATOR =
+ new Creator<EnableSecureLockDeviceParams>() {
+ @Override
+ public EnableSecureLockDeviceParams createFromParcel(Parcel in) {
+ return new EnableSecureLockDeviceParams(in);
+ }
+
+ @Override
+ public EnableSecureLockDeviceParams[] newArray(int size) {
+ return new EnableSecureLockDeviceParams[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mMessage);
+ }
+}
diff --git a/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl
new file mode 100644
index 000000000000..5ad4534c257a
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.authenticationpolicy;
+
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+
+/**
+ * Communication channel from AuthenticationPolicyManager to AuthenticationPolicyService.
+ * @hide
+ */
+interface IAuthenticationPolicyService {
+ @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
+ int enableSecureLockDevice(in EnableSecureLockDeviceParams params);
+
+ @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
+ int disableSecureLockDevice(in DisableSecureLockDeviceParams params);
+} \ No newline at end of file
diff --git a/core/java/android/security/authenticationpolicy/OWNERS b/core/java/android/security/authenticationpolicy/OWNERS
new file mode 100644
index 000000000000..4310d1a3a9db
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS \ No newline at end of file
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index ce901217d700..09004b3dcf03 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -115,6 +115,14 @@ flag {
}
flag {
+ name: "protect_device_config_flags"
+ namespace: "psap_ai"
+ description: "Feature flag to limit adb shell to allowlisted flags"
+ bug: "364083026"
+ is_fixed_read_only: true
+}
+
+flag {
name: "keystore_grant_api"
namespace: "hardware_backed_security"
description: "Feature flag for exposing KeyStore grant APIs"
diff --git a/core/java/android/security/forensic/ForensicEvent.java b/core/java/android/security/forensic/ForensicEvent.java
deleted file mode 100644
index 90906edcc636..000000000000
--- a/core/java/android/security/forensic/ForensicEvent.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2024 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.forensic;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.security.Flags;
-import android.util.ArrayMap;
-
-import java.util.Map;
-
-/**
- * A class that represents a forensic event.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_AFL_API)
-public final class ForensicEvent implements Parcelable {
- private static final String TAG = "ForensicEvent";
-
- @NonNull
- private final String mType;
-
- @NonNull
- private final Map<String, String> mKeyValuePairs;
-
- public static final @NonNull Parcelable.Creator<ForensicEvent> CREATOR =
- new Parcelable.Creator<>() {
- public ForensicEvent createFromParcel(Parcel in) {
- return new ForensicEvent(in);
- }
-
- public ForensicEvent[] newArray(int size) {
- return new ForensicEvent[size];
- }
- };
-
- public ForensicEvent(@NonNull String type, @NonNull Map<String, String> keyValuePairs) {
- mType = type;
- mKeyValuePairs = keyValuePairs;
- }
-
- private ForensicEvent(@NonNull Parcel in) {
- mType = in.readString();
- mKeyValuePairs = new ArrayMap<>(in.readInt());
- in.readMap(mKeyValuePairs, getClass().getClassLoader(), String.class, String.class);
- }
-
- public String getType() {
- return mType;
- }
-
- public Map<String, String> getKeyValuePairs() {
- return mKeyValuePairs;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeString(mType);
- out.writeInt(mKeyValuePairs.size());
- out.writeMap(mKeyValuePairs);
- }
-
- @FlaggedApi(Flags.FLAG_AFL_API)
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public String toString() {
- return "ForensicEvent{"
- + "mType=" + mType
- + ", mKeyValuePairs=" + mKeyValuePairs
- + '}';
- }
-}
diff --git a/core/java/android/security/forensic/IForensicService.aidl b/core/java/android/security/forensic/IForensicService.aidl
deleted file mode 100644
index a944b18cb26d..000000000000
--- a/core/java/android/security/forensic/IForensicService.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2024 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.forensic;
-
-import android.security.forensic.IForensicServiceCommandCallback;
-import android.security.forensic.IForensicServiceStateCallback;
-
-/**
- * Binder interface to communicate with ForensicService.
- * @hide
- */
-interface IForensicService {
- void monitorState(IForensicServiceStateCallback callback);
- void makeVisible(IForensicServiceCommandCallback callback);
- void makeInvisible(IForensicServiceCommandCallback callback);
- void enable(IForensicServiceCommandCallback callback);
- void disable(IForensicServiceCommandCallback callback);
-}
diff --git a/core/java/android/security/forensic/IBackupTransport.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
index c2cbc83ba1b3..eab1c156b6be 100644
--- a/core/java/android/security/forensic/IBackupTransport.aidl
+++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
@@ -14,28 +14,31 @@
* limitations under the License.
*/
-package android.security.forensic;
-import android.security.forensic.ForensicEvent;
+package android.security.intrusiondetection;
+
+import android.security.intrusiondetection.IntrusionDetectionEvent;
import com.android.internal.infra.AndroidFuture;
/** {@hide} */
-oneway interface IBackupTransport {
+oneway interface IIntrusionDetectionEventTransport {
/**
* Initialize the server side.
*/
- void initialize(in AndroidFuture<int> resultFuture);
+ void initialize(in AndroidFuture<boolean> resultFuture);
/**
- * Send forensic logging data to the backup destination.
- * The data is a list of ForensicEvent.
- * The ForensicEvent is an abstract class that represents
- * different type of events.
+ * Send intrusiondetection logging data to the transport destination.
+ * The data is a list of IntrusionDetectionEvent.
+ * The IntrusionDetectionEvent is an abstract class that represents
+ * different types of events.
*/
- void addData(in List<ForensicEvent> events, in AndroidFuture<int> resultFuture);
+ void addData(
+ in List<IntrusionDetectionEvent> events,
+ in AndroidFuture<boolean> resultFuture);
/**
* Release the binder to the server.
*/
- void release(in AndroidFuture<int> resultFuture);
+ void release(in AndroidFuture<boolean> resultFuture);
}
diff --git a/core/java/android/security/intrusiondetection/IIntrusionDetectionService.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionService.aidl
new file mode 100644
index 000000000000..0ba94185ddec
--- /dev/null
+++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionService.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2024 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.intrusiondetection;
+
+import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback;
+import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback;
+
+/**
+ * Binder interface to communicate with IntrusionDetectionService.
+ * @hide
+ */
+interface IIntrusionDetectionService {
+ @EnforcePermission("READ_INTRUSION_DETECTION_STATE")
+ void addStateCallback(IIntrusionDetectionServiceStateCallback callback);
+ @EnforcePermission("READ_INTRUSION_DETECTION_STATE")
+ void removeStateCallback(IIntrusionDetectionServiceStateCallback callback);
+ @EnforcePermission("MANAGE_INTRUSION_DETECTION_STATE")
+ void enable(IIntrusionDetectionServiceCommandCallback callback);
+ @EnforcePermission("MANAGE_INTRUSION_DETECTION_STATE")
+ void disable(IIntrusionDetectionServiceCommandCallback callback);
+}
diff --git a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceCommandCallback.aidl
index 7fa0c7f72690..80f09d520cc8 100644
--- a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl
+++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceCommandCallback.aidl
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-package android.security.forensic;
+package android.security.intrusiondetection;
/**
* @hide
*/
- oneway interface IForensicServiceCommandCallback {
+ oneway interface IIntrusionDetectionServiceCommandCallback {
@Backing(type="int")
enum ErrorCode{
UNKNOWN = 0,
PERMISSION_DENIED = 1,
INVALID_STATE_TRANSITION = 2,
- BACKUP_TRANSPORT_UNAVAILABLE = 3,
- DATA_SOURCE_UNAVAILABLE = 3,
+ TRANSPORT_UNAVAILABLE = 3,
+ DATA_SOURCE_UNAVAILABLE = 4,
}
void onSuccess();
void onFailure(ErrorCode error);
diff --git a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceStateCallback.aidl
index 0cda35083ffd..c88dc210320c 100644
--- a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl
+++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceStateCallback.aidl
@@ -14,18 +14,17 @@
* limitations under the License.
*/
-package android.security.forensic;
+package android.security.intrusiondetection;
/**
* @hide
*/
- oneway interface IForensicServiceStateCallback {
+ oneway interface IIntrusionDetectionServiceStateCallback {
@Backing(type="int")
enum State{
UNKNOWN = 0,
- INVISIBLE = 1,
- VISIBLE = 2,
- ENABLED = 3,
+ DISABLED = 1,
+ ENABLED = 2,
}
void onStateChange(State state);
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockAnimation.kt b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.aidl
index 5a041691b06a..80b439673b3d 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockAnimation.kt
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.aidl
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.shared.clocks
+package android.security.intrusiondetection;
-object ClockAnimation {
- const val NUM_CLOCK_FONT_ANIMATION_STEPS = 30
-}
+/** {@hide} */
+parcelable IntrusionDetectionEvent;
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
new file mode 100644
index 000000000000..b479ca7a0b6f
--- /dev/null
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2024 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.intrusiondetection;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.admin.ConnectEvent;
+import android.app.admin.DnsEvent;
+import android.app.admin.SecurityLog.SecurityEvent;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.security.Flags;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A class that represents a intrusiondetection event.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_AFL_API)
+public final class IntrusionDetectionEvent implements Parcelable {
+ private static final String TAG = "IntrusionDetectionEvent";
+
+ /**
+ * Event type representing a security-related event.
+ * This type is associated with a {@link SecurityEvent} object.
+ *
+ * @see SecurityEvent
+ */
+ public static final int SECURITY_EVENT = 0;
+
+ /**
+ * Event type representing a network DNS event.
+ * This type is associated with a {@link DnsEvent} object.
+ *
+ * @see DnsEvent
+ */
+ public static final int NETWORK_EVENT_DNS = 1;
+
+ /**
+ * Event type representing a network connection event.
+ * This type is associated with a {@link ConnectEvent} object.
+ *
+ * @see ConnectEvent
+ */
+ public static final int NETWORK_EVENT_CONNECT = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ IntrusionDetectionEvent.SECURITY_EVENT,
+ IntrusionDetectionEvent.NETWORK_EVENT_DNS,
+ IntrusionDetectionEvent.NETWORK_EVENT_CONNECT,
+ })
+ public @interface EventType {}
+
+ @NonNull @EventType private final int mType;
+
+ private final SecurityEvent mSecurityEvent;
+ private final DnsEvent mNetworkEventDns;
+ private final ConnectEvent mNetworkEventConnect;
+
+ public static final @NonNull Parcelable.Creator<IntrusionDetectionEvent> CREATOR =
+ new Parcelable.Creator<>() {
+ public IntrusionDetectionEvent createFromParcel(Parcel in) {
+ return new IntrusionDetectionEvent(in);
+ }
+
+ public IntrusionDetectionEvent[] newArray(int size) {
+ return new IntrusionDetectionEvent[size];
+ }
+ };
+
+ /**
+ * Creates an IntrusionDetectionEvent object with a
+ * {@link SecurityEvent} object as the event source.
+ *
+ * @param securityEvent The SecurityEvent object.
+ */
+ public IntrusionDetectionEvent(@NonNull SecurityEvent securityEvent) {
+ mType = SECURITY_EVENT;
+ mSecurityEvent = securityEvent;
+ mNetworkEventDns = null;
+ mNetworkEventConnect = null;
+ }
+
+ /**
+ * Creates an IntrusionDetectionEvent object with a
+ * {@link DnsEvent} object as the event source.
+ *
+ * @param dnsEvent The DnsEvent object.
+ */
+ public IntrusionDetectionEvent(@NonNull DnsEvent dnsEvent) {
+ mType = NETWORK_EVENT_DNS;
+ mNetworkEventDns = dnsEvent;
+ mSecurityEvent = null;
+ mNetworkEventConnect = null;
+ }
+
+ /**
+ * Creates an IntrusionDetectionEvent object with a
+ * {@link ConnectEvent} object as the event source.
+ *
+ * @param connectEvent The ConnectEvent object.
+ */
+ public IntrusionDetectionEvent(@NonNull ConnectEvent connectEvent) {
+ mType = NETWORK_EVENT_CONNECT;
+ mNetworkEventConnect = connectEvent;
+ mSecurityEvent = null;
+ mNetworkEventDns = null;
+ }
+
+ private IntrusionDetectionEvent(@NonNull Parcel in) {
+ mType = in.readInt();
+ switch (mType) {
+ case SECURITY_EVENT:
+ mSecurityEvent = SecurityEvent.CREATOR.createFromParcel(in);
+ mNetworkEventDns = null;
+ mNetworkEventConnect = null;
+ break;
+ case NETWORK_EVENT_DNS:
+ mNetworkEventDns = DnsEvent.CREATOR.createFromParcel(in);
+ mSecurityEvent = null;
+ mNetworkEventConnect = null;
+ break;
+ case NETWORK_EVENT_CONNECT:
+ mNetworkEventConnect = ConnectEvent.CREATOR.createFromParcel(in);
+ mSecurityEvent = null;
+ mNetworkEventDns = null;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid event type: " + mType);
+ }
+ }
+
+ /** Returns the type of the IntrusionDetectionEvent. */
+ @NonNull
+ public @EventType int getType() {
+ return mType;
+ }
+
+ /** Returns the SecurityEvent object. */
+ @NonNull
+ public SecurityEvent getSecurityEvent() {
+ if (mType == SECURITY_EVENT) {
+ return mSecurityEvent;
+ }
+ throw new IllegalArgumentException("Event type is not security event: " + mType);
+ }
+
+ /** Returns the DnsEvent object. */
+ @NonNull
+ public DnsEvent getDnsEvent() {
+ if (mType == NETWORK_EVENT_DNS) {
+ return mNetworkEventDns;
+ }
+ throw new IllegalArgumentException("Event type is not network DNS event: " + mType);
+ }
+
+ /** Returns the ConnectEvent object. */
+ @NonNull
+ public ConnectEvent getConnectEvent() {
+ if (mType == NETWORK_EVENT_CONNECT) {
+ return mNetworkEventConnect;
+ }
+ throw new IllegalArgumentException("Event type is not network connect event: " + mType);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mType);
+ switch (mType) {
+ case SECURITY_EVENT:
+ out.writeParcelable(mSecurityEvent, flags);
+ break;
+ case NETWORK_EVENT_DNS:
+ out.writeParcelable(mNetworkEventDns, flags);
+ break;
+ case NETWORK_EVENT_CONNECT:
+ out.writeParcelable(mNetworkEventConnect, flags);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid event type: " + mType);
+ }
+ }
+
+ @FlaggedApi(Flags.FLAG_AFL_API)
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "IntrusionDetectionEvent{"
+ + "mType=" + mType
+ + '}';
+ }
+}
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java
new file mode 100644
index 000000000000..2e2d0f7f2dd2
--- /dev/null
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 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.intrusiondetection;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SuppressLint;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.util.CloseGuard;
+
+import android.security.Flags;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.security.intrusiondetection.IIntrusionDetectionEventTransport;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.lang.AutoCloseable;
+import java.util.List;
+
+/**
+ * A class that provides a stable API for transporting intrusion detection events
+ * to a transport location, such as a file or a network endpoint.
+ *
+ * This class acts as a bridge between the {@link IIntrusionDetectionEventTransport}
+ * interface and its implementations. It allows system components to add intrusion
+ * detection events ({@link IntrusionDetectionEvent}) to a transport queue,
+ * which will then be delivered to the specified location.
+ *
+ * Usage:
+ * 1. Obtain an instance of {@link IntrusionDetectionEventTransport} using the constructor.
+ * 2. Initialize the transport by calling {@link #initialize()}.
+ * 3. Add events to the transport queue using {@link #addData(List)}.
+ * 4. Release the transport when finished by calling {@link #release()}.
+ *
+ * Key Components:
+ * - {@link IIntrusionDetectionEventTransport}: The underlying AIDL interface
+ * for interacting with transport implementations.
+ * - {@link IntrusionDetectionEvent}: Represents a single event.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_AFL_API)
+@SuppressLint("NotCloseable")
+public class IntrusionDetectionEventTransport {
+ IIntrusionDetectionEventTransport mBinderImpl = new TransportImpl();
+
+ /**
+ * Returns the binder interface for this transport.
+ */
+ @NonNull
+ public IBinder getBinder() {
+ return mBinderImpl.asBinder();
+ }
+
+ /**
+ * Initializes the transport.
+ *
+ * @return whether the initialization was successful.
+ */
+ public boolean initialize() {
+ return false;
+ }
+
+ /**
+ * Adds data to the transport.
+ *
+ * @param events the events to add.
+ * @return whether the addition was successful.
+ */
+ public boolean addData(@NonNull List<IntrusionDetectionEvent> events) {
+ return false;
+ }
+
+ /**
+ * Releases the transport.
+ *
+ * The release() method is a callback implemented by the concrete transport
+ * endpoint.
+ * The "SuppressLint" annotation is used to allow the release() method to be
+ * included in the API without requiring the class to implement AutoCloseable.
+ *
+ * @return whether the release was successful.
+ */
+ public boolean release() {
+ return false;
+ }
+
+ /**
+ * Bridge between the actual IIntrusionDetectionEventTransport implementation
+ * and the stable API. If the binder interface needs to change, we use this
+ * layer to translate so that we can decouple those framework-side changes
+ * from the IntrusionDetectionEventTransport implementations.
+ */
+ class TransportImpl extends IIntrusionDetectionEventTransport.Stub {
+ @Override
+ public void initialize(AndroidFuture<Boolean> resultFuture) {
+ try {
+ boolean result = IntrusionDetectionEventTransport.this.initialize();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
+ }
+
+ @Override
+ public void addData(
+ List<IntrusionDetectionEvent> events,
+ AndroidFuture<Boolean> resultFuture) {
+ try {
+ boolean result = IntrusionDetectionEventTransport.this.addData(events);
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
+ }
+
+ @Override
+ public void release(AndroidFuture<Boolean> resultFuture) {
+ try {
+ boolean result = IntrusionDetectionEventTransport.this.release();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java b/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java
new file mode 100644
index 000000000000..e2463384d0c8
--- /dev/null
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2024 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.intrusiondetection;
+
+import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE;
+import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.security.Flags;
+import android.util.Log;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * IntrusionDetectionManager manages the intrusion detection on Android devices.
+ * Upon user consent, intrusion detection collects various device events for
+ * off-device investigation of potential device compromise.
+ * <p>
+ * Intrusion detection logging can either be enabled ({@link #STATE_ENABLED}
+ * or disabled ({@link #STATE_DISABLED}).
+ * <p>
+ * The intrusion detection logs will be transferred to
+ * {@link android.security.intrusiondetection.IntrusionDetectionEventTransport}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_AFL_API)
+@SystemService(Context.INTRUSION_DETECTION_SERVICE)
+public class IntrusionDetectionManager {
+ private static final String TAG = "IntrusionDetectionManager";
+
+ /** @hide */
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_UNKNOWN,
+ STATE_DISABLED,
+ STATE_ENABLED
+ })
+ public @interface IntrusionDetectionState {}
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "ERROR_" }, value = {
+ ERROR_UNKNOWN,
+ ERROR_PERMISSION_DENIED,
+ ERROR_TRANSPORT_UNAVAILABLE,
+ ERROR_DATA_SOURCE_UNAVAILABLE
+ })
+ public @interface IntrusionDetectionError {}
+
+ /**
+ * Indicates an unknown state
+ */
+ public static final int STATE_UNKNOWN = IIntrusionDetectionServiceStateCallback.State.UNKNOWN;
+
+ /**
+ * Indicates an state that the intrusion detection is turned off.
+ */
+ public static final int STATE_DISABLED = IIntrusionDetectionServiceStateCallback.State.DISABLED;
+
+ /**
+ * Indicates an state that the intrusion detection is turned on.
+ */
+ public static final int STATE_ENABLED = IIntrusionDetectionServiceStateCallback.State.ENABLED;
+
+ /**
+ * Indicates an unknown error
+ */
+ public static final int ERROR_UNKNOWN =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.UNKNOWN;
+
+ /**
+ * Indicates an error due to insufficient access rights.
+ */
+ public static final int ERROR_PERMISSION_DENIED =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
+
+ /**
+ * Indicates an error due to unavailability of the intrusion detection event transport.
+ */
+ public static final int ERROR_TRANSPORT_UNAVAILABLE =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE;
+
+ /**
+ * Indicates an error due to unavailability of the data source.
+ */
+ public static final int ERROR_DATA_SOURCE_UNAVAILABLE =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
+
+
+ private final IIntrusionDetectionService mService;
+
+ private final ConcurrentHashMap<Consumer<Integer>, IIntrusionDetectionServiceStateCallback>
+ mStateCallbacks = new ConcurrentHashMap<>();
+
+ /**
+ * Constructor
+ *
+ * @param service A valid instance of IIntrusionDetectionService.
+ * @hide
+ */
+ public IntrusionDetectionManager(IIntrusionDetectionService service) {
+ mService = service;
+ }
+
+ /**
+ * Add a callback to monitor the state of the IntrusionDetectionService.
+ *
+ * @param executor The executor through which the callback should be invoked.
+ * @param callback The callback for state change.
+ * Once the callback is registered, the callback will be called
+ * to reflect the init state.
+ * The callback can be registered only once.
+ */
+ @RequiresPermission(READ_INTRUSION_DETECTION_STATE)
+ public void addStateCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull @IntrusionDetectionState Consumer<Integer> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ if (mStateCallbacks.get(callback) != null) {
+ Log.d(TAG, "addStateCallback callback already present");
+ return;
+ }
+
+ final IIntrusionDetectionServiceStateCallback wrappedCallback =
+ new IIntrusionDetectionServiceStateCallback.Stub() {
+ @Override
+ public void onStateChange(int state) {
+ executor.execute(() -> callback.accept(state));
+ }
+ };
+ try {
+ mService.addStateCallback(wrappedCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ mStateCallbacks.put(callback, wrappedCallback);
+ }
+
+ /**
+ * Remove a callback to monitor the state of the IntrusionDetectionService.
+ *
+ * @param callback The callback to remove.
+ */
+ @RequiresPermission(READ_INTRUSION_DETECTION_STATE)
+ public void removeStateCallback(@NonNull Consumer<@IntrusionDetectionState Integer> callback) {
+ Objects.requireNonNull(callback);
+ if (!mStateCallbacks.containsKey(callback)) {
+ Log.d(TAG, "removeStateCallback callback not present");
+ return;
+ }
+
+ IIntrusionDetectionServiceStateCallback wrappedCallback = mStateCallbacks.get(callback);
+
+ try {
+ mService.removeStateCallback(wrappedCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ mStateCallbacks.remove(callback);
+ }
+
+ /**
+ * Enable intrusion detection.
+ * If successful, IntrusionDetectionService will transition to {@link #STATE_ENABLED} state.
+ * <p>
+ * When intrusion detection is enabled, various device events will be collected and
+ * sent over to the registered
+ * {@link android.security.intrusiondetection.IntrusionDetectionEventTransport}.
+ *
+ * @param executor The executor through which the callback should be invoked.
+ * @param callback The callback for the command result.
+ */
+ @RequiresPermission(MANAGE_INTRUSION_DETECTION_STATE)
+ public void enable(@NonNull @CallbackExecutor Executor executor,
+ @NonNull CommandCallback callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ try {
+ mService.enable(new IIntrusionDetectionServiceCommandCallback.Stub() {
+ @Override
+ public void onSuccess() {
+ executor.execute(callback::onSuccess);
+ }
+
+ @Override
+ public void onFailure(int error) {
+ executor.execute(() -> callback.onFailure(error));
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Disable intrusion detection.
+ * If successful, IntrusionDetectionService will transition to {@link #STATE_DISABLED}.
+ * <p>
+ * When intrusion detection is disabled, device events will no longer be collected.
+ * Any events that have been collected but not yet sent to IntrusionDetectionEventTransport
+ * will be transferred as a final batch.
+ *
+ * @param executor The executor through which the callback should be invoked.
+ * @param callback The callback for the command result.
+ */
+ @RequiresPermission(MANAGE_INTRUSION_DETECTION_STATE)
+ public void disable(@NonNull @CallbackExecutor Executor executor,
+ @NonNull CommandCallback callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ try {
+ mService.disable(new IIntrusionDetectionServiceCommandCallback.Stub() {
+ @Override
+ public void onSuccess() {
+ executor.execute(callback::onSuccess);
+ }
+
+ @Override
+ public void onFailure(int error) {
+ executor.execute(() -> callback.onFailure(error));
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Callback used in {@link #enable} and {@link #disable} to indicate the result of the command.
+ */
+ public interface CommandCallback {
+ /**
+ * Called when command succeeds.
+ */
+ void onSuccess();
+
+ /**
+ * Called when command fails.
+ * @param error The error number.
+ */
+ void onFailure(@IntrusionDetectionError int error);
+ }
+}
diff --git a/core/java/android/security/forensic/OWNERS b/core/java/android/security/intrusiondetection/OWNERS
index d9e82a6e42f2..d9e82a6e42f2 100644
--- a/core/java/android/security/forensic/OWNERS
+++ b/core/java/android/security/intrusiondetection/OWNERS
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index 66e1f38621ae..357aba3fb136 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -96,6 +96,21 @@ flag {
}
flag {
+ name: "prevent_intent_redirect_throw_exception_if_nested_keys_not_collected"
+ namespace: "responsible_apis"
+ description: "Prevent intent redirect attacks by throwing exception if the intent does not collect nested keys"
+ bug: "361143368"
+}
+
+flag {
+ name: "prevent_intent_redirect_collect_nested_keys_on_server_if_not_collected"
+ namespace: "responsible_apis"
+ description: "Prevent intent redirect attacks by collecting nested keys on server if not yet collected"
+ bug: "361143368"
+ is_fixed_read_only: true
+}
+
+flag {
name: "enable_intent_matching_flags"
is_exported: true
namespace: "permissions"
@@ -103,3 +118,10 @@ flag {
description: "Applies intentMatchingFlags while matching intents to application components"
bug: "364354494"
}
+
+flag {
+ name: "aapm_feature_disable_install_unknown_sources"
+ namespace: "responsible_apis"
+ description: "Android Advanced Protection Mode Feature: Disable Install Unknown Sources"
+ bug: "369361373"
+}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 98dda1031eff..14a14e69f208 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -16,8 +16,10 @@
package android.service.autofill;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS;
import static android.view.autofill.Helper.sVerbose;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -63,14 +65,21 @@ public final class FillEventHistory implements Parcelable {
private static final String TAG = "FillEventHistory";
/**
- * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
+ * The ID of the autofill session that created the {@link FillResponse}.
+ *
+ * TODO: add this to the parcel.
*/
private final int mSessionId;
@Nullable private final Bundle mClientState;
@Nullable List<Event> mEvents;
- /** @hide */
+ /**
+ * Returns the unique identifier of this FillEventHistory.
+ *
+ * <p>This is used to differentiate individual FillEventHistory.
+ */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
public int getSessionId() {
return mSessionId;
}
@@ -283,6 +292,13 @@ public final class FillEventHistory implements Parcelable {
/** All fields matched contents of datasets. */
public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6;
+ /**
+ * Credential Manager is invoked instead of Autofill. When that happens, Save Dialog cannot
+ * be shown, and this will be populated in
+ */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+ public static final int NO_SAVE_UI_REASON_USING_CREDMAN = 7;
+
/** @hide */
@IntDef(prefix = { "NO_SAVE_UI_REASON_" }, value = {
NO_SAVE_UI_REASON_NONE,
@@ -310,11 +326,20 @@ public final class FillEventHistory implements Parcelable {
public static final int UI_TYPE_DIALOG = 3;
/**
- * The autofill suggestion is shown os a credman bottom sheet
- * @hide
+ * The autofill suggestion is shown os a credman bottom sheet
+ *
+ * <p>Note, this was introduced as bottom sheet even though it applies to all credman UI
+ * types. Instead of exposing this directly to the public, the generic UI_TYPE_CREDMAN is
+ * introduced with the same number.
+ *
+ * @hide
*/
public static final int UI_TYPE_CREDMAN_BOTTOM_SHEET = 4;
+ /** Credential Manager suggestions are shown instead of Autofill suggestion */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+ public static final int UI_TYPE_CREDMAN = 4;
+
/** @hide */
@IntDef(prefix = { "UI_TYPE_" }, value = {
UI_TYPE_UNKNOWN,
@@ -359,6 +384,13 @@ public final class FillEventHistory implements Parcelable {
return mEventType;
}
+ /** Gets the {@code AutofillId} that's focused at the time of action */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+ @Nullable
+ public AutofillId getFocusedId() {
+ return null;
+ }
+
/**
* Returns the id of dataset the id was on.
*
@@ -391,6 +423,17 @@ public final class FillEventHistory implements Parcelable {
}
/**
+ * Returns which datasets were shown to the user.
+ *
+ * <p><b>Note: </b>Only set on events of type {@link #TYPE_DATASETS_SHOWN}.
+ */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+ @NonNull
+ public Set<String> getShownDatasetIds() {
+ return Collections.emptySet();
+ }
+
+ /**
* Returns which datasets were NOT selected by the user.
*
* <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index ca20801852f1..be4629ab8178 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -16,6 +16,9 @@
package android.service.autofill;
+import static android.service.autofill.Flags.FLAG_FILL_DIALOG_IMPROVEMENTS;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -100,7 +103,12 @@ public final class FillRequest implements Parcelable {
/**
* Indicates the request supports fill dialog presentation for the fields, the
* system will send the request when the activity just started.
+ *
+ * @deprecated All requests would support fill dialog by default.
+ * Presence of this flag isn't needed.
*/
+ @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS)
+ @Deprecated
public static final @RequestFlags int FLAG_SUPPORTS_FILL_DIALOG = 0x40;
/**
@@ -588,10 +596,10 @@ public final class FillRequest implements Parcelable {
};
@DataClass.Generated(
- time = 1701010178309L,
+ time = 1730991738865L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SCREEN_HAS_CREDMAN_FIELD\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_REQUESTS_CREDMAN_SERVICE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.annotation.FlaggedApi @java.lang.Deprecated @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SCREEN_HAS_CREDMAN_FIELD\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_REQUESTS_CREDMAN_SERVICE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index 61213e6293ba..a825a7e110f5 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -16,6 +16,7 @@
package android.service.carrier;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,6 +27,8 @@ import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
+import com.android.internal.telephony.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
@@ -97,16 +100,317 @@ public abstract class CarrierMessagingService extends Service {
public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
/**
- * SMS/MMS sending failed. We should not retry via the carrier network.
+ * SMS/MMS sending failed due to an unspecified issue. Sending will not be retried via the
+ * carrier network.
+ *
+ * <p>Maps to SmsManager.RESULT_RIL_GENERIC_FAILURE for SMS and SmsManager.MMS_ERROR_UNSPECIFIED
+ * for MMS.
*/
public static final int SEND_STATUS_ERROR = 2;
+ /**
+ * More precise error reasons for outbound SMS send requests. These will not be retried on the
+ * carrier network.
+ *
+ * <p>Each code maps directly to an SmsManager code (e.g. SEND_STATS_RESULT_ERROR_NULL_PDU maps
+ * to SmsManager.RESULT_ERROR_NULL_PDU).
+ */
+
+ /**
+ * Generic failure cause.
+ *
+ * @see android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE = 200;
+
+ /**
+ * Failed because no pdu provided.
+ *
+ * @see android.telephony.SmsManager.RESULT_ERROR_NULL_PDU
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ERROR_NULL_PDU = 201;
+
+ /**
+ * Failed because service is currently unavailable.
+ *
+ * @see android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ERROR_NO_SERVICE = 202;
+
+ /**
+ * Failed because we reached the sending queue limit.
+ *
+ * @see android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED = 203;
+
+ /**
+ * Failed because FDN is enabled.
+ *
+ * @see android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE = 204;
+
+ /**
+ * Failed because user denied the sending of this short code.
+ *
+ * @see android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 205;
+
+ /**
+ * Failed because the user has denied this app ever send premium short codes.
+ *
+ * @see android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 206;
+
+ /**
+ * Failed because of network rejection.
+ *
+ * @see android.telephony.SmsManager.RESULT_NETWORK_REJECT
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_NETWORK_REJECT = 207;
+
+ /**
+ * Failed because of invalid arguments.
+ *
+ * @see android.telephony.SmsManager.RESULT_INVALID_ARGUMENTS
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_INVALID_ARGUMENTS = 208;
+
+ /**
+ * Failed because of an invalid state.
+ *
+ * @see android.telephony.SmsManager.RESULT_INVALID_STATE
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_INVALID_STATE = 209;
+
+ /**
+ * Failed because the sms format is not valid.
+ *
+ * @see android.telephony.SmsManager.RESULT_INVALID_SMS_FORMAT
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_INVALID_SMS_FORMAT = 210;
+
+ /**
+ * Failed because of a network error.
+ *
+ * @see android.telephony.SmsManager.RESULT_NETWORK_ERROR
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_NETWORK_ERROR = 211;
+
+ /**
+ * Failed because of an encoding error.
+ *
+ * @see android.telephony.SmsManager.RESULT_ENCODING_ERROR
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_ENCODING_ERROR = 212;
+
+ /**
+ * Failed because of an invalid smsc address
+ *
+ * @see android.telephony.SmsManager.RESULT_INVALID_SMSC_ADDRESS
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS = 213;
+
+ /**
+ * Failed because the operation is not allowed.
+ *
+ * @see android.telephony.SmsManager.RESULT_OPERATION_NOT_ALLOWED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED = 214;
+
+ /**
+ * Failed because the operation was cancelled.
+ *
+ * @see android.telephony.SmsManager.RESULT_CANCELLED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_CANCELLED = 215;
+
+ /**
+ * Failed because the request is not supported.
+ *
+ * @see android.telephony.SmsManager.RESULT_REQUEST_NOT_SUPPORTED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED = 216;
+
+ /**
+ * Failed sending during an emergency call.
+ *
+ * @see android.telephony.SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY = 217;
+
+ /**
+ * Failed to send an sms retry.
+ *
+ * @see android.telephony.SmsManager.RESULT_SMS_SEND_RETRY_FAILED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED = 218;
+
+ /**
+ * More precise error reasons for outbound MMS send requests. These will not be retried on the
+ * carrier network.
+ *
+ * <p>Each code maps directly to an SmsManager code (e.g.
+ * SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS maps to SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS).
+ */
+
+ /**
+ * Unspecific MMS error occurred during send.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_UNSPECIFIED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_UNSPECIFIED = 400;
+
+ /**
+ * ApnException occurred during MMS network setup.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_INVALID_APN
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_INVALID_APN = 401;
+
+ /**
+ * An error occurred during the MMS connection setup.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 402;
+
+ /**
+ * An error occurred during the HTTP client setup.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_HTTP_FAILURE
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_HTTP_FAILURE = 403;
+
+ /**
+ * An I/O error occurred reading the PDU.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_IO_ERROR
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_IO_ERROR = 404;
+
+ /**
+ * An error occurred while retrying sending the MMS.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_RETRY
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_RETRY = 405;
+
+ /**
+ * The carrier-dependent configuration values could not be loaded.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_CONFIGURATION_ERROR
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 406;
+
+ /**
+ * There is neither Wi-Fi nor mobile data network.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_NO_DATA_NETWORK
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK = 407;
+
+ /**
+ * The subscription id for the send is invalid.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 408;
+
+ /**
+ * The subscription id for the send is inactive.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 409;
+
+ /**
+ * Data is disabled for the MMS APN.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_DATA_DISABLED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_DATA_DISABLED = 410;
+
+ /**
+ * MMS is disabled by a carrier.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 411;
+
/** @hide */
- @IntDef(prefix = { "SEND_STATUS_" }, value = {
- SEND_STATUS_OK,
- SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
- SEND_STATUS_ERROR
- })
+ @IntDef(
+ prefix = {"SEND_STATUS_"},
+ value = {
+ SEND_STATUS_OK,
+ SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+ SEND_STATUS_ERROR,
+ SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE,
+ SEND_STATUS_RESULT_ERROR_NULL_PDU,
+ SEND_STATUS_RESULT_ERROR_NO_SERVICE,
+ SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED,
+ SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE,
+ SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED,
+ SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED,
+ SEND_STATUS_RESULT_NETWORK_REJECT,
+ SEND_STATUS_RESULT_INVALID_ARGUMENTS,
+ SEND_STATUS_RESULT_INVALID_STATE,
+ SEND_STATUS_RESULT_INVALID_SMS_FORMAT,
+ SEND_STATUS_RESULT_NETWORK_ERROR,
+ SEND_STATUS_RESULT_ENCODING_ERROR,
+ SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS,
+ SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED,
+ SEND_STATUS_RESULT_CANCELLED,
+ SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED,
+ SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY,
+ SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED,
+ SEND_STATUS_MMS_ERROR_UNSPECIFIED,
+ SEND_STATUS_MMS_ERROR_INVALID_APN,
+ SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS,
+ SEND_STATUS_MMS_ERROR_HTTP_FAILURE,
+ SEND_STATUS_MMS_ERROR_IO_ERROR,
+ SEND_STATUS_MMS_ERROR_RETRY,
+ SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR,
+ SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK,
+ SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID,
+ SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION,
+ SEND_STATUS_MMS_ERROR_DATA_DISABLED,
+ SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface SendResult {}
@@ -121,16 +425,138 @@ public abstract class CarrierMessagingService extends Service {
public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
/**
- * MMS downloading failed. We should not retry via the carrier network.
+ * MMS downloading failed due to an unspecified issue. Downloading will not be retried via the
+ * carrier network.
+ *
+ * <p>Maps to SmsManager.MMR_ERROR_UNSPECIFIED.
*/
public static final int DOWNLOAD_STATUS_ERROR = 2;
+ /**
+ * More precise error reasons for inbound MMS download requests. These will not be retried on
+ * the carrier network.
+ *
+ * <p>Each code maps directly to an SmsManager code (e.g.
+ * DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS maps to
+ * SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS).
+ */
+
+ /**
+ * Unspecific MMS error occurred during download.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_UNSPECIFIED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED = 600;
+
+ /**
+ * ApnException occurred during MMS network setup.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_INVALID_APN
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN = 601;
+
+ /**
+ * An error occurred during the MMS connection setup.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 602;
+
+ /**
+ * An error occurred during the HTTP client setup.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_HTTP_FAILURE
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE = 603;
+
+ /**
+ * An I/O error occurred reading the PDU.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_IO_ERROR
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR = 604;
+
+ /**
+ * An error occurred while retrying downloading the MMS.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_RETRY
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_RETRY = 605;
+
+ /**
+ * The carrier-dependent configuration values could not be loaded.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_CONFIGURATION_ERROR
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 606;
+
+ /**
+ * There is neither Wi-Fi nor mobile data network.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_NO_DATA_NETWORK
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK = 607;
+
+ /**
+ * The subscription id for the download is invalid.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 608;
+
+ /**
+ * The subscription id for the download is inactive.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 609;
+
+ /**
+ * Data is disabled for the MMS APN.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_DATA_DISABLED
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED = 610;
+
+ /**
+ * MMS is disabled by a carrier.
+ *
+ * @see android.telephony.SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER
+ */
+ @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+ public static final int DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 611;
+
/** @hide */
- @IntDef(prefix = { "DOWNLOAD_STATUS_" }, value = {
- DOWNLOAD_STATUS_OK,
- DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK,
- DOWNLOAD_STATUS_ERROR
- })
+ @IntDef(
+ prefix = {"DOWNLOAD_STATUS_"},
+ value = {
+ DOWNLOAD_STATUS_OK,
+ DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK,
+ DOWNLOAD_STATUS_ERROR,
+ DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED,
+ DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN,
+ DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS,
+ DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE,
+ DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR,
+ DOWNLOAD_STATUS_MMS_ERROR_RETRY,
+ DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR,
+ DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK,
+ DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID,
+ DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION,
+ DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED,
+ DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DownloadResult {}
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index b384b66bf680..54710488cd67 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -34,10 +34,14 @@ oneway interface INotificationListener
void onListenerConnected(in NotificationRankingUpdate update);
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
+ void onNotificationPostedFull(in StatusBarNotification sbn,
+ in NotificationRankingUpdate update);
void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons);
// stats only for assistant
void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update, in NotificationStats stats, int reason);
+ void onNotificationRemovedFull(in StatusBarNotification sbn,
+ in NotificationRankingUpdate update, in NotificationStats stats, int reason);
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
@@ -48,7 +52,9 @@ oneway interface INotificationListener
// assistants only
void onNotificationEnqueuedWithChannel(in IStatusBarNotificationHolder notificationHolder, in NotificationChannel channel, in NotificationRankingUpdate update);
+ void onNotificationEnqueuedWithChannelFull(in StatusBarNotification sbn, in NotificationChannel channel, in NotificationRankingUpdate update);
void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);
+ void onNotificationSnoozedUntilContextFull(in StatusBarNotification sbn, String snoozeCriterionId);
void onNotificationsSeen(in List<String> keys);
void onPanelRevealed(int items);
void onPanelHidden();
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 091b25ab77ce..0a9276c34bfd 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -423,7 +423,12 @@ public abstract class NotificationAssistantService extends NotificationListenerS
+ "Error receiving StatusBarNotification");
return;
}
+ onNotificationEnqueuedWithChannelFull(sbn, channel, update);
+ }
+ @Override
+ public void onNotificationEnqueuedWithChannelFull(StatusBarNotification sbn,
+ NotificationChannel channel, NotificationRankingUpdate update) {
applyUpdateLocked(update);
SomeArgs args = SomeArgs.obtain();
args.arg1 = sbn;
@@ -447,7 +452,12 @@ public abstract class NotificationAssistantService extends NotificationListenerS
Log.w(TAG, "onNotificationSnoozed: Error receiving StatusBarNotification");
return;
}
+ onNotificationSnoozedUntilContextFull(sbn, snoozeCriterionId);
+ }
+ @Override
+ public void onNotificationSnoozedUntilContextFull(
+ StatusBarNotification sbn, String snoozeCriterionId) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = sbn;
args.arg2 = snoozeCriterionId;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a8ab2115d97f..5d0ec73a024b 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1490,7 +1490,12 @@ public abstract class NotificationListenerService extends Service {
Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification");
return;
}
+ onNotificationPostedFull(sbn, update);
+ }
+ @Override
+ public void onNotificationPostedFull(StatusBarNotification sbn,
+ NotificationRankingUpdate update) {
try {
// convert icon metadata to legacy format for older clients
createLegacyIconExtras(sbn.getNotification());
@@ -1518,7 +1523,6 @@ public abstract class NotificationListenerService extends Service {
mRankingMap).sendToTarget();
}
}
-
}
@Override
@@ -1531,6 +1535,12 @@ public abstract class NotificationListenerService extends Service {
Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
return;
}
+ onNotificationRemovedFull(sbn, update, stats, reason);
+ }
+
+ @Override
+ public void onNotificationRemovedFull(StatusBarNotification sbn,
+ NotificationRankingUpdate update, NotificationStats stats, int reason) {
if (sbn == null) {
Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification");
return;
@@ -1592,6 +1602,14 @@ public abstract class NotificationListenerService extends Service {
}
@Override
+ public void onNotificationEnqueuedWithChannelFull(
+ StatusBarNotification sbn, NotificationChannel channel,
+ NotificationRankingUpdate update)
+ throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
public void onNotificationsSeen(List<String> keys)
throws RemoteException {
// no-op in the listener
@@ -1621,6 +1639,13 @@ public abstract class NotificationListenerService extends Service {
}
@Override
+ public void onNotificationSnoozedUntilContextFull(
+ StatusBarNotification sbn, String snoozeCriterionId)
+ throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
public void onNotificationExpansionChanged(
String key, boolean isUserAction, boolean isExpanded) {
// no-op in the listener
@@ -1688,8 +1713,6 @@ public abstract class NotificationListenerService extends Service {
Bundle feedback) {
// no-op in the listener
}
-
-
}
/**
diff --git a/core/java/android/service/notification/SystemZenRules.java b/core/java/android/service/notification/SystemZenRules.java
index ebb8569ead49..f11ce1621f93 100644
--- a/core/java/android/service/notification/SystemZenRules.java
+++ b/core/java/android/service/notification/SystemZenRules.java
@@ -122,17 +122,16 @@ public final class SystemZenRules {
@Nullable
public static String getTriggerDescriptionForScheduleTime(Context context,
@NonNull ScheduleInfo schedule) {
- final StringBuilder sb = new StringBuilder();
String daysSummary = getDaysOfWeekShort(context, schedule);
if (daysSummary == null) {
// no use outputting times without dates
return null;
}
- sb.append(daysSummary);
- sb.append(context.getString(R.string.zen_mode_trigger_summary_divider_text));
- sb.append(getTimeSummary(context, schedule));
-
- return sb.toString();
+ return context.getString(
+ R.string.zen_mode_trigger_summary_combined,
+ daysSummary,
+ getTimeSummary(context, schedule)
+ );
}
/**
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 24328eb1e825..13887781f1ec 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -2532,7 +2532,7 @@ public class ZenModeConfig implements Parcelable {
/** Returns whether the rule id corresponds to an implicit rule. */
public static boolean isImplicitRuleId(@NonNull String ruleId) {
- return ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX);
+ return ruleId != null && ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX);
}
private static int[] tryParseHourAndMinute(String value) {
diff --git a/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl b/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl
index 0dca78d890a5..03e27b866b7a 100644
--- a/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl
+++ b/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl
@@ -43,4 +43,6 @@ interface IQuickAccessWalletService {
oneway void unregisterWalletServiceEventListener(in WalletServiceEventListenerRequest request);
// Request to get a PendingIntent to launch an activity from which the user can manage their cards.
oneway void onTargetActivityIntentRequested(in IQuickAccessWalletServiceCallbacks callbacks);
+ // Request to get a PendingIntent to launch an activity, triggered when the user performs a gesture.
+ oneway void onGestureTargetActivityIntentRequested(in IQuickAccessWalletServiceCallbacks callbacks);
} \ No newline at end of file
diff --git a/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl b/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl
index 1b69ca12da3a..61d7fd1f526c 100644
--- a/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl
+++ b/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl
@@ -37,4 +37,6 @@ interface IQuickAccessWalletServiceCallbacks {
oneway void onWalletServiceEvent(in WalletServiceEvent event);
// Called in response to onTargetActivityIntentRequested. May only be called once per request.
oneway void onTargetActivityPendingIntentReceived(in PendingIntent pendingIntent);
+ //Called in response to onGesturePendingIntent
+ oneway void onGestureTargetActivityPendingIntentReceived(in PendingIntent pendingIntent);
} \ No newline at end of file
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
index faa5b2fe3488..b5251db4e539 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
@@ -17,6 +17,7 @@
package android.service.quickaccesswallet;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -181,6 +182,23 @@ public interface QuickAccessWalletClient extends Closeable {
}
/**
+ * Gets the {@link PendingIntent} provided by QuickAccessWalletService to be sent when the user
+ * launches Wallet via gesture.
+ */
+ @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ void getGestureTargetActivityPendingIntent(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull GesturePendingIntentCallback gesturePendingIntentCallback);
+
+ /** Callback interface for getGesturePendingIntent. */
+ @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ interface GesturePendingIntentCallback {
+ /** Callback method for getGesturePendingIntent */
+ @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ void onGesturePendingIntentRetrieved(@Nullable PendingIntent pendingIntent);
+ }
+
+ /**
* The manifest entry for the QuickAccessWalletService may also publish information about the
* activity that hosts the Wallet view. This is typically the home screen of the Wallet
* application.
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
index a59f026c4182..97a4beff633f 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
@@ -267,6 +267,34 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser
}
@Override
+ public void getGestureTargetActivityPendingIntent(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull GesturePendingIntentCallback gesturePendingIntentCallback) {
+ BaseCallbacks callbacks =
+ new BaseCallbacks() {
+ @Override
+ public void onGestureTargetActivityPendingIntentReceived(
+ PendingIntent pendingIntent) {
+ if (!Flags.launchWalletOptionOnPowerDoubleTap()) {
+ return;
+ }
+ executor.execute(
+ () ->
+ gesturePendingIntentCallback
+ .onGesturePendingIntentRetrieved(pendingIntent));
+ }
+ };
+
+ executeApiCall(
+ new ApiCaller("getGestureTargetActivityPendingIntent") {
+ @Override
+ void performApiCall(IQuickAccessWalletService service) throws RemoteException {
+ service.onGestureTargetActivityIntentRequested(callbacks);
+ }
+ });
+ }
+
+ @Override
@Nullable
public Intent createWalletSettingsIntent() {
if (mServiceInfo == null) {
@@ -506,5 +534,9 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser
public void onTargetActivityPendingIntentReceived(PendingIntent pendingIntent) {
throw new IllegalStateException();
}
+
+ public void onGestureTargetActivityPendingIntentReceived(PendingIntent pendingIntent) {
+ throw new IllegalStateException();
+ }
}
}
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
index 36fa21c19d27..90136ae00f6a 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
@@ -16,6 +16,9 @@
package android.service.quickaccesswallet;
+import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -247,6 +250,19 @@ public abstract class QuickAccessWalletService extends Service {
callbacks));
}
+ @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ @Override
+ public void onGestureTargetActivityIntentRequested(
+ @NonNull IQuickAccessWalletServiceCallbacks callbacks) {
+ if (launchWalletOptionOnPowerDoubleTap()) {
+ mHandler.post(
+ () ->
+ QuickAccessWalletService.this
+ .onGestureTargetActivityIntentRequestedInternal(
+ callbacks));
+ }
+ }
+
public void registerWalletServiceEventListener(
@NonNull WalletServiceEventListenerRequest request,
@NonNull IQuickAccessWalletServiceCallbacks callback) {
@@ -275,6 +291,20 @@ public abstract class QuickAccessWalletService extends Service {
}
}
+ private void onGestureTargetActivityIntentRequestedInternal(
+ IQuickAccessWalletServiceCallbacks callbacks) {
+ if (!Flags.launchWalletOptionOnPowerDoubleTap()) {
+ return;
+ }
+
+ try {
+ callbacks.onGestureTargetActivityPendingIntentReceived(
+ getGestureTargetActivityPendingIntent());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error", e);
+ }
+ }
+
@Override
@Nullable
public IBinder onBind(@NonNull Intent intent) {
@@ -349,6 +379,18 @@ public abstract class QuickAccessWalletService extends Service {
return null;
}
+ /**
+ * Specify a {@link PendingIntent} to be launched on user gesture.
+ *
+ * <p>The pending intent will be sent when the user performs a gesture to open Wallet.
+ * The pending intent should launch an activity.
+ */
+ @Nullable
+ @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ public PendingIntent getGestureTargetActivityPendingIntent() {
+ return null;
+ }
+
private void sendWalletServiceEventInternal(WalletServiceEvent serviceEvent) {
if (mEventListener == null) {
Log.i(TAG, "No dismiss listener registered");
diff --git a/core/java/android/service/quickaccesswallet/flags.aconfig b/core/java/android/service/quickaccesswallet/flags.aconfig
new file mode 100644
index 000000000000..75a93091eec3
--- /dev/null
+++ b/core/java/android/service/quickaccesswallet/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.service.quickaccesswallet"
+container: "system"
+
+flag {
+ name: "launch_wallet_option_on_power_double_tap"
+ namespace: "wallet_integration"
+ description: "Option to launch the Wallet app on double-tap of the power button"
+ bug: "378469025"
+} \ No newline at end of file
diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
index 1d08c5217129..1acb7b8460cf 100644
--- a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
+++ b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
@@ -19,7 +19,7 @@ package android.service.settings.preferences;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.SuppressLint;
-import android.app.PendingIntent;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -63,7 +63,7 @@ public final class SettingsPreferenceMetadata implements Parcelable {
private final boolean mRestricted;
private final int mSensitivity;
@Nullable
- private final PendingIntent mLaunchIntent;
+ private final Intent mLaunchIntent;
@NonNull
private final Bundle mExtras;
@@ -149,6 +149,8 @@ public final class SettingsPreferenceMetadata implements Parcelable {
/**
* Returns whether Preference is restricted.
+ * <p>If true, this means the Preference is treated as a Restricted Preference which indicates
+ * that it could be conditionally disabled/unavailable due to admin settings.
*/
public boolean isRestricted() {
return mRestricted;
@@ -165,14 +167,18 @@ public final class SettingsPreferenceMetadata implements Parcelable {
/**
* Returns the intent to launch the host app page for this Preference.
*/
+ @SuppressLint("IntentBuilderName")
@Nullable
- public PendingIntent getLaunchIntent() {
+ public Intent getLaunchIntent() {
return mLaunchIntent;
}
/**
* Returns any additional fields specific to this preference.
- * <p>Treat all data as optional.
+ * <p>Treat all data as optional. This may contain unstructured data for a given preference,
+ * where the type and format of this data may only known by inspecting the source code of that
+ * preference. As such, any access of this data must handle failures gracefully to account for
+ * changing or missing data.
*/
@NonNull
public Bundle getExtras() {
@@ -236,8 +242,8 @@ public final class SettingsPreferenceMetadata implements Parcelable {
mWritable = in.readBoolean();
mRestricted = in.readBoolean();
mSensitivity = in.readInt();
- mLaunchIntent = in.readParcelable(PendingIntent.class.getClassLoader(),
- PendingIntent.class);
+ mLaunchIntent = in.readParcelable(Intent.class.getClassLoader(),
+ Intent.class);
mExtras = Objects.requireNonNullElseGet(in.readBundle(), Bundle::new);
}
@@ -298,7 +304,7 @@ public final class SettingsPreferenceMetadata implements Parcelable {
private boolean mWritable = false;
private boolean mRestricted = false;
@WriteSensitivity private int mSensitivity = INTENT_ONLY;
- private PendingIntent mLaunchIntent;
+ private Intent mLaunchIntent;
private Bundle mExtras;
/**
@@ -411,7 +417,7 @@ public final class SettingsPreferenceMetadata implements Parcelable {
* Sets the intent to launch the host app page for this preference.
*/
@NonNull
- public Builder setLaunchIntent(@Nullable PendingIntent launchIntent) {
+ public Builder setLaunchIntent(@Nullable Intent launchIntent) {
mLaunchIntent = launchIntent;
return this;
}
diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java b/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java
index 39995a47fcbe..f6d85d51ddd4 100644
--- a/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java
+++ b/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java
@@ -49,67 +49,55 @@ import java.util.concurrent.Executor;
* available services, a caller may query {@link android.content.pm.PackageManager} for applications
* that provide the intent action {@link SettingsPreferenceService#ACTION_PREFERENCE_SERVICE} that
* are also system applications ({@link android.content.pm.ApplicationInfo#FLAG_SYSTEM}).
+ * <p>
+ * Note: Each instance of this client will open a binding to an application. This can be resource
+ * intensive and affect the health of the system. It is essential that each client instance is
+ * only used when needed and the number of calls made are minimal.
*/
@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public class SettingsPreferenceServiceClient implements AutoCloseable {
+ @NonNull
private final Context mContext;
+ @NonNull
private final Intent mServiceIntent;
+ @NonNull
private final ServiceConnection mServiceConnection;
- private final boolean mSystemOnly;
+ @Nullable
private ISettingsPreferenceService mRemoteService;
/**
* Construct a client for binding to a {@link SettingsPreferenceService} provided by the
* application corresponding to the provided package name.
- * @param packageName - package name for which this client will initiate a service binding
+ * @param context Application context
+ * @param packageName package name for which this client will initiate a service binding
+ * @param callbackExecutor executor on which to invoke clientReadyCallback
+ * @param clientReadyCallback callback invoked once the client is ready, error otherwise
*/
- public SettingsPreferenceServiceClient(@NonNull Context context,
- @NonNull String packageName) {
- this(context, packageName, true, null);
+ public SettingsPreferenceServiceClient(
+ @NonNull Context context,
+ @NonNull String packageName,
+ @CallbackExecutor @NonNull Executor callbackExecutor,
+ @NonNull
+ OutcomeReceiver<SettingsPreferenceServiceClient, Exception> clientReadyCallback) {
+ this(context, packageName, true, callbackExecutor, clientReadyCallback);
}
/**
* @hide Only to be called directly by test
*/
@TestApi
- public SettingsPreferenceServiceClient(@NonNull Context context,
- @NonNull String packageName,
- boolean systemOnly,
- @Nullable ServiceConnection connectionListener) {
+ public SettingsPreferenceServiceClient(
+ @NonNull Context context,
+ @NonNull String packageName,
+ boolean systemOnly,
+ @CallbackExecutor @NonNull Executor callbackExecutor,
+ @NonNull
+ OutcomeReceiver<SettingsPreferenceServiceClient, Exception> clientReadyCallback) {
mContext = context.getApplicationContext();
mServiceIntent = new Intent(ACTION_PREFERENCE_SERVICE).setPackage(packageName);
- mSystemOnly = systemOnly;
- mServiceConnection = createServiceConnection(connectionListener);
- }
-
- /**
- * Initiate binding to service.
- * <p>If no service exists for the package provided or the package is not for a system
- * application, no binding will occur.
- */
- public void start() {
- PackageManager pm = mContext.getPackageManager();
- PackageManager.ResolveInfoFlags flags;
- if (mSystemOnly) {
- flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY);
- } else {
- flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL);
- }
- List<ResolveInfo> infos = pm.queryIntentServices(mServiceIntent, flags);
- if (infos.size() == 1) {
- mContext.bindService(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
- }
- }
-
- /**
- * If there is an active service binding, unbind from that service.
- */
- public void stop() {
- if (mRemoteService != null) {
- mRemoteService = null;
- mContext.unbindService(mServiceConnection);
- }
+ mServiceConnection = createServiceConnection(callbackExecutor, clientReadyCallback);
+ connect(systemOnly, callbackExecutor, clientReadyCallback);
}
/**
@@ -209,40 +197,73 @@ public class SettingsPreferenceServiceClient implements AutoCloseable {
}
}
+ /**
+ * This client handles a resource, thus is it important to appropriately close that resource
+ * when it is no longer needed.
+ * <p>This method is provided by {@link AutoCloseable} and calling it
+ * will unbind any service binding.
+ */
+ @Override
+ public void close() {
+ if (mRemoteService != null) {
+ mRemoteService = null;
+ mContext.unbindService(mServiceConnection);
+ }
+ }
+
+ /*
+ * Initiate binding to service.
+ * <p>If no service exists for the package provided or the package is not for a system
+ * application, no binding will occur.
+ */
+ private void connect(
+ boolean matchSystemOnly,
+ @NonNull Executor callbackExecutor,
+ @NonNull OutcomeReceiver<SettingsPreferenceServiceClient, Exception> clientCallback) {
+ PackageManager pm = mContext.getPackageManager();
+ PackageManager.ResolveInfoFlags flags;
+ if (matchSystemOnly) {
+ flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY);
+ } else {
+ flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL);
+ }
+ List<ResolveInfo> infos = pm.queryIntentServices(mServiceIntent, flags);
+ if (infos.size() != 1
+ || !mContext.bindService(mServiceIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE)) {
+ callbackExecutor.execute(() ->
+ clientCallback.onError(new IllegalStateException("Unable to bind service")));
+ }
+ }
+
@NonNull
- private ServiceConnection createServiceConnection(@Nullable ServiceConnection listener) {
+ private ServiceConnection createServiceConnection(
+ @NonNull Executor callbackExecutor,
+ @NonNull OutcomeReceiver<SettingsPreferenceServiceClient, Exception> clientCallback) {
return new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- mRemoteService = getPreferenceServiceInterface(service);
- if (listener != null) {
- listener.onServiceConnected(name, service);
- }
+ mRemoteService = ISettingsPreferenceService.Stub.asInterface(service);
+ callbackExecutor.execute(() ->
+ clientCallback.onResult(SettingsPreferenceServiceClient.this));
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteService = null;
- if (listener != null) {
- listener.onServiceDisconnected(name);
- }
}
- };
- }
- @NonNull
- private ISettingsPreferenceService getPreferenceServiceInterface(@NonNull IBinder service) {
- return ISettingsPreferenceService.Stub.asInterface(service);
- }
+ @Override
+ public void onBindingDied(ComponentName name) {
+ close();
+ }
- /**
- * This client handles a resource, thus is it important to appropriately close that resource
- * when it is no longer needed.
- * <p>This method is provided by {@link AutoCloseable} and calling it
- * will unbind any service binding.
- */
- @Override
- public void close() {
- stop();
+ @Override
+ public void onNullBinding(ComponentName name) {
+ callbackExecutor.execute(() -> clientCallback.onError(
+ new IllegalStateException("Unable to connect client")));
+ close();
+ }
+ };
}
}
diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
index f056e34a0dd2..08826ca9776b 100644
--- a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
+++ b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
@@ -44,6 +44,7 @@ public final class SettingsPreferenceValue implements Parcelable {
@Type
private final int mType;
private final boolean mBooleanValue;
+ private final int mIntValue;
private final long mLongValue;
private final double mDoubleValue;
@Nullable
@@ -65,6 +66,13 @@ public final class SettingsPreferenceValue implements Parcelable {
}
/**
+ * Returns the int value for Preference if type is {@link #TYPE_INT}.
+ */
+ public int getIntValue() {
+ return mIntValue;
+ }
+
+ /**
* Returns the long value for Preference if type is {@link #TYPE_LONG}.
*/
public long getLongValue() {
@@ -92,6 +100,7 @@ public final class SettingsPreferenceValue implements Parcelable {
TYPE_LONG,
TYPE_DOUBLE,
TYPE_STRING,
+ TYPE_INT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
@@ -104,6 +113,8 @@ public final class SettingsPreferenceValue implements Parcelable {
public static final int TYPE_DOUBLE = 2;
/** Value is of type string. Access via {@link #getStringValue}. */
public static final int TYPE_STRING = 3;
+ /** Value is of type int. Access via {@link #getIntValue}. */
+ public static final int TYPE_INT = 4;
private SettingsPreferenceValue(@NonNull Builder builder) {
mType = builder.mType;
@@ -111,6 +122,7 @@ public final class SettingsPreferenceValue implements Parcelable {
mLongValue = builder.mLongValue;
mDoubleValue = builder.mDoubleValue;
mStringValue = builder.mStringValue;
+ mIntValue = builder.mIntValue;
}
private SettingsPreferenceValue(@NonNull Parcel in) {
@@ -119,6 +131,7 @@ public final class SettingsPreferenceValue implements Parcelable {
mLongValue = in.readLong();
mDoubleValue = in.readDouble();
mStringValue = in.readString8();
+ mIntValue = in.readInt();
}
/** @hide */
@@ -129,6 +142,7 @@ public final class SettingsPreferenceValue implements Parcelable {
dest.writeLong(mLongValue);
dest.writeDouble(mDoubleValue);
dest.writeString8(mStringValue);
+ dest.writeInt(mIntValue);
}
/** @hide */
@@ -163,6 +177,7 @@ public final class SettingsPreferenceValue implements Parcelable {
private long mLongValue;
private double mDoubleValue;
private String mStringValue;
+ private int mIntValue;
/**
* Create Builder instance.
@@ -183,6 +198,15 @@ public final class SettingsPreferenceValue implements Parcelable {
}
/**
+ * Sets the int value for Preference.
+ */
+ @NonNull
+ public Builder setIntValue(int intValue) {
+ mIntValue = intValue;
+ return this;
+ }
+
+ /**
* Sets long value for Preference.
*/
@NonNull
diff --git a/core/java/android/service/wearable/WearableSensingService.java b/core/java/android/service/wearable/WearableSensingService.java
index 47ec0801f551..e20d5e996e66 100644
--- a/core/java/android/service/wearable/WearableSensingService.java
+++ b/core/java/android/service/wearable/WearableSensingService.java
@@ -27,6 +27,7 @@ import android.app.ambientcontext.AmbientContextEvent;
import android.app.ambientcontext.AmbientContextEventRequest;
import android.app.wearable.Flags;
import android.app.wearable.IWearableSensingCallback;
+import android.app.wearable.WearableConnection;
import android.app.wearable.WearableSensingDataRequest;
import android.app.wearable.WearableSensingManager;
import android.content.Context;
@@ -380,7 +381,11 @@ public abstract class WearableSensingService extends Service {
*
* @param secureWearableConnection The secure connection to the wearable.
* @param statusConsumer The consumer for the service status.
+ * @deprecated Use {@link #onSecureConnectionProvided(ParcelFileDescriptor, PersistableBundle,
+ * Consumer)} instead to receive a remote wearable device connection.
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
+ @Deprecated
@BinderThread
public void onSecureConnectionProvided(
@NonNull ParcelFileDescriptor secureWearableConnection,
@@ -389,12 +394,20 @@ public abstract class WearableSensingService extends Service {
}
/**
- * Called when a secure connection to the wearable is available.
+ * Called when a secure connection to the wearable is available. See {@link
+ * WearableSensingManager#provideConnection(WearableConnection, Executor)} for details about the
+ * secure connection.
+ *
+ * <p>When the {@code secureWearableConnection} is closed, the system will send a {@link
+ * WearableSensingManager#STATUS_CHANNEL_ERROR} status code to the error callback provided by
+ * the caller of {@link WearableSensingManager#provideConnection(WearableConnection, Executor)}.
+ *
+ * <p>The implementing class should override this method. It should return an appropriate status
+ * code via {@code statusConsumer} after receiving the {@code secureWearableConnection}.
*
* @param secureWearableConnection The secure connection to the wearable.
* @param metadata Metadata related to the provided connection.
* @param statusConsumer The consumer for the service status.
- * @see #onSecureConnectionProvided(ParcelFileDescriptor, Consumer)
*/
@FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
@BinderThread
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 1df3b4332754..c16a510ed729 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -1712,6 +1712,15 @@ public class PhoneStateListener {
@NonNull NtnSignalStrength ntnSignalStrength) {
// not supported on the deprecated interface - Use TelephonyCallback instead
}
+
+ public final void onSecurityAlgorithmsChanged(SecurityAlgorithmUpdate update) {
+ // not supported on the deprecated interface - Use TelephonyCallback instead
+ }
+
+ public final void onCellularIdentifierDisclosedChanged(
+ CellularIdentifierDisclosure disclosure) {
+ // not supported on the deprecated interface - Use TelephonyCallback instead
+ }
}
private void log(String s) {
diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
index 7b48a16c2227..4c59a8589df2 100644
--- a/core/java/android/telephony/SubscriptionPlan.java
+++ b/core/java/android/telephony/SubscriptionPlan.java
@@ -18,6 +18,7 @@ package android.telephony;
import android.annotation.BytesLong;
import android.annotation.CurrentTimeMillisLong;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,6 +29,7 @@ import android.telephony.Annotation.NetworkType;
import android.util.Range;
import android.util.RecurrenceRule;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
@@ -83,6 +85,33 @@ public final class SubscriptionPlan implements Parcelable {
/** Value indicating a timestamp is unknown. */
public static final long TIME_UNKNOWN = -1;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SUBSCRIPTION_STATUS_" }, value = {
+ SUBSCRIPTION_STATUS_UNKNOWN,
+ SUBSCRIPTION_STATUS_ACTIVE,
+ SUBSCRIPTION_STATUS_INACTIVE,
+ SUBSCRIPTION_STATUS_TRIAL,
+ SUBSCRIPTION_STATUS_SUSPENDED
+ })
+ public @interface SubscriptionStatus {}
+
+ /** Subscription status is unknown. */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public static final int SUBSCRIPTION_STATUS_UNKNOWN = 0;
+ /** Subscription is active. */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public static final int SUBSCRIPTION_STATUS_ACTIVE = 1;
+ /** Subscription is inactive. */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public static final int SUBSCRIPTION_STATUS_INACTIVE = 2;
+ /** Subscription is in a trial period. */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public static final int SUBSCRIPTION_STATUS_TRIAL = 3;
+ /** Subscription is suspended. */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public static final int SUBSCRIPTION_STATUS_SUSPENDED = 4;
+
private final RecurrenceRule cycleRule;
private CharSequence title;
private CharSequence summary;
@@ -91,6 +120,7 @@ public final class SubscriptionPlan implements Parcelable {
private long dataUsageBytes = BYTES_UNKNOWN;
private long dataUsageTime = TIME_UNKNOWN;
private @NetworkType int[] networkTypes;
+ private int mSubscriptionStatus = SUBSCRIPTION_STATUS_UNKNOWN;
private SubscriptionPlan(RecurrenceRule cycleRule) {
this.cycleRule = Preconditions.checkNotNull(cycleRule);
@@ -107,6 +137,7 @@ public final class SubscriptionPlan implements Parcelable {
dataUsageBytes = source.readLong();
dataUsageTime = source.readLong();
networkTypes = source.createIntArray();
+ mSubscriptionStatus = source.readInt();
}
@Override
@@ -124,6 +155,7 @@ public final class SubscriptionPlan implements Parcelable {
dest.writeLong(dataUsageBytes);
dest.writeLong(dataUsageTime);
dest.writeIntArray(networkTypes);
+ dest.writeInt(mSubscriptionStatus);
}
@Override
@@ -137,13 +169,14 @@ public final class SubscriptionPlan implements Parcelable {
.append(" dataUsageBytes=").append(dataUsageBytes)
.append(" dataUsageTime=").append(dataUsageTime)
.append(" networkTypes=").append(Arrays.toString(networkTypes))
+ .append(" subscriptionStatus=").append(mSubscriptionStatus)
.append("}").toString();
}
@Override
public int hashCode() {
return Objects.hash(cycleRule, title, summary, dataLimitBytes, dataLimitBehavior,
- dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes));
+ dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes), mSubscriptionStatus);
}
@Override
@@ -157,7 +190,8 @@ public final class SubscriptionPlan implements Parcelable {
&& dataLimitBehavior == other.dataLimitBehavior
&& dataUsageBytes == other.dataUsageBytes
&& dataUsageTime == other.dataUsageTime
- && Arrays.equals(networkTypes, other.networkTypes);
+ && Arrays.equals(networkTypes, other.networkTypes)
+ && mSubscriptionStatus == other.mSubscriptionStatus;
}
return false;
}
@@ -179,6 +213,13 @@ public final class SubscriptionPlan implements Parcelable {
return cycleRule;
}
+ /** Return the end date of this plan, or null if no end date exists. */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public @Nullable ZonedDateTime getPlanEndDate() {
+ // ZonedDateTime is immutable, so no need to create a defensive copy.
+ return cycleRule.end;
+ }
+
/** Return the short title of this plan. */
public @Nullable CharSequence getTitle() {
return title;
@@ -238,6 +279,16 @@ public final class SubscriptionPlan implements Parcelable {
}
/**
+ * Returns the status of the subscription plan.
+ *
+ * @return The subscription status, or {@link #SUBSCRIPTION_STATUS_UNKNOWN} if not available.
+ */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public @SubscriptionStatus int getSubscriptionStatus() {
+ return mSubscriptionStatus;
+ }
+
+ /**
* Builder for a {@link SubscriptionPlan}.
*/
public static class Builder {
@@ -382,5 +433,21 @@ public final class SubscriptionPlan implements Parcelable {
TelephonyManager.getAllNetworkTypes().length);
return this;
}
+
+ /**
+ * Set the subscription status.
+ *
+ * @param subscriptionStatus the current subscription status
+ */
+ @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+ public @NonNull Builder setSubscriptionStatus(@SubscriptionStatus int subscriptionStatus) {
+ if (subscriptionStatus < SUBSCRIPTION_STATUS_UNKNOWN
+ || subscriptionStatus > SUBSCRIPTION_STATUS_SUSPENDED) {
+ throw new IllegalArgumentException(
+ "Subscription status must be defined with a valid value");
+ }
+ plan.mSubscriptionStatus = subscriptionStatus;
+ return this;
+ }
}
}
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 0d1dc4611343..2c585e640fdd 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -705,6 +705,28 @@ public class TelephonyCallback {
public static final int EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED = 45;
/**
+ * Event for changes to mobile network ciphering algorithms.
+ * See {@link SecurityAlgorithmsListener#onSecurityAlgorithmsChanged}
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi
+ public static final int EVENT_SECURITY_ALGORITHMS_CHANGED = 46;
+
+ /**
+ * Event for updates to sensitive device identifier disclosures (IMSI, IMEI, unciphered SUCI).
+ * See {@link CellularIdentifierDisclosedListener#onCellularIdentifierDisclosedChanged}
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi
+ public static final int EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED = 47;
+
+ /**
* @hide
*/
@IntDef(prefix = {"EVENT_"}, value = {
@@ -752,7 +774,9 @@ public class TelephonyCallback {
EVENT_CARRIER_ROAMING_NTN_MODE_CHANGED,
EVENT_CARRIER_ROAMING_NTN_ELIGIBLE_STATE_CHANGED,
EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED,
- EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED
+ EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED,
+ EVENT_SECURITY_ALGORITHMS_CHANGED,
+ EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface TelephonyEvent {
@@ -1827,6 +1851,41 @@ public class TelephonyCallback {
}
/**
+ * Interface for CellularIdentifierDisclosedListener
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
+ public interface CellularIdentifierDisclosedListener {
+ /**
+ * Callback invoked when a device identifier (IMSI, IMEI, or unciphered SUCI)
+ * is disclosed over the network before a security context is established
+ * ("pre-authentication").
+ *
+ * @param disclosure details of the identifier disclosure
+ * See {@link CellularIdentifierDisclosure} for more details
+ */
+ void onCellularIdentifierDisclosedChanged(@NonNull CellularIdentifierDisclosure disclosure);
+ }
+
+ /**
+ * Interface for SecurityAlgorithmsListener
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SECURITY_ALGORITHMS_UPDATE_INDICATIONS)
+ public interface SecurityAlgorithmsListener {
+ /**
+ * Callback invoked when the most recently reported security algorithms has changed,
+ * per a specified connection event.
+ *
+ * @param securityAlgorithmUpdate details of the security algorithm update
+ * See {@link SecurityAlgorithmUpdate} for more details
+ */
+ void onSecurityAlgorithmsChanged(@NonNull SecurityAlgorithmUpdate securityAlgorithmUpdate);
+ }
+
+ /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
* <p>
@@ -2302,5 +2361,27 @@ public class TelephonyCallback {
() -> listener.onCarrierRoamingNtnSignalStrengthChanged(ntnSignalStrength)));
}
+
+ public void onSecurityAlgorithmsChanged(SecurityAlgorithmUpdate update) {
+ if (!Flags.securityAlgorithmsUpdateIndications()) return;
+
+ SecurityAlgorithmsListener listener =
+ (SecurityAlgorithmsListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+ () -> listener.onSecurityAlgorithmsChanged(update)));
+ }
+
+ public void onCellularIdentifierDisclosedChanged(CellularIdentifierDisclosure disclosure) {
+ if (!Flags.cellularIdentifierDisclosureIndications()) return;
+
+ CellularIdentifierDisclosedListener listener =
+ (CellularIdentifierDisclosedListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+ () -> listener.onCellularIdentifierDisclosedChanged(disclosure)));
+ }
}
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 90b0bb34c145..4ec429d0c4ad 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -1154,6 +1154,40 @@ public class TelephonyRegistryManager {
}
}
+ /**
+ * Notify external listeners that the radio security algorithms have changed.
+ * @param slotIndex for the phone object that got updated
+ * @param subId for which the security algorithm changed
+ * @param update details of the security algorithm update
+ * @hide
+ */
+ public void notifySecurityAlgorithmsChanged(
+ int slotIndex, int subId, SecurityAlgorithmUpdate update) {
+ try {
+ sRegistry.notifySecurityAlgorithmsChanged(slotIndex, subId, update);
+ } catch (RemoteException ex) {
+ // system server crash
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notify external listeners of a new cellular identifier disclosure change.
+ * @param slotIndex for the phone object that the disclosure applies to
+ * @param subId for which the disclosure applies to
+ * @param disclosure details of the identifier disclosure
+ * @hide
+ */
+ public void notifyCellularIdentifierDisclosedChanged(
+ int slotIndex, int subId, CellularIdentifierDisclosure disclosure) {
+ try {
+ sRegistry.notifyCellularIdentifierDisclosedChanged(slotIndex, subId, disclosure);
+ } catch (RemoteException ex) {
+ // system server crash
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
/**
* Processes potential event changes from the provided {@link TelephonyCallback}.
*
@@ -1313,6 +1347,15 @@ public class TelephonyRegistryManager {
eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED);
eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED);
}
+
+ if (telephonyCallback instanceof TelephonyCallback.CellularIdentifierDisclosedListener) {
+ eventList.add(TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED);
+ }
+
+ if (telephonyCallback instanceof TelephonyCallback.SecurityAlgorithmsListener) {
+ eventList.add(TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED);
+ }
+
return eventList;
}
diff --git a/core/java/android/text/ClientFlags.java b/core/java/android/text/ClientFlags.java
deleted file mode 100644
index ca887646b3aa..000000000000
--- a/core/java/android/text/ClientFlags.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2023 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.text;
-
-/**
- * An aconfig feature flags that can be accessible from application process without
- * ContentProvider IPCs.
- *
- * When you add new flags, you have to add flag string to {@link TextFlags#TEXT_ACONFIGS_FLAGS}.
- *
- * TODO(nona): Remove this class.
- * @hide
- */
-public class ClientFlags {
-}
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index ae12132d49a1..a42eece57eec 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -614,7 +614,7 @@ public class Html {
if (style[j] instanceof TypefaceSpan) {
String s = ((TypefaceSpan) style[j]).getFamily();
- if (s.equals("monospace")) {
+ if ("monospace".equals(s)) {
out.append("</tt>");
}
}
diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java
deleted file mode 100644
index f69a333ff81f..000000000000
--- a/core/java/android/text/TextFlags.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2023 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.text;
-
-import android.annotation.NonNull;
-import android.app.AppGlobals;
-
-/**
- * Flags in the "text" namespace.
- *
- * TODO(nona): Remove this class.
- * @hide
- */
-public final class TextFlags {
-
- /**
- * The name space of the "text" feature.
- *
- * This needs to move to DeviceConfig constant.
- */
- public static final String NAMESPACE = "text";
-
- /**
- * Whether we use the new design of context menu.
- */
- public static final String ENABLE_NEW_CONTEXT_MENU =
- "TextEditing__enable_new_context_menu";
-
- /**
- * The key name used in app core settings for {@link #ENABLE_NEW_CONTEXT_MENU}.
- */
- public static final String KEY_ENABLE_NEW_CONTEXT_MENU = "text__enable_new_context_menu";
-
- /**
- * Default value for the flag {@link #ENABLE_NEW_CONTEXT_MENU}.
- */
- public static final boolean ENABLE_NEW_CONTEXT_MENU_DEFAULT = true;
-
- /**
- * List of text flags to be transferred to the application process.
- */
- public static final String[] TEXT_ACONFIGS_FLAGS = {
- };
-
- /**
- * List of the default values of the text flags.
- *
- * The order must be the same to the TEXT_ACONFIG_FLAGS.
- */
- public static final boolean[] TEXT_ACONFIG_DEFAULT_VALUE = {
- };
-
- /**
- * Get a key for the feature flag.
- */
- public static String getKeyForFlag(@NonNull String flag) {
- return "text__" + flag;
- }
-
- /**
- * Return true if the feature flag is enabled.
- */
- public static boolean isFeatureEnabled(@NonNull String flag) {
- return AppGlobals.getIntCoreSetting(
- getKeyForFlag(flag), 0 /* aconfig is false by default */) != 0;
- }
-}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 032f5923d3f2..cb72b976c784 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -50,6 +50,7 @@ import android.text.style.LineBackgroundSpan;
import android.text.style.LineBreakConfigSpan;
import android.text.style.LineHeightSpan;
import android.text.style.LocaleSpan;
+import android.text.style.NoWritingToolsSpan;
import android.text.style.ParagraphStyle;
import android.text.style.QuoteSpan;
import android.text.style.RelativeSizeSpan;
@@ -817,7 +818,9 @@ public class TextUtils {
/** @hide */
public static final int LINE_BREAK_CONFIG_SPAN = 30;
/** @hide */
- public static final int LAST_SPAN = LINE_BREAK_CONFIG_SPAN;
+ public static final int NO_WRITING_TOOLS_SPAN = 31;
+ /** @hide */
+ public static final int LAST_SPAN = NO_WRITING_TOOLS_SPAN;
/**
* Flatten a CharSequence and whatever styles can be copied across processes
@@ -1025,6 +1028,10 @@ public class TextUtils {
span = LineBreakConfigSpan.CREATOR.createFromParcel(p);
break;
+ case NO_WRITING_TOOLS_SPAN:
+ span = NoWritingToolsSpan.CREATOR.createFromParcel(p);
+ break;
+
default:
throw new RuntimeException("bogus span encoding " + kind);
}
diff --git a/core/java/android/text/style/NoWritingToolsSpan.java b/core/java/android/text/style/NoWritingToolsSpan.java
new file mode 100644
index 000000000000..90f85aa69faa
--- /dev/null
+++ b/core/java/android/text/style/NoWritingToolsSpan.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 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.text.style;
+
+import static android.view.inputmethod.Flags.FLAG_WRITING_TOOLS;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
+
+/**
+ * A span that signals to IMEs that writing tools should not modify the text.
+ *
+ * <p>For example, a text field may contain a mix of user input text and quoted text. The app
+ * can apply {@code NoWritingToolsSpan} to the quoted text so that the IME knows that writing
+ * tools should only rewrite the user input text, and not modify the quoted text.
+ */
+@FlaggedApi(FLAG_WRITING_TOOLS)
+public final class NoWritingToolsSpan implements ParcelableSpan {
+
+ /**
+ * Creates a {@link NoWritingToolsSpan}.
+ */
+ public NoWritingToolsSpan() {
+ }
+
+ @Override
+ public int getSpanTypeId() {
+ return getSpanTypeIdInternal();
+ }
+
+ /** @hide */
+ @Override
+ public int getSpanTypeIdInternal() {
+ return TextUtils.NO_WRITING_TOOLS_SPAN;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ writeToParcelInternal(dest, flags);
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
+ }
+
+ @Override
+ public String toString() {
+ return "NoWritingToolsSpan{}";
+ }
+
+ @NonNull
+ public static final Creator<NoWritingToolsSpan> CREATOR = new Creator<>() {
+
+ @Override
+ public NoWritingToolsSpan createFromParcel(Parcel source) {
+ return new NoWritingToolsSpan();
+ }
+
+ @Override
+ public NoWritingToolsSpan[] newArray(int size) {
+ return new NoWritingToolsSpan[size];
+ }
+ };
+}
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index b7b8f0b1b5d8..a337ba2a57fb 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -19,6 +19,7 @@ package android.text.style;
import static com.android.text.flags.Flags.FLAG_TTS_SPAN_DURATION;
import android.annotation.FlaggedApi;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.PersistableBundle;
@@ -324,7 +325,8 @@ public class TtsSpan implements ParcelableSpan {
/**
* Argument used to specify the seconds of a time or duration. The seconds should be
- * provided as an integer in the range from 0 up to and including 59.
+ * provided as an integer in the range from 0 up to and including 59 for
+ * {@link #TYPE_TIME}.
* Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}.
*/
@FlaggedApi(FLAG_TTS_SPAN_DURATION)
@@ -1140,7 +1142,7 @@ public class TtsSpan implements ParcelableSpan {
* @return This instance.
* @see #ARG_HOURS
*/
- public TimeBuilder setHours(int hours) {
+ public TimeBuilder setHours(@IntRange(from = 0, to = 24) int hours) {
return setIntArgument(TtsSpan.ARG_HOURS, hours);
}
@@ -1151,7 +1153,7 @@ public class TtsSpan implements ParcelableSpan {
* @return This instance.
* @see #ARG_MINUTES
*/
- public TimeBuilder setMinutes(int minutes) {
+ public TimeBuilder setMinutes(@IntRange(from = 0, to = 59) int minutes) {
return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
}
@@ -1162,7 +1164,7 @@ public class TtsSpan implements ParcelableSpan {
*/
@FlaggedApi(FLAG_TTS_SPAN_DURATION)
@NonNull
- public TimeBuilder setSeconds(int seconds) {
+ public TimeBuilder setSeconds(@IntRange(from = 0, to = 59) int seconds) {
return setIntArgument(TtsSpan.ARG_SECONDS, seconds);
}
}
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 174e0c8e6549..7ee0ff15c5ad 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -649,7 +649,6 @@ public final class ArrayMap<K, V> implements Map<K, V> {
}
if (index > 0 && mHashes[index-1] > hash) {
RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
Log.w(TAG, "New hash " + hash
+ " is before end of array hash " + mHashes[index-1]
+ " at index " + index + (DEBUG ? " key " + key : ""), e);
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index bfbca07ed256..1344bb9a73eb 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -526,7 +526,6 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
// Cannot optimize since it would break the sorted order - fallback to add()
if (DEBUG) {
RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
Log.w(TAG, "New hash " + hash
+ " is before end of array hash " + mHashes[index - 1]
+ " at index " + index, e);
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index 5406cf557410..239da87b71ee 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -15,9 +15,11 @@
*/
package android.view;
+import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.UiThread;
import android.content.Context;
import android.graphics.Rect;
@@ -29,6 +31,8 @@ import android.window.SurfaceSyncGroup;
import com.android.window.flags.Flags;
+import java.util.concurrent.Executor;
+
/**
* Provides an interface to the root-Surface of a View Hierarchy or Window. This
* is used in combination with the {@link android.view.SurfaceControl} API to enable
@@ -202,4 +206,24 @@ public interface AttachedSurfaceControl {
throw new UnsupportedOperationException("The getInputTransferToken needs to be "
+ "implemented before making this call.");
}
+
+ /**
+ * Registers a {@link OnJankDataListener} to receive jank classification data about rendered
+ * frames.
+ * <p>
+ * Use {@link SurfaceControl.OnJankDataListenerRegistration#removeAfter} to unregister the
+ * listener.
+ *
+ * @param executor The executor on which the listener will be invoked.
+ * @param listener The listener to add.
+ * @return The {@link OnJankDataListenerRegistration} for the listener.
+ */
+ @NonNull
+ @FlaggedApi(Flags.FLAG_JANK_API)
+ @SuppressLint("PairedRegistration")
+ default SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull SurfaceControl.OnJankDataListener listener) {
+ return SurfaceControl.OnJankDataListenerRegistration.NONE;
+ }
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 7e247493e35c..8cb96ae1d611 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -189,6 +189,11 @@ public final class Choreographer {
@UnsupportedAppUsage
private long mLastFrameTimeNanos;
+ // Keeps track of the last scheduled frame time without additional offsets
+ // added from buffer stuffing recovery. Used to compare timing of vsyncs to
+ // determine idle state.
+ private long mLastNoOffsetFrameTimeNanos;
+
/** DO NOT USE since this will not updated when screen refresh changes. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@link android.view.Display#getRefreshRate} instead")
@@ -203,6 +208,50 @@ public final class Choreographer {
private final FrameData mFrameData = new FrameData();
private volatile boolean mInDoFrameCallback = false;
+ private static class BufferStuffingData {
+ enum RecoveryAction {
+ // No recovery
+ NONE,
+ // Recovery has started, adds a negative offset
+ OFFSET,
+ // Recovery has started, delays a frame to return buffer count
+ // back toward threshold.
+ DELAY_FRAME
+ }
+ // The maximum number of times frames will be delayed per buffer stuffing event.
+ // Since buffer stuffing can persist for several consecutive frames following the
+ // initial missed frame, we want to adjust the timeline with enough frame delays and
+ // offsets to return the queued buffer count back to threshold.
+ public static final int MAX_FRAME_DELAYS = 3;
+
+ // Whether buffer stuffing recovery has begun. Recovery can only end
+ // when events are idle.
+ public boolean isRecovering = false;
+
+ // The number of frames delayed so far during recovery. Used to compare with
+ // MAX_FRAME_DELAYS to safeguard against excessive frame delays during recovery.
+ // Also used as unique cookie for tracing.
+ public int numberFrameDelays = 0;
+
+ // The number of additional frame delays scheduled during recovery to wait for the next
+ // vsync. These are scheduled when frame times appear to go backward or frames are
+ // being skipped due to FPSDivisor.
+ public int numberWaitsForNextVsync = 0;
+
+ /**
+ * After buffer stuffing recovery has ended with a detected idle state, the
+ * recovery data trackers can be reset in preparation for any future
+ * stuffing events.
+ */
+ public void reset() {
+ isRecovering = false;
+ numberFrameDelays = 0;
+ numberWaitsForNextVsync = 0;
+ }
+ }
+
+ private final BufferStuffingData mBufferStuffingData = new BufferStuffingData();
+
/**
* Contains information about the current frame for jank-tracking,
* mainly timings of key events along with a bit of metadata about
@@ -850,13 +899,99 @@ public final class Choreographer {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
+ // Conducts logic for beginning or ending buffer stuffing recovery.
+ // Returns an enum for the recovery action that should be taken in doFrame().
+ BufferStuffingData.RecoveryAction checkBufferStuffingRecovery(long frameTimeNanos,
+ DisplayEventReceiver.VsyncEventData vsyncEventData) {
+ // Canned animations can recover from buffer stuffing whenever more
+ // than 2 buffers are queued.
+ if (vsyncEventData.numberQueuedBuffers > 2) {
+ mBufferStuffingData.isRecovering = true;
+ // Intentional frame delay that can happen at most MAX_FRAME_DELAYS times per
+ // buffer stuffing event until the buffer count returns to threshold. The
+ // delayed frames are compensated for by the negative offsets added to the
+ // animation timestamps.
+ if (mBufferStuffingData.numberFrameDelays < mBufferStuffingData.MAX_FRAME_DELAYS) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.asyncTraceForTrackBegin(
+ Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", "Thread "
+ + android.os.Process.myTid() + ", recover frame #"
+ + mBufferStuffingData.numberFrameDelays,
+ mBufferStuffingData.numberFrameDelays);
+ }
+ mBufferStuffingData.numberFrameDelays++;
+ scheduleVsyncLocked();
+ return BufferStuffingData.RecoveryAction.DELAY_FRAME;
+ }
+ }
+
+ if (mBufferStuffingData.isRecovering) {
+ // Includes an additional expected frame delay from the natural scheduling
+ // of the next vsync event.
+ int totalFrameDelays = mBufferStuffingData.numberFrameDelays
+ + mBufferStuffingData.numberWaitsForNextVsync + 1;
+ long vsyncsSinceLastCallback = mLastFrameIntervalNanos > 0
+ ? (frameTimeNanos - mLastNoOffsetFrameTimeNanos) / mLastFrameIntervalNanos : 0;
+
+ // Detected idle state due to a longer inactive period since the last vsync callback
+ // than the total expected number of vsync frame delays. End buffer stuffing recovery.
+ // There are no frames to animate and offsets no longer need to be added
+ // since the idle state gives the animation a chance to catch up.
+ if (vsyncsSinceLastCallback > totalFrameDelays) {
+ if (DEBUG_JANK) {
+ Log.d(TAG, "End buffer stuffing recovery");
+ }
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ for (int i = 0; i < mBufferStuffingData.numberFrameDelays; i++) {
+ Trace.asyncTraceForTrackEnd(
+ Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", i);
+ }
+ }
+ mBufferStuffingData.reset();
+
+ } else {
+ if (DEBUG_JANK) {
+ Log.d(TAG, "Adjust animation timeline with a negative offset");
+ }
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.instantForTrack(
+ Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery",
+ "Negative offset added to animation");
+ }
+ return BufferStuffingData.RecoveryAction.OFFSET;
+ }
+ }
+ return BufferStuffingData.RecoveryAction.NONE;
+ }
+
void doFrame(long frameTimeNanos, int frame,
DisplayEventReceiver.VsyncEventData vsyncEventData) {
final long startNanos;
final long frameIntervalNanos = vsyncEventData.frameInterval;
boolean resynced = false;
+ long offsetFrameTimeNanos = frameTimeNanos;
+
+ // Evaluate if buffer stuffing recovery needs to start or end, and
+ // what actions need to be taken for recovery.
+ switch (checkBufferStuffingRecovery(frameTimeNanos, vsyncEventData)) {
+ case NONE:
+ // Without buffer stuffing recovery, offsetFrameTimeNanos is
+ // synonymous with frameTimeNanos.
+ break;
+ case OFFSET:
+ // Add animation offset. Used to update frame timeline with
+ // offset before jitter is calculated.
+ offsetFrameTimeNanos = frameTimeNanos - frameIntervalNanos;
+ break;
+ case DELAY_FRAME:
+ // Intentional frame delay to help restore queued buffer count to threshold.
+ return;
+ default:
+ break;
+ }
+
try {
- FrameTimeline timeline = mFrameData.update(frameTimeNanos, vsyncEventData);
+ FrameTimeline timeline = mFrameData.update(offsetFrameTimeNanos, vsyncEventData);
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(
Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + timeline.mVsyncId);
@@ -867,15 +1002,18 @@ public final class Choreographer {
traceMessage("Frame not scheduled");
return; // no work to do
}
+ mLastNoOffsetFrameTimeNanos = frameTimeNanos;
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: "
- + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
+ + ((offsetFrameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
- long intendedFrameTimeNanos = frameTimeNanos;
+ long intendedFrameTimeNanos = offsetFrameTimeNanos;
startNanos = System.nanoTime();
+ // Calculating jitter involves using the original frame time without
+ // adjustments from buffer stuffing
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= frameIntervalNanos) {
frameTimeNanos = startNanos;
@@ -899,6 +1037,13 @@ public final class Choreographer {
+ " ms in the past.");
}
}
+ if (mBufferStuffingData.isRecovering) {
+ frameTimeNanos -= frameIntervalNanos;
+ if (DEBUG_JANK) {
+ Log.d(TAG, "Adjusted animation timeline with a negative offset after"
+ + " jitter calculation");
+ }
+ }
timeline = mFrameData.update(
frameTimeNanos, mDisplayEventReceiver, jitterNanos);
resynced = true;
@@ -910,6 +1055,9 @@ public final class Choreographer {
+ "previously skipped frame. Waiting for next vsync.");
}
traceMessage("Frame time goes backward");
+ if (mBufferStuffingData.isRecovering) {
+ mBufferStuffingData.numberWaitsForNextVsync++;
+ }
scheduleVsyncLocked();
return;
}
@@ -918,6 +1066,9 @@ public final class Choreographer {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
traceMessage("Frame skipped due to FPSDivisor");
+ if (mBufferStuffingData.isRecovering) {
+ mBufferStuffingData.numberWaitsForNextVsync++;
+ }
scheduleVsyncLocked();
return;
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index a1a9fc697271..c9d560c3424b 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE;
import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
import static android.hardware.flags.Flags.FLAG_OVERLAYPROPERTIES_CLASS_API;
+import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES;
import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API;
import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_HAS_ARR_SUPPORT;
import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE;
@@ -63,6 +64,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -1207,17 +1209,36 @@ public final class Display {
/**
* Get the supported refresh rates of this display in frames per second.
- * <p>
- * This method only returns refresh rates for the display's default modes. For more options, use
- * {@link #getSupportedModes()}.
*
- * @deprecated use {@link #getSupportedModes()} instead
+ * <ul>
+ * <li> Android version {@link Build.VERSION_CODES#BAKLAVA} and above:
+ * returns display supported render rates.
+ * <li> Android version {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and below:
+ * This method only returns refresh rates for the display's default modes. For more options,
+ * use {@link #getSupportedModes()}.
+ * </ul>
*/
- @Deprecated
- public float[] getSupportedRefreshRates() {
+ @FlaggedApi(FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES)
+ public @NonNull float[] getSupportedRefreshRates() {
+ synchronized (mLock) {
+ updateDisplayInfoLocked();
+ final float[] refreshRates = mDisplayInfo.getDefaultRefreshRates();
+ Objects.requireNonNull(refreshRates);
+ return refreshRates;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
+ @SuppressLint({"UnflaggedApi"}) // Usage in the CTS to test backward compatibility.
+ public @NonNull float[] getSupportedRefreshRatesLegacy() {
synchronized (mLock) {
updateDisplayInfoLocked();
- return mDisplayInfo.getDefaultRefreshRates();
+ final float[] refreshRates = mDisplayInfo.getDefaultRefreshRatesLegacy();
+ Objects.requireNonNull(refreshRates);
+ return refreshRates;
}
}
@@ -1279,8 +1300,19 @@ public final class Display {
}
}
+ /**
+ * Represents the {@link FrameRateCategory} for the Normal frame rate
+ *
+ * @see FrameRateCategory
+ */
@FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE)
public static final int FRAME_RATE_CATEGORY_NORMAL = 0;
+
+ /**
+ * Represents the {@link FrameRateCategory} for the High frame rate
+ *
+ * @see FrameRateCategory
+ */
@FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE)
public static final int FRAME_RATE_CATEGORY_HIGH = 1;
@@ -2438,6 +2470,8 @@ public final class Display {
* constrained by the system.
* @hide
*/
+ @SuppressWarnings("UnflaggedApi") // For testing only
+ @TestApi
public float getVsyncRate() {
return mVsyncRate;
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index fc7a65dbdc41..bb233d2711de 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -207,6 +207,8 @@ public abstract class DisplayEventReceiver {
// reasonable timestamps.
public int frameTimelinesLength = 1;
+ public int numberQueuedBuffers = 0;
+
VsyncEventData() {
frameTimelines = new FrameTimeline[FRAME_TIMELINES_CAPACITY];
for (int i = 0; i < frameTimelines.length; i++) {
@@ -217,11 +219,13 @@ public abstract class DisplayEventReceiver {
// Called from native code.
@SuppressWarnings("unused")
VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex,
- int frameTimelinesLength, long frameInterval) {
+ int frameTimelinesLength, long frameInterval,
+ int numberQueuedBuffers) {
this.frameTimelines = frameTimelines;
this.preferredFrameTimelineIndex = preferredFrameTimelineIndex;
this.frameTimelinesLength = frameTimelinesLength;
this.frameInterval = frameInterval;
+ this.numberQueuedBuffers = numberQueuedBuffers;
}
void copyFrom(VsyncEventData other) {
@@ -231,6 +235,7 @@ public abstract class DisplayEventReceiver {
for (int i = 0; i < frameTimelines.length; i++) {
frameTimelines[i].copyFrom(other.frameTimelines[i]);
}
+ numberQueuedBuffers = other.numberQueuedBuffers;
}
public FrameTimeline preferredFrameTimeline() {
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 4ff04d5c1fa6..8b6458a54c43 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -210,6 +210,11 @@ public final class DisplayInfo implements Parcelable {
public FrameRateCategoryRate frameRateCategoryRate;
/**
+ * All the refresh rates supported in the active mode.
+ */
+ public float[] supportedRefreshRates = new float[0];
+
+ /**
* The default display mode.
*/
public int defaultModeId;
@@ -449,6 +454,7 @@ public final class DisplayInfo implements Parcelable {
&& modeId == other.modeId
&& hasArrSupport == other.hasArrSupport
&& Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)
+ && Arrays.equals(supportedRefreshRates, other.supportedRefreshRates)
&& defaultModeId == other.defaultModeId
&& userPreferredModeId == other.userPreferredModeId
&& Arrays.equals(supportedModes, other.supportedModes)
@@ -512,6 +518,8 @@ public final class DisplayInfo implements Parcelable {
renderFrameRate = other.renderFrameRate;
hasArrSupport = other.hasArrSupport;
frameRateCategoryRate = other.frameRateCategoryRate;
+ supportedRefreshRates = Arrays.copyOf(
+ other.supportedRefreshRates, other.supportedRefreshRates.length);
defaultModeId = other.defaultModeId;
userPreferredModeId = other.userPreferredModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
@@ -571,6 +579,11 @@ public final class DisplayInfo implements Parcelable {
hasArrSupport = source.readBoolean();
frameRateCategoryRate = source.readParcelable(null,
android.view.FrameRateCategoryRate.class);
+ int numOfSupportedRefreshRates = source.readInt();
+ supportedRefreshRates = new float[numOfSupportedRefreshRates];
+ for (int i = 0; i < numOfSupportedRefreshRates; i++) {
+ supportedRefreshRates[i] = source.readFloat();
+ }
defaultModeId = source.readInt();
userPreferredModeId = source.readInt();
int nModes = source.readInt();
@@ -646,6 +659,10 @@ public final class DisplayInfo implements Parcelable {
dest.writeFloat(renderFrameRate);
dest.writeBoolean(hasArrSupport);
dest.writeParcelable(frameRateCategoryRate, flags);
+ dest.writeInt(supportedRefreshRates.length);
+ for (float supportedRefreshRate : supportedRefreshRates) {
+ dest.writeFloat(supportedRefreshRate);
+ }
dest.writeInt(defaultModeId);
dest.writeInt(userPreferredModeId);
dest.writeInt(supportedModes.length);
@@ -750,9 +767,19 @@ public final class DisplayInfo implements Parcelable {
}
/**
- * Returns the list of supported refresh rates in the default mode.
+ * Returns the list of supported refresh rates in the active mode.
*/
public float[] getDefaultRefreshRates() {
+ if (supportedRefreshRates.length == 0) {
+ return getDefaultRefreshRatesLegacy();
+ }
+ return Arrays.copyOf(supportedRefreshRates, supportedRefreshRates.length);
+ }
+
+ /**
+ * Returns the list of supported refresh rates in the default mode.
+ */
+ public float[] getDefaultRefreshRatesLegacy() {
Display.Mode[] modes = appsSupportedModes;
ArraySet<Float> rates = new ArraySet<>();
Display.Mode defaultMode = getDefaultMode();
@@ -898,6 +925,8 @@ public final class DisplayInfo implements Parcelable {
sb.append(hasArrSupport);
sb.append(", frameRateCategoryRate ");
sb.append(frameRateCategoryRate);
+ sb.append(", supportedRefreshRates ");
+ sb.append(Arrays.toString(supportedRefreshRates));
sb.append(", defaultMode ");
sb.append(defaultModeId);
sb.append(", userPreferredModeId ");
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 9e25a3e18c0c..58b2a67ec69e 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -18,10 +18,13 @@ package android.view;
import static android.graphics.FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import com.android.window.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -177,6 +180,16 @@ public final class FrameMetrics {
public static final int DEADLINE = 13;
/**
+ * Metric identifier for the frame's VSync identifier.
+ * <p>
+ * The id that corresponds to the chosen frame timeline, used to correlate a frame produced
+ * by HWUI with the timeline data from the compositor.
+ * </p>
+ */
+ @FlaggedApi(Flags.FLAG_JANK_API)
+ public static final int FRAME_TIMELINE_VSYNC_ID = 14;
+
+ /**
* Identifiers for metrics available for each frame.
*
* {@see #getMetric(int)}
@@ -337,7 +350,8 @@ public final class FrameMetrics {
* @return the value of the metric or -1 if it is not available.
*/
public long getMetric(@Metric int id) {
- if (id < UNKNOWN_DELAY_DURATION || id > DEADLINE) {
+ if (id < UNKNOWN_DELAY_DURATION
+ || id > (Flags.jankApi() ? FRAME_TIMELINE_VSYNC_ID : DEADLINE)) {
return -1;
}
@@ -351,6 +365,8 @@ public final class FrameMetrics {
return mTimingData[Index.INTENDED_VSYNC];
} else if (id == VSYNC_TIMESTAMP) {
return mTimingData[Index.VSYNC];
+ } else if (id == FRAME_TIMELINE_VSYNC_ID) {
+ return mTimingData[Index.FRAME_TIMELINE_VSYNC_ID];
}
int durationsIdx = 2 * id;
@@ -358,4 +374,3 @@ public final class FrameMetrics {
- mTimingData[DURATIONS[durationsIdx]];
}
}
-
diff --git a/core/java/android/view/HapticScrollFeedbackProvider.java b/core/java/android/view/HapticScrollFeedbackProvider.java
index 0001176220b5..c3fb855eb1ff 100644
--- a/core/java/android/view/HapticScrollFeedbackProvider.java
+++ b/core/java/android/view/HapticScrollFeedbackProvider.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.flags.Flags.dynamicViewRotaryHapticsConfiguration;
+
import android.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
@@ -41,13 +43,8 @@ public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {
private final View mView;
private final ViewConfiguration mViewConfig;
- /**
- * Flag to disable the logic in this class if the View-based scroll haptics implementation is
- * enabled. If {@code false}, this class will continue to run despite the View's scroll
- * haptics implementation being enabled. This value should be set to {@code true} when this
- * class is directly used by the View class.
- */
- private final boolean mDisabledIfViewPlaysScrollHaptics;
+ /** Whether or not this provider is being used directly by the View class. */
+ private final boolean mIsFromView;
// Info about the cause of the latest scroll event.
@@ -65,17 +62,23 @@ public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {
private boolean mHapticScrollFeedbackEnabled = false;
public HapticScrollFeedbackProvider(@NonNull View view) {
- this(view, ViewConfiguration.get(view.getContext()),
- /* disabledIfViewPlaysScrollHaptics= */ true);
+ this(view, ViewConfiguration.get(view.getContext()), /* isFromView= */ false);
}
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public HapticScrollFeedbackProvider(
- View view, ViewConfiguration viewConfig, boolean disabledIfViewPlaysScrollHaptics) {
+ View view, ViewConfiguration viewConfig, boolean isFromView) {
mView = view;
mViewConfig = viewConfig;
- mDisabledIfViewPlaysScrollHaptics = disabledIfViewPlaysScrollHaptics;
+ mIsFromView = isFromView;
+ if (dynamicViewRotaryHapticsConfiguration() && !isFromView) {
+ // Disable the View class's rotary scroll feedback logic if this provider is not being
+ // directly used by the View class. This is to avoid double rotary scroll feedback:
+ // one from the View class, and one from this provider instance (i.e. mute the View
+ // class's rotary feedback and enable this provider).
+ view.disableRotaryScrollFeedback();
+ }
}
@Override
@@ -151,7 +154,8 @@ public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {
mAxis = axis;
mDeviceId = deviceId;
- if (mDisabledIfViewPlaysScrollHaptics
+ if (!dynamicViewRotaryHapticsConfiguration()
+ && !mIsFromView
&& (source == InputDevice.SOURCE_ROTARY_ENCODER)
&& mViewConfig.isViewBasedRotaryEncoderHapticScrollFeedbackEnabled()) {
mHapticScrollFeedbackEnabled = false;
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 11a3168daa0e..1f8f0820ca3a 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -372,4 +372,14 @@ interface IWindowSession {
*/
oneway void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
in ImeTracker.Token statsToken);
+
+ /**
+ * Notifies WindowState whether inset animations are currently running within the Window.
+ * This value is used by the server to vote for refresh rate.
+ * see {@link com.android.server.wm.WindowState#mInsetsAnimationRunning).
+ *
+ * @param window The window that is insets animaiton is running.
+ * @param running Indicates the insets animation state.
+ */
+ oneway void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running);
}
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 58ef5efe846f..6cd4a4033adf 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -260,6 +260,15 @@ public final class InputWindowHandle {
touchableRegionSurfaceControl = new WeakReference<>(bounds);
}
+ /**
+ * Resize the window touchable region.
+ * @param rect new touchable region rectangle.
+ */
+ public void setTouchableRegion(Rect rect) {
+ touchableRegion.set(rect);
+ }
+
+
public void setWindowToken(IBinder iwindow) {
windowToken = iwindow;
}
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 5a28d5f7fc01..80ae3c3d4e73 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -437,16 +437,16 @@ public class ScaleGestureDetector {
}
}
- /**
- * Return whether the quick scale gesture, in which the user performs a double tap followed by a
- * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
- */
+ /**
+ * Return whether the quick scale gesture, in which the user performs a double tap followed by a
+ * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
+ */
public boolean isQuickScaleEnabled() {
return mQuickScaleEnabled;
}
/**
- * Sets whether the associates {@link OnScaleGestureListener} should receive
+ * Sets whether the associated {@link OnScaleGestureListener} should receive
* onScale callbacks when the user uses a stylus and presses the button.
* Note that this is enabled by default if the app targets API 23 and newer.
*
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 206c73756088..dd9a95e58bd1 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -22,6 +22,7 @@ import static android.graphics.Matrix.MSKEW_X;
import static android.graphics.Matrix.MSKEW_Y;
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
+import static android.view.flags.Flags.bufferStuffingRecovery;
import static android.view.SurfaceControlProto.HASH_CODE;
import static android.view.SurfaceControlProto.LAYER_ID;
import static android.view.SurfaceControlProto.NAME;
@@ -36,6 +37,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.Size;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.ColorSpace;
@@ -57,6 +59,7 @@ import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
import android.hardware.graphics.common.DisplayDecorationSupport;
+import android.media.quality.PictureProfileHandle;
import android.opengl.EGLDisplay;
import android.opengl.EGLSync;
import android.os.Build;
@@ -233,7 +236,6 @@ public final class SurfaceControl implements Parcelable {
long nativeObject, float currentBufferRatio, float desiredRatio);
private static native void nativeSetDesiredHdrHeadroom(long transactionObj,
long nativeObject, float desiredRatio);
-
private static native void nativeSetCachingHint(long transactionObj,
long nativeObject, int cachingHint);
private static native void nativeSetDamageRegion(long transactionObj, long nativeObject,
@@ -313,6 +315,11 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeSetLuts(long transactionObj, long nativeObject,
float[] buffers, int[] slots, int[] dimensions, int[] sizes, int[] samplingKeys);
private static native void nativeEnableDebugLogCallPoints(long transactionObj);
+ private static native int nativeGetMaxPictureProfiles();
+ private static native void nativeSetPictureProfileId(long transactionObj,
+ long nativeObject, long pictureProfileId);
+ private static native void nativeSetContentPriority(long transactionObj, long nativeObject,
+ int priority);
/**
* Transforms that can be applied to buffers as they are displayed to a window.
@@ -410,8 +417,19 @@ public final class SurfaceControl implements Parcelable {
/**
* Jank information to be fed back via {@link OnJankDataListener}.
- * @hide
+ * <p>
+ * Apps may register a {@link OnJankDataListener} to get periodic batches of jank classification
+ * data from the (<a
+ * href="https://source.android.com/docs/core/graphics/surfaceflinger-windowmanagersystem">
+ * composer</a> regarding rendered frames. A frame is considered janky if it did not reach the
+ * display at the intended time, typically due to missing a rendering deadline. This API
+ * provides information that can be used to identify the root cause of the scheduling misses
+ * and provides overall frame scheduling statistics.
+ * <p>
+ * This API can be used in conjunction with the {@link FrameMetrics} API by associating jank
+ * classification data with {@link FrameMetrics} data via the frame VSync id.
*/
+ @FlaggedApi(Flags.FLAG_JANK_API)
public static class JankData {
/**
@@ -428,29 +446,105 @@ public final class SurfaceControl implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface JankType {}
- // No Jank
+ /**
+ * No jank detected, the frame was on time.
+ */
public static final int JANK_NONE = 0;
- // Jank caused by the composer missing a deadline
+
+ /**
+ * Bitmask for jank due to deadlines missed by the composer.
+ */
public static final int JANK_COMPOSER = 1 << 0;
- // Jank caused by the application missing the composer's deadline
+
+ /**
+ * Bitmask for jank due to deadlines missed by the application.
+ */
public static final int JANK_APPLICATION = 1 << 1;
- // Jank due to other unknown reasons
+
+ /**
+ * Bitmask for jank due to deadlines missed by other system components.
+ */
public static final int JANK_OTHER = 1 << 2;
+ private final long mFrameVsyncId;
+ private final @JankType int mJankType;
+ private final long mFrameIntervalNs;
+ private final long mScheduledAppFrameTimeNs;
+ private final long mActualAppFrameTimeNs;
+
+ /**
+ * @hide
+ */
public JankData(long frameVsyncId, @JankType int jankType, long frameIntervalNs,
long scheduledAppFrameTimeNs, long actualAppFrameTimeNs) {
- this.frameVsyncId = frameVsyncId;
- this.jankType = jankType;
- this.frameIntervalNs = frameIntervalNs;
- this.scheduledAppFrameTimeNs = scheduledAppFrameTimeNs;
- this.actualAppFrameTimeNs = actualAppFrameTimeNs;
- }
-
- public final long frameVsyncId;
- public final @JankType int jankType;
- public final long frameIntervalNs;
- public final long scheduledAppFrameTimeNs;
- public final long actualAppFrameTimeNs;
+ mFrameVsyncId = frameVsyncId;
+ mJankType = jankType;
+ mFrameIntervalNs = frameIntervalNs;
+ mScheduledAppFrameTimeNs = scheduledAppFrameTimeNs;
+ mActualAppFrameTimeNs = actualAppFrameTimeNs;
+ }
+
+ /**
+ * Returns the id of the frame for this jank classification.
+ *
+ * @see FrameMetrics#FRAME_TIMELINE_VSYNC_ID
+ * @see Choreographer.FrameTimeline#getVsyncId
+ * @see Transaction#setFrameTimeline
+ * @return the frame id
+ */
+ public long getVsyncId() {
+ return mFrameVsyncId;
+ }
+
+ /**
+ * Returns the bitmask indicating the types of jank observed.
+ *
+ * @return the jank type bitmask
+ */
+ public @JankType int getJankType() {
+ return mJankType;
+ }
+
+ /**
+ * Returns the time between frame VSyncs in nanoseconds.
+ *
+ * @return the frame interval in ns
+ * @hide
+ */
+ public long getFrameIntervalNanos() {
+ return mFrameIntervalNs;
+ }
+
+ /**
+ * Returns the duration in nanoseconds the application was scheduled to use to render this
+ * frame.
+ * <p>
+ * Note that this may be higher than the frame interval to allow for CPU/GPU
+ * parallelization of work.
+ *
+ * @return scheduled app time in ns
+ */
+ public long getScheduledAppFrameTimeNanos() {
+ return mScheduledAppFrameTimeNs;
+ }
+
+ /**
+ * Returns the actual time in nanoseconds taken by the application to render this frame.
+ *
+ * @return the actual app time in ns
+ */
+ public long getActualAppFrameTimeNanos() {
+ return mActualAppFrameTimeNs;
+ }
+
+ @Override
+ public String toString() {
+ return "JankData{vsync=" + mFrameVsyncId
+ + ", jankType=0x" + Integer.toHexString(mJankType)
+ + ", frameInterval=" + mFrameIntervalNs + "ns"
+ + ", scheduledAppTime=" + mScheduledAppFrameTimeNs + "ns"
+ + ", actualAppTime=" + mActualAppFrameTimeNs + "ns}";
+ }
}
/**
@@ -458,12 +552,13 @@ public final class SurfaceControl implements Parcelable {
* surface.
*
* @see JankData
- * @see #addJankDataListener
- * @hide
+ * @see #addOnJankDataListener
*/
+ @FlaggedApi(Flags.FLAG_JANK_API)
public interface OnJankDataListener {
/**
- * Called when new jank classifications are available.
+ * Called when new jank classifications are available. The listener is invoked out of band
+ * of the rendered frames with jank classification data for a batch of frames.
*/
void onJankDataAvailable(@NonNull List<JankData> jankData);
@@ -471,9 +566,22 @@ public final class SurfaceControl implements Parcelable {
/**
* Handle to a registered {@link OnJankDatalistener}.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_JANK_API)
public static class OnJankDataListenerRegistration {
+ /** @hide */
+ public static final OnJankDataListenerRegistration NONE =
+ new OnJankDataListenerRegistration() {
+ @Override
+ public void flush() {}
+
+ @Override
+ public void removeAfter(long afterVsync) {}
+
+ @Override
+ public void release() {}
+ };
+
private final long mNativeObject;
private static final NativeAllocationRegistry sRegistry =
@@ -484,6 +592,11 @@ public final class SurfaceControl implements Parcelable {
private final Runnable mFreeNativeResources;
private boolean mRemoved = false;
+ private OnJankDataListenerRegistration() {
+ mNativeObject = 0;
+ mFreeNativeResources = () -> {};
+ }
+
OnJankDataListenerRegistration(SurfaceControl surface, OnJankDataListener listener) {
mNativeObject = nativeCreateJankDataListenerWrapper(surface.mNativeObject, listener);
mFreeNativeResources = (mNativeObject == 0) ? () -> {} :
@@ -491,18 +604,28 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * Request a flush of any pending jank classification data. May cause the registered
- * listener to be invoked inband.
+ * Request a flush of any pending jank classification data.
+ * <p>
+ * May cause the registered listener to be invoked inband. Since jank is tracked by the
+ * system compositor by surface, flushing the data on one listener, will also cause other
+ * listeners on the same surface to receive jank classification data.
*/
public void flush() {
nativeFlushJankData(mNativeObject);
}
/**
- * Request the removal of the registered listener after the VSync with the provided ID. Use
- * a value <= 0 for afterVsync to remove the listener immediately. The given listener will
- * not be removed before the given VSync, but may still reveive data for frames past the
- * provided VSync.
+ * Schedule the removal of the registered listener after the frame with the provided id.
+ * <p>
+ * Because jank classification is only possible after frames have been displayed, the
+ * callbacks are always delayed. To ensure receipt of all jank classification data, an
+ * application can schedule the removal to happen no sooner than after the data for the
+ * frame with the provided id has been provided.
+ * <p>
+ * Use a value &lt;= 0 for afterVsync to remove the listener immediately, ensuring no future
+ * callbacks.
+ *
+ * @param afterVsync the id of the Vsync after which to remove the listener
*/
public void removeAfter(long afterVsync) {
mRemoved = true;
@@ -511,6 +634,7 @@ public final class SurfaceControl implements Parcelable {
/**
* Free the native resources associated with the listener registration.
+ * @hide
*/
public void release() {
if (!mRemoved) {
@@ -663,6 +787,13 @@ public final class SurfaceControl implements Parcelable {
public static final int CAN_OCCLUDE_PRESENTATION = 0x00001000;
/**
+ * Indicates that the SurfaceControl should recover from buffer stuffing when
+ * possible. This is the case when the SurfaceControl is a ViewRootImpl.
+ * @hide
+ */
+ public static final int RECOVERABLE_FROM_BUFFER_STUFFING = 0x00002000;
+
+ /**
* Surface creation flag: Creates a surface where color components are interpreted
* as "non pre-multiplied" by their alpha channel. Of course this flag is
* meaningless for surfaces without an alpha channel. By default
@@ -1801,6 +1932,7 @@ public final class SurfaceControl implements Parcelable {
public float renderFrameRate;
public boolean hasArrSupport;
public FrameRateCategoryRate frameRateCategoryRate;
+ public float[] supportedRefreshRates;
public int[] supportedColorModes;
public int activeColorMode;
@@ -1820,6 +1952,7 @@ public final class SurfaceControl implements Parcelable {
+ ", renderFrameRate=" + renderFrameRate
+ ", hasArrSupport=" + hasArrSupport
+ ", frameRateCategoryRate=" + frameRateCategoryRate
+ + ", supportedRefreshRates=" + Arrays.toString(supportedRefreshRates)
+ ", supportedColorModes=" + Arrays.toString(supportedColorModes)
+ ", activeColorMode=" + activeColorMode
+ ", hdrCapabilities=" + hdrCapabilities
@@ -1841,14 +1974,15 @@ public final class SurfaceControl implements Parcelable {
&& Objects.equals(hdrCapabilities, that.hdrCapabilities)
&& preferredBootDisplayMode == that.preferredBootDisplayMode
&& hasArrSupport == that.hasArrSupport
- && Objects.equals(frameRateCategoryRate, that.frameRateCategoryRate);
+ && Objects.equals(frameRateCategoryRate, that.frameRateCategoryRate)
+ && Arrays.equals(supportedRefreshRates, that.supportedRefreshRates);
}
@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId,
renderFrameRate, activeColorMode, hdrCapabilities, hasArrSupport,
- frameRateCategoryRate);
+ frameRateCategoryRate, Arrays.hashCode(supportedRefreshRates));
}
}
@@ -2711,6 +2845,33 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Retrieve the maximum number of concurrent picture profiles allowed across all displays.
+ *
+ * A picture profile is assigned to a layer via:
+ * <ul>
+ * <li>Picture processing via {@link MediaCodec.KEY_PICTURE_PROFILE}</li>
+ * <li>Picture processing via {@link SurfaceControl.Transaction#setPictureProfileHandle}
+ * </li>
+ * </ul>
+ *
+ * If the maximum number is exceeded, some layers will not receive profiles based on:
+ * <ul>
+ * <li>The content priority assigned by the app</li>
+ * <li>The system-determined priority of the app owning the layer</li>
+ * </ul>
+ *
+ * @see MediaCodec.KEY_PICTURE_PROFILE
+ * @see SurfaceControl.Transaction#setPictureProfileHandle
+ * @see SurfaceControl.Transaction#setContentPriority
+ *
+ * @hide
+ */
+ @IntRange(from = 0)
+ public static int getMaxPictureProfiles() {
+ return nativeGetMaxPictureProfiles();
+ }
+
+ /**
* Interface to handle request to
* {@link SurfaceControl.Transaction#addTransactionCommittedListener(Executor, TransactionCommittedListener)}
*/
@@ -4444,14 +4605,96 @@ public final class SurfaceControl implements Parcelable {
return this;
}
- /** @hide */
+ /**
+ * Sets the Luts for the layer.
+ *
+ * <p> The function also allows to clear previously applied lut(s). To do this,
+ * set the displayluts to be either {@code nullptr} or
+ * an empty {@link android.hardware.DisplayLuts} instance.
+ *
+ * @param sc The SurfaceControl to update
+ *
+ * @param displayLuts The selected Lut(s)
+ *
+ * @return this
+ * @see DisplayLuts
+ */
+ @FlaggedApi(android.hardware.flags.Flags.FLAG_LUTS_API)
public @NonNull Transaction setLuts(@NonNull SurfaceControl sc,
- @NonNull DisplayLuts displayLuts) {
+ @Nullable DisplayLuts displayLuts) {
+ checkPreconditions(sc);
+ if (displayLuts != null && displayLuts.valid()) {
+ nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(),
+ displayLuts.getOffsets(), displayLuts.getLutDimensions(),
+ displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys());
+ } else {
+ nativeSetLuts(mNativeObject, sc.mNativeObject, null, null, null, null, null);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the desired picture profile handle for a layer.
+ * <p>
+ * A handle, retrieved from {@link MediaQualityManager#getProfileHandles}, which
+ * refers a set of parameters that are used to configure picture processing that is applied
+ * to all subsequent buffers to enhance the quality of their contents (e.g. gamma, color
+ * temperature, hue, saturation, etc.).
+ * <p>
+ * Setting a handle does not guarantee access to limited picture processing. The content
+ * priority for the as well as the prominance of app to the current user experience plays a
+ * role in which layer(s) get access to the limited picture processing resources. A maximum
+ * number of {@link MediaQualityManager.getMaxPictureProfiles} can be applied at any given
+ * point in time.
+ *
+ * @param sc The SurfaceControl of the layer that should be updated
+ * @param handle The picture profile handle which refers to the set of desired parameters
+ *
+ * @see MediaQualityManager#getMaxPictureProfiles
+ * @see MediaQualityManager#getProfileHandles
+ * @see MediaCodec.KEY_PICTURE_PROFILE
+ * @see SurfaceControl.Transaction#setContentPriority
+ *
+ * @hide
+ */
+ @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
+ @SystemApi
+ public @NonNull Transaction setPictureProfileHandle(@NonNull SurfaceControl sc,
+ @NonNull PictureProfileHandle handle) {
checkPreconditions(sc);
- nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(),
- displayLuts.getOffsets(), displayLuts.getLutDimensions(),
- displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys());
+ nativeSetPictureProfileId(mNativeObject, sc.mNativeObject, handle.getId());
+ return this;
+ }
+
+ /**
+ * Sets the importance the layer's contents has to the app's user experience.
+ * <p>
+ * When a two layers within the same app are competing for a limited rendering resource,
+ * the priority will determine which layer gets access to the resource. The lower the
+ * priority, the more likely the layer will get access to the resource.
+ * <p>
+ * Resources managed by this priority:
+ * <ul>
+ * <li>Picture processing via {@link MediaCodec.KEY_PICTURE_PROFILE}</li>
+ * <li>Picture processing via {@link SurfaceControl.Transaction#setPictureProfileHandle}
+ * </li>
+ * </ul>
+ *
+ * @param sc The SurfaceControl of the layer that should be updated
+ * @param priority The priority this layer should have with respect to other layers in the
+ * app. The default priority is zero.
+ *
+ * @see MediaQualityManager#getMaxPictureProfiles
+ * @see MediaCodec.KEY_PICTURE_PROFILE
+ * @see SurfaceControl.Transaction#setPictureProfileHandle
+ */
+ @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
+ public @NonNull Transaction setContentPriority(@NonNull SurfaceControl sc,
+ int priority) {
+ checkPreconditions(sc);
+
+ nativeSetContentPriority(mNativeObject, sc.mNativeObject, priority);
return this;
}
@@ -4867,6 +5110,23 @@ public final class SurfaceControl implements Parcelable {
nativeSetDesiredPresentTimeNanos(mNativeObject, desiredPresentTimeNanos);
return this;
}
+
+ /**
+ * Specifies that the SurfaceControl is a buffer producer that should recover from buffer
+ * stuffing, meaning that the SurfaceControl is a ViewRootImpl.
+ *
+ * @hide
+ */
+ @NonNull
+ public Transaction setRecoverableFromBufferStuffing(@NonNull SurfaceControl sc) {
+ if (bufferStuffingRecovery()) {
+ checkPreconditions(sc);
+ nativeSetFlags(mNativeObject, sc.mNativeObject, RECOVERABLE_FROM_BUFFER_STUFFING,
+ RECOVERABLE_FROM_BUFFER_STUFFING);
+ }
+ return this;
+ }
+
/**
* Writes the transaction to parcel, clearing the transaction as if it had been applied so
* it can be used to store future transactions. It's the responsibility of the parcel
diff --git a/core/java/android/view/SurfaceControlActivePicture.java b/core/java/android/view/SurfaceControlActivePicture.java
new file mode 100644
index 000000000000..569159d73d2d
--- /dev/null
+++ b/core/java/android/view/SurfaceControlActivePicture.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 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.view;
+
+import android.annotation.NonNull;
+import android.media.quality.PictureProfileHandle;
+
+/**
+ * A record of a visible layer that is using picture processing.
+ * @hide
+ */
+public class SurfaceControlActivePicture {
+ private final int mLayerId;
+ private final int mOwnerUid;
+ private final @NonNull PictureProfileHandle mPictureProfileHandle;
+
+ /**
+ * Create a record of a visible layer that is using picture processing.
+ *
+ * @param layerId the layer that is using picture processing
+ * @param ownerUid the UID of the package that owns the layer
+ * @param handle the handle for the picture profile that configured the processing
+ */
+ private SurfaceControlActivePicture(int layerId, int ownerUid, PictureProfileHandle handle) {
+ mLayerId = layerId;
+ mOwnerUid = ownerUid;
+ mPictureProfileHandle = handle;
+ }
+
+ /** The layer that is using picture processing. */
+ public int getLayerId() {
+ return mLayerId;
+ }
+
+ /** The UID of the package that owns the layer using picture processing. */
+ public int getOwnerUid() {
+ return mOwnerUid;
+ }
+
+ /** A handle that indicates which picture profile has configured the picture processing. */
+ public @NonNull PictureProfileHandle getPictureProfileHandle() {
+ return mPictureProfileHandle;
+ }
+}
diff --git a/core/java/android/view/SurfaceControlActivePictureListener.java b/core/java/android/view/SurfaceControlActivePictureListener.java
new file mode 100644
index 000000000000..d7c53748784f
--- /dev/null
+++ b/core/java/android/view/SurfaceControlActivePictureListener.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2024 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.view;
+
+import android.annotation.RequiresPermission;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Allows for the monitoring of visible layers that are using picture processing.
+ * @hide
+ */
+public abstract class SurfaceControlActivePictureListener {
+ private static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ SurfaceControlActivePictureListener.class.getClassLoader(),
+ nativeGetDestructor());
+
+ /**
+ * Callback when there are changes in the visible layers that are using picture processing.
+ *
+ * @param activePictures The visible layers that are using picture processing.
+ */
+ public abstract void onActivePicturesChanged(SurfaceControlActivePicture[] activePictures);
+
+ /**
+ * Start listening to changes in active pictures.
+ */
+ @RequiresPermission(android.Manifest.permission.OBSERVE_PICTURE_PROFILES)
+ public void startListening() {
+ synchronized (this) {
+ long nativePtr = nativeMakeAndStartListening();
+ mDestructor = sRegistry.registerNativeAllocation(this, nativePtr);
+ }
+ }
+
+ /**
+ * Stop listening to changes in active pictures.
+ */
+ @RequiresPermission(android.Manifest.permission.OBSERVE_PICTURE_PROFILES)
+ public void stopListening() {
+ final Runnable destructor;
+ synchronized (this) {
+ destructor = mDestructor;
+ }
+ if (destructor != null) {
+ destructor.run();
+ }
+ }
+
+ private native long nativeMakeAndStartListening();
+ private static native long nativeGetDestructor();
+
+ private Runnable mDestructor;
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4df7649e1c9b..b0051cefb21b 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -932,7 +932,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
/**
* Sets the desired amount of HDR headroom to be used when HDR content is presented on this
- * SurfaceView.
+ * SurfaceView. This is expressed as the ratio of maximum HDR white point over the SDR
+ * white point, not as absolute nits.
*
* <p>By default the system will choose an amount of HDR headroom that is appropriate
* for the underlying device capabilities & bit-depth of the panel. However, for some types
@@ -946,6 +947,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
* See {@link Display#getHdrSdrRatio()} for more information as well as how to query the
* current value.</p>
*
+ * <p>Note: This API operates independently of both the
+ * {@link Window#setColorMode Widow color mode} and the
+ * {@link Window#setDesiredHdrHeadroom Window desiredHdrHeadroom}</p>
+ *
* @param desiredHeadroom The amount of HDR headroom that is desired. Must be >= 1.0 (no HDR)
* and <= 10,000.0. Passing 0.0 will reset to the default, automatically
* chosen value.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c71bf4be308c..049189f8af8d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16754,9 +16754,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_DETERMINED;
}
}
- final boolean processForRotaryScrollHaptics =
- isRotaryEncoderEvent && ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_ENABLED) != 0);
- if (processForRotaryScrollHaptics) {
+ if (isRotaryEncoderEvent && ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_ENABLED) != 0)) {
mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT;
mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT;
}
@@ -16773,7 +16771,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Process scroll haptics after `onGenericMotionEvent`, since that's where scrolling usually
// happens. Some views may return false from `onGenericMotionEvent` even if they have done
// scrolling, so disregard the return value when processing for scroll haptics.
- if (processForRotaryScrollHaptics) {
+ // Check for `PFLAG4_ROTARY_HAPTICS_ENABLED` again, because the View implementation may
+ // call `disableRotaryScrollFeedback` in `onGenericMotionEvent`, which could change the
+ // value of `PFLAG4_ROTARY_HAPTICS_ENABLED`.
+ if (isRotaryEncoderEvent && ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_ENABLED) != 0)) {
if ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT) != 0) {
doRotaryProgressForScrollHaptics(event);
} else {
@@ -18716,7 +18717,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private HapticScrollFeedbackProvider getScrollFeedbackProvider() {
if (mScrollFeedbackProvider == null) {
mScrollFeedbackProvider = new HapticScrollFeedbackProvider(this,
- ViewConfiguration.get(mContext), /* disabledIfViewPlaysScrollHaptics= */ false);
+ ViewConfiguration.get(mContext), /* isFromView= */ true);
}
return mScrollFeedbackProvider;
}
@@ -18746,6 +18747,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Disables the rotary scroll feedback implementation of the View class.
+ *
+ * <p>Note that this does NOT disable all rotary scroll feedback; it just disables the logic
+ * implemented within the View class. The child implementation of the View may implement its own
+ * rotary scroll feedback logic or use {@link ScrollFeedbackProvider} to generate rotary scroll
+ * feedback.
+ */
+ void disableRotaryScrollFeedback() {
+ // Force set PFLAG4_ROTARY_HAPTICS_DETERMINED to avoid recalculating
+ // PFLAG4_ROTARY_HAPTICS_ENABLED under any circumstance.
+ mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_DETERMINED;
+ mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_ENABLED;
+ }
+
+ /**
* This is called in response to an internal scroll in this view (i.e., the
* view scrolled its own contents). This is typically as a result of
* {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 75d2da1b70e4..b6e114b3a3ca 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -110,7 +110,6 @@ import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_B
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
-import static android.view.accessibility.Flags.fixMergedContentChangeEventV2;
import static android.view.accessibility.Flags.forceInvertColor;
import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
import static android.view.flags.Flags.addSchandleToVriSurface;
@@ -140,6 +139,8 @@ import android.accessibilityservice.AccessibilityService;
import android.animation.AnimationHandler;
import android.animation.LayoutTransition;
import android.annotation.AnyThread;
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
@@ -1250,7 +1251,6 @@ public final class ViewRootImpl implements ViewParent,
mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName);
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
- mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
@@ -2514,7 +2514,16 @@ public final class ViewRootImpl implements ViewParent,
@VisibleForTesting
public void notifyInsetsAnimationRunningStateChanged(boolean running) {
if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.instant(Trace.TRACE_TAG_VIEW,
+ TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)",
+ Boolean.toString(running)));
+ }
mInsetsAnimationRunning = running;
+ try {
+ mWindowSession.notifyInsetsAnimationRunningStateChanged(mWindow, running);
+ } catch (RemoteException e) {
+ }
}
}
@@ -2758,6 +2767,9 @@ public final class ViewRootImpl implements ViewParent,
// Only call transferFrom if the surface has changed to prevent inc the generation ID and
// causing EGL resources to be recreated.
mSurface.transferFrom(blastSurface);
+
+ // Since the SurfaceControl is a VRI, indicate that it can recover from buffer stuffing.
+ mTransaction.setRecoverableFromBufferStuffing(mSurfaceControl).applyAsyncUnsafe();
}
private void setBoundsLayerCrop(Transaction t) {
@@ -8864,11 +8876,6 @@ public final class ViewRootImpl implements ViewParent,
SyntheticTouchNavigationHandler() {
super(true);
- int gestureDetectorVelocityStrategy =
- android.companion.virtual.flags.Flags
- .impulseVelocityStrategyForTouchNavigation()
- ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE
- : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT;
mGestureDetector = new GestureDetector(mContext,
new GestureDetector.OnGestureListener() {
@Override
@@ -8908,7 +8915,7 @@ public final class ViewRootImpl implements ViewParent,
}
},
/* handler= */ null,
- gestureDetectorVelocityStrategy);
+ VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE);
}
public void process(MotionEvent event) {
@@ -11897,6 +11904,20 @@ public final class ViewRootImpl implements ViewParent,
}
/**
+ * {@inheritDoc}
+ */
+ @NonNull
+ @Override
+ @FlaggedApi(com.android.window.flags.Flags.FLAG_JANK_API)
+ public SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull SurfaceControl.OnJankDataListener listener) {
+ SurfaceControl.OnJankDataListener wrapped = (data) ->
+ executor.execute(() -> listener.onJankDataAvailable(data));
+ return mSurfaceControl.addOnJankDataListener(wrapped);
+ }
+
+ /**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
*/
@@ -12267,31 +12288,20 @@ public final class ViewRootImpl implements ViewParent,
}
if (mSource != null) {
- if (fixMergedContentChangeEventV2()) {
- View newSource = getCommonPredecessor(mSource, source);
- if (newSource != null) {
- newSource = newSource.getSelfOrParentImportantForA11y();
- }
- if (newSource == null) {
- // If there is no common predecessor, then mSource points to
- // a removed view, hence in this case always prefer the source.
- newSource = source;
- }
-
- mChangeTypes |= changeType;
- if (mSource != newSource) {
- mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
- mSource = newSource;
- }
- } else {
+ View newSource = getCommonPredecessor(mSource, source);
+ if (newSource != null) {
+ newSource = newSource.getSelfOrParentImportantForA11y();
+ }
+ if (newSource == null) {
// If there is no common predecessor, then mSource points to
// a removed view, hence in this case always prefer the source.
- View predecessor = getCommonPredecessor(mSource, source);
- if (predecessor != null) {
- predecessor = predecessor.getSelfOrParentImportantForA11y();
- }
- mSource = (predecessor != null) ? predecessor : source;
- mChangeTypes |= changeType;
+ newSource = source;
+ }
+
+ mChangeTypes |= changeType;
+ if (mSource != newSource) {
+ mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
+ mSource = newSource;
}
final int performingAction = mAccessibilityManager.getPerformingAction();
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 1af9387e6fbd..1be7f4849f07 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -17,6 +17,7 @@
package android.view;
import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
@@ -79,27 +80,24 @@ public abstract class ViewStructure {
* Key used for writing the type of the view that generated the virtual structure of its
* children.
*
- * For example, if the virtual structure is generated by a webview, the value would be
+ * <p>For example, if the virtual structure is generated by a webview, the value would be
* "WebView". If the virtual structure is generated by a compose view, then the value would be
* "ComposeView". The value is of type String.
*
- * This value is added to mainly help with debugging purpose.
- *
- * @hide
+ * <p>This value is added to mainly help with debugging purpose.
*/
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE =
"android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE";
-
/**
* Key used for specifying the version of the view that generated the virtual structure for
* itself and its children
*
- * For example, if the virtual structure is generated by a webview of version "104.0.5112.69",
- * then the value should be "104.0.5112.69"
- *
- * @hide
+ * <p>For example, if the virtual structure is generated by a webview of version
+ * "104.0.5112.69", then the value should be "104.0.5112.69"
*/
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER =
"android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER";
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 381006c8a21b..39533344173b 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1334,6 +1334,9 @@ public abstract class Window {
* <p>The requested color mode is not guaranteed to be honored. Please refer to
* {@link #getColorMode()} for more information.</p>
*
+ * <p>Note: This does not impact SurfaceViews or SurfaceControls, as those have their own
+ * independent color mode and HDR parameters.</p>
+ *
* @see #getColorMode()
* @see Display#isWideColorGamut()
* @see Configuration#isScreenWideColorGamut()
@@ -1361,6 +1364,9 @@ public abstract class Window {
* See {@link Display#getHdrSdrRatio()} for more information as well as how to query the
* current value.</p>
*
+ * <p>Note: This does not impact SurfaceViews or SurfaceControls, as those have their own
+ * independent desired HDR headroom and HDR capabilities.</p>
+ *
* @param desiredHeadroom The amount of HDR headroom that is desired. Must be >= 1.0 (no HDR)
* and <= 10,000.0. Passing 0.0 will reset to the default, automatically
* chosen value.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index b4b0687eb498..1e8cad61381c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1426,8 +1426,9 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE";
/**
- * Activity-level {@link android.content.pm.PackageManager.Property PackageManager.Property}
- * that specifies whether this activity can declare or request
+ * Application or Activity level
+ * {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * that specifies whether this package or activity can declare or request
* {@link android.R.attr#screenOrientation fixed orientation},
* {@link android.R.attr#minAspectRatio max aspect ratio},
* {@link android.R.attr#maxAspectRatio min aspect ratio}
@@ -1438,6 +1439,13 @@ public interface WindowManager extends ViewManager {
*
* <p><b>Syntax:</b>
* <pre>
+ * &lt;application&gt;
+ * &lt;property
+ * android:name="android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"
+ * android:value="false"/&gt;
+ * &lt;/application&gt;
+ * </pre>or
+ * <pre>
* &lt;activity&gt;
* &lt;property
* android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
@@ -1446,7 +1454,7 @@ public interface WindowManager extends ViewManager {
* </pre>
* @hide
*/
- // TODO(b/357141415): Make this public API.
+ // TODO(b/357141415): Remove this from sdk 37
String PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY =
"android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY";
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 65e993049979..72a595d95ec2 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -679,6 +679,11 @@ public class WindowlessWindowManager implements IWindowSession {
@NonNull ImeTracker.Token statsToken) {
}
+ @Override
+ public void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running) {
+ // NO-OP
+ }
+
void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder();
IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder();
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 0204517e869a..df0c5a34e992 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -6551,15 +6551,23 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Range type: indeterminate.
*
+ * When using this type, the {@code min}, {@code max}, and {@code current} values used to
+ * construct an instance may be ignored.
+ *
+ * @see #INDETERMINATE
+ */
+ @FlaggedApi(Flags.FLAG_INDETERMINATE_RANGE_INFO)
+ public static final int RANGE_TYPE_INDETERMINATE = 3;
+
+ /**
* A {@link RangeInfo} type used to represent a node which may typically expose range
* information but is presently in an indeterminate state, such as a {@link
* android.widget.ProgressBar} representing a loading operation of unknown duration.
- * When using this type, the {@code min}, {@code max}, and {@code current} values used to
- * construct an instance may be ignored. It is recommended to use {@code Float.NaN} for
- * these values.
*/
+ @NonNull
@FlaggedApi(Flags.FLAG_INDETERMINATE_RANGE_INFO)
- public static final int RANGE_TYPE_INDETERMINATE = 3;
+ public static final RangeInfo INDETERMINATE = new RangeInfo(RANGE_TYPE_INDETERMINATE, 0.0f,
+ 0.0f, 0.0f);
private int mType;
private float mMin;
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index 8a006fa5b509..e60fc3ae6b47 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -99,16 +99,6 @@ flag {
flag {
namespace: "accessibility"
- name: "fix_merged_content_change_event_v2"
- description: "Fixes event type and source of content change event merged in ViewRootImpl"
- bug: "277305460"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "accessibility"
name: "flash_notification_system_api"
is_exported: true
description: "Makes flash notification APIs as system APIs for calling from mainline module"
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 6b608582c1dd..bd277784c1d3 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -15,6 +15,9 @@
*/
package android.view.autofill;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -111,12 +114,43 @@ public final class AutofillId implements Parcelable {
return new AutofillId(flags, id.mViewId, virtualChildId, NO_SESSION);
}
- /** @hide */
+ /**
+ * Returns the assigned unique identifier of this AutofillID.
+ *
+ * See @link{android.view.View#getAutofillId()} for more information on
+ * how this is generated for native Views.
+ */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
public int getViewId() {
return mViewId;
}
/**
+ * Gets the virtual id. This is set if the view is a virtual view, most commonly set if the View
+ * is of {@link android.webkit.WebView}.
+ */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+ public int getAutofillVirtualId() {
+ return mVirtualIntId;
+ }
+
+ /** Checks whether this AutofillId represents a virtual view. */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+ public boolean isVirtual() {
+ return !isNonVirtual();
+ }
+
+ /**
+ * Checks if this node is generate as part of a {@link android.app.assist.AssistStructure}. This
+ * will usually return true if it should be used by an autofill service provider, and false
+ * otherwise.
+ */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+ public boolean isInAutofillSession() {
+ return hasSession();
+ }
+
+ /**
* Gets the virtual child id.
*
* <p>Should only be used on subsystems where such id is represented by an {@code int}
@@ -181,7 +215,12 @@ public final class AutofillId implements Parcelable {
return (mFlags & FLAG_HAS_SESSION) != 0;
}
- /** @hide */
+ /**
+ * Used to get the Session identifier associated with this AutofillId.
+ *
+ * @return a non-zero integer if {@link #isInAutofillSession()} returns true
+ */
+ @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
public int getSessionId() {
return mSessionId;
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 1a45939f65b6..52c5af8889ec 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -25,12 +25,14 @@ import static android.service.autofill.FillRequest.FLAG_SCREEN_HAS_CREDMAN_FIELD
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
+import static android.service.autofill.Flags.FLAG_FILL_DIALOG_IMPROVEMENTS;
import static android.view.ContentInfo.SOURCE_AUTOFILL;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1607,7 +1609,12 @@ public final class AutofillManager {
* the virtual view in the host view.
*
* @throws IllegalArgumentException if the {@code infos} was empty
+ *
+ * @deprecated This function will not do anything. Showing fill dialog is now fully controlled
+ * by the framework and the autofill provider.
*/
+ @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS)
+ @Deprecated
public void notifyVirtualViewsReady(
@NonNull View view, @NonNull SparseArray<VirtualViewFillInfo> infos) {
Objects.requireNonNull(infos);
@@ -4034,8 +4041,13 @@ public final class AutofillManager {
* receiving a focus event. The autofill suggestions shown will include content for
* related views as well.
* @return {@code true} if the autofill dialog is being shown
+ *
+ * @deprecated This function will not do anything. Showing fill dialog is now fully controlled
+ * by the framework and the autofill provider.
*/
// TODO(b/210926084): Consider whether to include the one-time show logic within this method.
+ @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS)
+ @Deprecated
public boolean showAutofillDialog(@NonNull View view) {
Objects.requireNonNull(view);
if (shouldShowAutofillDialog(view, view.getAutofillId())) {
@@ -4073,7 +4085,12 @@ public final class AutofillManager {
* suggestions.
* @param virtualId id identifying the virtual view inside the host view.
* @return {@code true} if the autofill dialog is being shown
+ *
+ * @deprecated This function will not do anything. Showing fill dialog is now fully controlled
+ * by the framework and the autofill provider.
*/
+ @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS)
+ @Deprecated
public boolean showAutofillDialog(@NonNull View view, int virtualId) {
Objects.requireNonNull(view);
if (shouldShowAutofillDialog(view, getAutofillId(view, virtualId))) {
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index 658aa29a3cc6..ebda4d472b0d 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -23,3 +23,10 @@ flag {
bug: "331830899"
is_fixed_read_only: true
}
+
+flag {
+ namespace: "wear_frameworks"
+ name: "dynamic_view_rotary_haptics_configuration"
+ description: "Whether ScrollFeedbackProvider dynamically disables View-based rotary haptics."
+ bug: "377998870"
+}
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 1b86f96d7eb7..3b6343e7c4ae 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -132,4 +132,12 @@ flag {
description: "Use refactored round scrollbar."
bug: "333417898"
is_fixed_read_only: true
+}
+
+flag {
+ name: "buffer_stuffing_recovery"
+ namespace: "window_surfaces"
+ description: "Recover from buffer stuffing when SurfaceFlinger misses a frame"
+ bug: "294922229"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index fb3e0831fdc9..afe195c48b01 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -24,6 +24,7 @@ import static android.view.inputmethod.EditorInfoProto.PACKAGE_NAME;
import static android.view.inputmethod.EditorInfoProto.PRIVATE_IME_OPTIONS;
import static android.view.inputmethod.EditorInfoProto.TARGET_INPUT_METHOD_USER_ID;
import static android.view.inputmethod.Flags.FLAG_EDITORINFO_HANDWRITING_ENABLED;
+import static android.view.inputmethod.Flags.FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -470,12 +471,10 @@ public class EditorInfo implements InputType, Parcelable {
public String packageName;
/**
- * Autofill Id for the field that's currently on focus.
- *
- * <p> Marked as hide since it's only used by framework.</p>
- * @hide
+ * Autofill Id for the field that's currently on focus. See link {@link AutofillId} for more
+ * details. It is set by {@link View#getAutofillId()}
*/
- public AutofillId autofillId;
+ private AutofillId autofillId;
/**
* Identifier for the editor's field. This is optional, and may be
@@ -524,7 +523,6 @@ public class EditorInfo implements InputType, Parcelable {
@Nullable
public LocaleList hintLocales = null;
-
/**
* List of acceptable MIME types for
* {@link InputConnection#commitContent(InputContentInfo, int, Bundle)}.
@@ -759,6 +757,30 @@ public class EditorInfo implements InputType, Parcelable {
return mIsStylusHandwritingEnabled;
}
+ private boolean mWritingToolsEnabled = true;
+
+ /**
+ * Returns {@code true} when an {@code Editor} has writing tools enabled.
+ * {@code true} by default for all editors. Toolkits can optionally disable them where not
+ * relevant e.g. passwords, number input, etc.
+ * @see #setWritingToolsEnabled(boolean)
+ */
+ @FlaggedApi(Flags.FLAG_WRITING_TOOLS)
+ public boolean isWritingToolsEnabled() {
+ return mWritingToolsEnabled;
+ }
+
+ /**
+ * Set {@code false} if {@code Editor} opts-out of writing tools, that enable IMEs to replace
+ * text with generative AI text.
+ * @param enabled set {@code true} to enabled or {@code false to disable} support.
+ * @see #isWritingToolsEnabled()
+ */
+ @FlaggedApi(Flags.FLAG_WRITING_TOOLS)
+ public void setWritingToolsEnabled(boolean enabled) {
+ mWritingToolsEnabled = enabled;
+ }
+
/**
* If not {@code null}, this editor needs to talk to IMEs that run for the specified user, no
* matter what user ID the calling process has.
@@ -1200,6 +1222,28 @@ public class EditorInfo implements InputType, Parcelable {
}
/**
+ * Returns the {@link AutofillId} of the view that this {@link EditorInfo} is associated with.
+ * The value is filled in with the result of {@link android.view.View#getAutofillId()
+ * View.getAutofillId()} on the view that is being edited.
+ *
+ * Note: For virtual view(e.g. Compose or Webview), default behavior is the autofillId is the id
+ * of the container view, unless the virtual view provider sets the virtual id when the
+ * InputMethodManager calls {@link android.view.View#onCreateInputConnection()} on the container
+ * view.
+ */
+ @FlaggedApi(FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO)
+ @Nullable
+ public AutofillId getAutofillId() {
+ return autofillId;
+ }
+
+ /** Sets the {@link AutofillId} of the view that this {@link EditorInfo} is associated with. */
+ @FlaggedApi(FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO)
+ public void setAutofillId(@Nullable AutofillId autofillId) {
+ this.autofillId = autofillId;
+ }
+
+ /**
* Export the state of {@link EditorInfo} into a protocol buffer output stream.
*
* @param proto Stream to write the state to
@@ -1255,6 +1299,7 @@ public class EditorInfo implements InputType, Parcelable {
+ InputMethodDebug.handwritingGestureTypeFlagsToString(
mSupportedHandwritingGesturePreviewTypes));
pw.println(prefix + "isStylusHandwritingEnabled=" + mIsStylusHandwritingEnabled);
+ pw.println(prefix + "writingToolsEnabled=" + mWritingToolsEnabled);
pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes));
if (targetInputMethodUser != null) {
pw.println(prefix + "targetInputMethodUserId=" + targetInputMethodUser.getIdentifier());
@@ -1335,6 +1380,7 @@ public class EditorInfo implements InputType, Parcelable {
}
dest.writeStringArray(contentMimeTypes);
UserHandle.writeToParcel(targetInputMethodUser, dest);
+ dest.writeBoolean(mWritingToolsEnabled);
}
/**
@@ -1375,6 +1421,7 @@ public class EditorInfo implements InputType, Parcelable {
res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
res.contentMimeTypes = source.readStringArray();
res.targetInputMethodUser = UserHandle.readFromParcel(source);
+ res.mWritingToolsEnabled = source.readBoolean();
return res;
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 73f9d9fc23dc..6303c7637a59 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2471,6 +2471,11 @@ public final class InputMethodManager {
return;
}
+ if (Flags.refactorInsetsController()) {
+ showSoftInput(rootView, statsToken, flags, resultReceiver, reason);
+ return;
+ }
+
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
// Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
@@ -5174,7 +5179,7 @@ public final class InputMethodManager {
// system can verify the consistency between the uid of this process and package name passed
// from here. See comment of Context#getOpPackageName() for details.
editorInfo.packageName = servedView.getContext().getOpPackageName();
- editorInfo.autofillId = servedView.getAutofillId();
+ editorInfo.setAutofillId(servedView.getAutofillId());
editorInfo.fieldId = servedView.getId();
final InputConnection ic = servedView.onCreateInputConnection(editorInfo);
if (DEBUG) Log.v(TAG, "Starting input: editorInfo=" + editorInfo + " ic=" + ic);
@@ -5183,7 +5188,7 @@ public final class InputMethodManager {
// This ensures that even disconnected EditorInfos have well-defined attributes,
// making them consistently and straightforwardly comparable.
if (ic == null) {
- editorInfo.autofillId = AutofillId.NO_AUTOFILL_ID;
+ editorInfo.setAutofillId(AutofillId.NO_AUTOFILL_ID);
editorInfo.fieldId = 0;
}
return new Pair<>(ic, editorInfo);
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index 4f48cb684e8c..1806a8369d01 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.annotation.NonNull;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.Bundle;
@@ -125,6 +126,23 @@ public interface InputMethodSession {
public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback);
/**
+ * Received by the IME before dispatch to {@link InputMethodService#onKeyDown(int, KeyEvent)}
+ * to let the system know if the {@link KeyEvent} needs to be verified that it originated from
+ * the system. {@link KeyEvent}s may originate from outside of the system and any sensitive keys
+ * should be marked for verification. One example of this could be using key shortcuts for
+ * switching to another IME.
+ *
+ * @param event the event that may need verification.
+ * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch,
+ * {@code false} otherwise.
+ *
+ * @hide
+ */
+ default boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) {
+ return false;
+ }
+
+ /**
* This method is called when there is a track ball event.
*
* <p>
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index edd9d6cff799..73abc472be6d 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -165,4 +165,30 @@ flag {
description: "Writing tools API"
bug: "373788889"
is_fixed_read_only: true
-} \ No newline at end of file
+}
+
+flag {
+ name: "public_autofill_id_in_editorinfo"
+ is_exported: true
+ namespace: "input_method"
+ description: "Guarding public API autofillId in editor info"
+ bug: "342672560"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "adaptive_handwriting_bounds"
+ is_exported: true
+ namespace: "input_method"
+ description: "Feature flag for adaptively increasing handwriting bounds."
+ bug: "350047836"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "verify_key_event"
+ namespace: "input_method"
+ description: "Verify KeyEvents in IME"
+ bug: "331730488"
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java
index 98c00ac7f6f7..0bf6380eb904 100644
--- a/core/java/android/widget/Button.java
+++ b/core/java/android/widget/Button.java
@@ -16,17 +16,22 @@
package android.widget;
-import static android.view.flags.Flags.enableArrowIconOnHoverWhenClickable;
import static android.view.flags.Flags.FLAG_ENABLE_ARROW_ICON_ON_HOVER_WHEN_CLICKABLE;
+import static android.view.flags.Flags.enableArrowIconOnHoverWhenClickable;
import android.annotation.FlaggedApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.util.AttributeSet;
import android.view.InputDevice;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.widget.RemoteViews.RemoteView;
+import android.widget.flags.Flags;
/**
* A user interface element the user can tap or click to perform an action.
@@ -88,6 +93,12 @@ import android.widget.RemoteViews.RemoteView;
@RemoteView
public class Button extends TextView {
+ @ChangeId
+ @EnabledSince(targetSdkVersion = 36)
+ private static final long WEAR_MATERIAL3_BUTTON = 376561342L;
+
+ private static Boolean sUseWearMaterial3Style;
+
/**
* Simple constructor to use when creating a button from code.
*
@@ -118,7 +129,18 @@ public class Button extends TextView {
* @see android.view.View#View(Context, AttributeSet)
*/
public Button(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.buttonStyle);
+ // Starting sdk 36+, wear devices will use a specific material3
+ // design. The new design will be applied when all of following conditions are met:
+ // 1. app target sdk is 36 or above.
+ // 2. feature flag rolled-out.
+ // 3. device is a watch.
+ // getButtonDefaultStyleAttr and getButtonDefaultStyleRes works together to alter the UI
+ // while considering the conditions above.
+ // Their results are mutual exclusive. i.e. when conditions above are all true,
+ // getButtonDefaultStyleRes returns non-zero value(new wear material3), abd
+ // getButtonDefaultStyleAttr returns 0. Otherwise, getButtonDefaultStyleAttr returns system
+ // attr com.android.internal.R.attr.buttonStyle and getButtonDefaultStyleRes returns 0.
+ this(context, attrs, getButtonDefaultStyleAttr(context), getButtonDefaultStyleRes());
}
/**
@@ -189,4 +211,24 @@ public class Button extends TextView {
}
return super.onResolvePointerIcon(event, pointerIndex);
}
+
+ private static int getButtonDefaultStyleAttr(Context context) {
+ sUseWearMaterial3Style = useWearMaterial3Style(context);
+ if (sUseWearMaterial3Style) {
+ return 0;
+ }
+ return com.android.internal.R.attr.buttonStyle;
+ }
+
+ private static int getButtonDefaultStyleRes() {
+ if (sUseWearMaterial3Style != null && sUseWearMaterial3Style) {
+ return com.android.internal.R.style.Widget_DeviceDefault_Button_WearMaterial3;
+ }
+ return 0;
+ }
+
+ private static boolean useWearMaterial3Style(Context context) {
+ return Flags.useWearMaterial3Ui() && CompatChanges.isChangeEnabled(WEAR_MATERIAL3_BUTTON)
+ && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 9b6311f35d17..80d39d1f9a1c 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -20,6 +20,7 @@ import static android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL;
import static android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO;
import static android.appwidget.flags.Flags.drawDataParcel;
import static android.appwidget.flags.Flags.remoteAdapterConversion;
+import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
import static android.util.proto.ProtoInputStream.NO_MORE_FIELDS;
import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR;
@@ -54,6 +55,10 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentSender;
import android.content.ServiceConnection;
+import android.content.om.FabricatedOverlay;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.ColorStateList;
@@ -1559,6 +1564,16 @@ public class RemoteViews implements Parcelable, Filter {
final Context context = ActivityThread.currentApplication();
final CompletableFuture<RemoteCollectionItems> result = new CompletableFuture<>();
+ String contextPackageName = context.getPackageName();
+ ComponentName intentComponent = intent.getComponent();
+ if (contextPackageName != null
+ && intentComponent != null
+ && (!contextPackageName.equals(intentComponent.getPackageName()))) {
+ // We shouldn't allow for connections to other packages
+ result.complete(new RemoteCollectionItems.Builder().build());
+ return result;
+ }
+
context.bindService(intent, Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE),
result.defaultExecutor(), new ServiceConnection() {
@Override
@@ -8468,8 +8483,11 @@ public class RemoteViews implements Parcelable, Filter {
}
try {
LoadedApk.checkAndUpdateApkPaths(mApplication);
- return context.createApplicationContext(mApplication,
+ Context applicationContext = context.createApplicationContext(mApplication,
Context.CONTEXT_RESTRICTED);
+ // Get the correct apk paths while maintaining the current context's configuration.
+ return applicationContext.createConfigurationContext(
+ context.getResources().getConfiguration());
} catch (NameNotFoundException e) {
Log.e(LOG_TAG, "Package name " + mApplication.packageName + " not found");
}
@@ -8547,8 +8565,6 @@ public class RemoteViews implements Parcelable, Filter {
/**
* Object allowing the modification of a context to overload the system's dynamic colors.
*
- * Only colors from {@link android.R.color#system_accent1_0} to
- * {@link android.R.color#system_neutral2_1000} can be overloaded.
* @hide
*/
public static final class ColorResources {
@@ -8559,6 +8575,9 @@ public class RemoteViews implements Parcelable, Filter {
// Size, in bytes, of an entry in the array of colors in an ARSC file.
private static final int ARSC_ENTRY_SIZE = 16;
+ private static final String OVERLAY_NAME = "remote_views_color_resources";
+ private static final String OVERLAY_TARGET_PACKAGE_NAME = "android";
+
private final ResourcesLoader mLoader;
private final SparseIntArray mColorMapping;
@@ -8629,7 +8648,11 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
- * Adds a resource loader for theme colors to the given context.
+ * Adds a resource loader for theme colors to the given context. The loader is created
+ * based on resource files created at build time.
+ *
+ * <p>Only colors from {@link android.R.color#system_accent1_0} to
+ * {@link android.R.color#system_error_1000} can be overloaded.</p>
*
* @param context Context of the view hosting the widget.
* @param colorMapping Mapping of resources to color values.
@@ -8667,6 +8690,57 @@ public class RemoteViews implements Parcelable, Filter {
}
return null;
}
+
+ /**
+ * Adds a resource loader for theme colors to the given context. The loader is created
+ * using fabricated runtime resource overlay (FRRO).
+ *
+ * <p>The created class can overlay any color resources, private or public, at runtime.</p>
+ *
+ * @param context Context of the view hosting the widget.
+ * @param colorMapping Mapping of resources to color values.
+ *
+ * @hide
+ */
+ @Nullable
+ public static ColorResources createWithOverlay(Context context,
+ SparseIntArray colorMapping) {
+ try {
+ String owningPackage = context.getPackageName();
+ FabricatedOverlay overlay = new FabricatedOverlay.Builder(owningPackage,
+ OVERLAY_NAME, OVERLAY_TARGET_PACKAGE_NAME).build();
+
+ for (int i = 0; i < colorMapping.size(); i++) {
+ overlay.setResourceValue(
+ context.getResources().getResourceName(colorMapping.keyAt(i)),
+ TYPE_INT_COLOR_ARGB8, colorMapping.valueAt(i), null);
+ }
+ OverlayManager overlayManager = context.getSystemService(OverlayManager.class);
+ OverlayManagerTransaction.Builder transaction =
+ new OverlayManagerTransaction.Builder()
+ .registerFabricatedOverlay(overlay)
+ .setSelfTargeting(true);
+ overlayManager.commit(transaction.build());
+
+ OverlayInfo overlayInfo =
+ overlayManager.getOverlayInfosForTarget(OVERLAY_TARGET_PACKAGE_NAME)
+ .stream()
+ .filter(info -> TextUtils.equals(info.overlayName, OVERLAY_NAME)
+ && TextUtils.equals(info.packageName, owningPackage))
+ .findFirst()
+ .orElse(null);
+ if (overlayInfo == null) {
+ Log.e(LOG_TAG, "Failed to get overlay info ", new Throwable());
+ return null;
+ }
+ ResourcesLoader colorsLoader = new ResourcesLoader();
+ colorsLoader.addProvider(ResourcesProvider.loadOverlay(overlayInfo));
+ return new ColorResources(colorsLoader, colorMapping.clone());
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Failed to add theme color overlay into loader", e);
+ }
+ return null;
+ }
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d7750bd412a3..cb70466fcd81 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -106,6 +106,7 @@ import android.os.Parcelable;
import android.os.ParcelableParcel;
import android.os.Process;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.BoringLayout;
@@ -9229,174 +9230,179 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
protected void onDraw(Canvas canvas) {
- restartMarqueeIfNeeded();
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onDraw");
+ try {
+ restartMarqueeIfNeeded();
- // Draw the background for this view
- super.onDraw(canvas);
-
- final int compoundPaddingLeft = getCompoundPaddingLeft();
- final int compoundPaddingTop = getCompoundPaddingTop();
- final int compoundPaddingRight = getCompoundPaddingRight();
- final int compoundPaddingBottom = getCompoundPaddingBottom();
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
- final int right = mRight;
- final int left = mLeft;
- final int bottom = mBottom;
- final int top = mTop;
- final boolean isLayoutRtl = isLayoutRtl();
- final int offset = getHorizontalOffsetForDrawables();
- final int leftOffset = isLayoutRtl ? 0 : offset;
- final int rightOffset = isLayoutRtl ? offset : 0;
+ // Draw the background for this view
+ super.onDraw(canvas);
- final Drawables dr = mDrawables;
- if (dr != null) {
- /*
- * Compound, not extended, because the icon is not clipped
- * if the text height is smaller.
- */
+ final int compoundPaddingLeft = getCompoundPaddingLeft();
+ final int compoundPaddingTop = getCompoundPaddingTop();
+ final int compoundPaddingRight = getCompoundPaddingRight();
+ final int compoundPaddingBottom = getCompoundPaddingBottom();
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
+ final int right = mRight;
+ final int left = mLeft;
+ final int bottom = mBottom;
+ final int top = mTop;
+ final boolean isLayoutRtl = isLayoutRtl();
+ final int offset = getHorizontalOffsetForDrawables();
+ final int leftOffset = isLayoutRtl ? 0 : offset;
+ final int rightOffset = isLayoutRtl ? offset : 0;
- int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
- int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ /*
+ * Compound, not extended, because the icon is not clipped
+ * if the text height is smaller.
+ */
- // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
- // Make sure to update invalidateDrawable() when changing this code.
- if (dr.mShowing[Drawables.LEFT] != null) {
- canvas.save();
- canvas.translate(scrollX + mPaddingLeft + leftOffset,
- scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2);
- dr.mShowing[Drawables.LEFT].draw(canvas);
- canvas.restore();
- }
+ int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
+ int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
+
+ // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+ // Make sure to update invalidateDrawable() when changing this code.
+ if (dr.mShowing[Drawables.LEFT] != null) {
+ canvas.save();
+ canvas.translate(scrollX + mPaddingLeft + leftOffset,
+ scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2);
+ dr.mShowing[Drawables.LEFT].draw(canvas);
+ canvas.restore();
+ }
- // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
- // Make sure to update invalidateDrawable() when changing this code.
- if (dr.mShowing[Drawables.RIGHT] != null) {
- canvas.save();
- canvas.translate(scrollX + right - left - mPaddingRight
- - dr.mDrawableSizeRight - rightOffset,
- scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
- dr.mShowing[Drawables.RIGHT].draw(canvas);
- canvas.restore();
- }
+ // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+ // Make sure to update invalidateDrawable() when changing this code.
+ if (dr.mShowing[Drawables.RIGHT] != null) {
+ canvas.save();
+ canvas.translate(scrollX + right - left - mPaddingRight
+ - dr.mDrawableSizeRight - rightOffset,
+ scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
+ dr.mShowing[Drawables.RIGHT].draw(canvas);
+ canvas.restore();
+ }
- // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
- // Make sure to update invalidateDrawable() when changing this code.
- if (dr.mShowing[Drawables.TOP] != null) {
- canvas.save();
- canvas.translate(scrollX + compoundPaddingLeft
- + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
- dr.mShowing[Drawables.TOP].draw(canvas);
- canvas.restore();
- }
+ // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+ // Make sure to update invalidateDrawable() when changing this code.
+ if (dr.mShowing[Drawables.TOP] != null) {
+ canvas.save();
+ canvas.translate(scrollX + compoundPaddingLeft
+ + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
+ dr.mShowing[Drawables.TOP].draw(canvas);
+ canvas.restore();
+ }
- // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
- // Make sure to update invalidateDrawable() when changing this code.
- if (dr.mShowing[Drawables.BOTTOM] != null) {
- canvas.save();
- canvas.translate(scrollX + compoundPaddingLeft
- + (hspace - dr.mDrawableWidthBottom) / 2,
- scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
- dr.mShowing[Drawables.BOTTOM].draw(canvas);
- canvas.restore();
+ // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+ // Make sure to update invalidateDrawable() when changing this code.
+ if (dr.mShowing[Drawables.BOTTOM] != null) {
+ canvas.save();
+ canvas.translate(scrollX + compoundPaddingLeft
+ + (hspace - dr.mDrawableWidthBottom) / 2,
+ scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
+ dr.mShowing[Drawables.BOTTOM].draw(canvas);
+ canvas.restore();
+ }
}
- }
- int color = mCurTextColor;
+ int color = mCurTextColor;
- if (mLayout == null) {
- assumeLayout();
- }
+ if (mLayout == null) {
+ assumeLayout();
+ }
+
+ Layout layout = mLayout;
- Layout layout = mLayout;
+ if (mHint != null && !mHideHint && mText.length() == 0) {
+ if (mHintTextColor != null) {
+ color = mCurHintTextColor;
+ }
- if (mHint != null && !mHideHint && mText.length() == 0) {
- if (mHintTextColor != null) {
- color = mCurHintTextColor;
+ layout = mHintLayout;
}
- layout = mHintLayout;
- }
+ mTextPaint.setColor(color);
+ mTextPaint.drawableState = getDrawableState();
- mTextPaint.setColor(color);
- mTextPaint.drawableState = getDrawableState();
+ canvas.save();
+ /* Would be faster if we didn't have to do this. Can we chop the
+ (displayable) text so that we don't need to do this ever?
+ */
- canvas.save();
- /* Would be faster if we didn't have to do this. Can we chop the
- (displayable) text so that we don't need to do this ever?
- */
+ int extendedPaddingTop = getExtendedPaddingTop();
+ int extendedPaddingBottom = getExtendedPaddingBottom();
- int extendedPaddingTop = getExtendedPaddingTop();
- int extendedPaddingBottom = getExtendedPaddingBottom();
+ final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
+ final int maxScrollY = mLayout.getHeight() - vspace;
- final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
- final int maxScrollY = mLayout.getHeight() - vspace;
+ float clipLeft = compoundPaddingLeft + scrollX;
+ float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
+ float clipRight = right - left - getCompoundPaddingRight() + scrollX;
+ float clipBottom = bottom - top + scrollY
+ - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
- float clipLeft = compoundPaddingLeft + scrollX;
- float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
- float clipRight = right - left - getCompoundPaddingRight() + scrollX;
- float clipBottom = bottom - top + scrollY
- - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
+ if (mShadowRadius != 0) {
+ clipLeft += Math.min(0, mShadowDx - mShadowRadius);
+ clipRight += Math.max(0, mShadowDx + mShadowRadius);
- if (mShadowRadius != 0) {
- clipLeft += Math.min(0, mShadowDx - mShadowRadius);
- clipRight += Math.max(0, mShadowDx + mShadowRadius);
+ clipTop += Math.min(0, mShadowDy - mShadowRadius);
+ clipBottom += Math.max(0, mShadowDy + mShadowRadius);
+ }
- clipTop += Math.min(0, mShadowDy - mShadowRadius);
- clipBottom += Math.max(0, mShadowDy + mShadowRadius);
- }
+ canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);
- canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);
+ int voffsetText = 0;
+ int voffsetCursor = 0;
- int voffsetText = 0;
- int voffsetCursor = 0;
+ // translate in by our padding
+ /* shortcircuit calling getVerticaOffset() */
+ if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
+ voffsetText = getVerticalOffset(false);
+ voffsetCursor = getVerticalOffset(true);
+ }
+ canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
+
+ final int layoutDirection = getLayoutDirection();
+ final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
+ if (isMarqueeFadeEnabled()) {
+ if (!mSingleLine && getLineCount() == 1 && canMarquee()
+ && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
+ final int width = mRight - mLeft;
+ final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
+ final float dx = mLayout.getLineRight(0) - (width - padding);
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+ }
- // translate in by our padding
- /* shortcircuit calling getVerticaOffset() */
- if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
- voffsetText = getVerticalOffset(false);
- voffsetCursor = getVerticalOffset(true);
- }
- canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
-
- final int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
- if (isMarqueeFadeEnabled()) {
- if (!mSingleLine && getLineCount() == 1 && canMarquee()
- && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
- final int width = mRight - mLeft;
- final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
- final float dx = mLayout.getLineRight(0) - (width - padding);
- canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+ if (mMarquee != null && mMarquee.isRunning()) {
+ final float dx = -mMarquee.getScroll();
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+ }
}
- if (mMarquee != null && mMarquee.isRunning()) {
- final float dx = -mMarquee.getScroll();
- canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
- }
- }
+ final int cursorOffsetVertical = voffsetCursor - voffsetText;
- final int cursorOffsetVertical = voffsetCursor - voffsetText;
+ maybeUpdateHighlightPaths();
+ // If there is a gesture preview highlight, then the selection or cursor is not drawn.
+ Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath();
+ if (mEditor != null) {
+ mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight,
+ mHighlightPaint, cursorOffsetVertical);
+ } else {
+ layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+ cursorOffsetVertical);
+ }
- maybeUpdateHighlightPaths();
- // If there is a gesture preview highlight, then the selection or cursor is not drawn.
- Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath();
- if (mEditor != null) {
- mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight,
- mHighlightPaint, cursorOffsetVertical);
- } else {
- layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
- cursorOffsetVertical);
- }
+ if (mMarquee != null && mMarquee.shouldDrawGhost()) {
+ final float dx = mMarquee.getGhostOffset();
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+ layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+ cursorOffsetVertical);
+ }
- if (mMarquee != null && mMarquee.shouldDrawGhost()) {
- final float dx = mMarquee.getGhostOffset();
- canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
- layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
- cursorOffsetVertical);
+ canvas.restore();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
-
- canvas.restore();
}
@Override
@@ -11254,192 +11260,201 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
- int width;
- int height;
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onMeasure");
+ try {
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- BoringLayout.Metrics boring = UNKNOWN_BORING;
- BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
+ int width;
+ int height;
- if (mTextDir == null) {
- mTextDir = getTextDirectionHeuristic();
- }
+ BoringLayout.Metrics boring = UNKNOWN_BORING;
+ BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
- int des = -1;
- boolean fromexisting = false;
- final float widthLimit = (widthMode == MeasureSpec.AT_MOST)
- ? (float) widthSize : Float.MAX_VALUE;
-
- if (widthMode == MeasureSpec.EXACTLY) {
- // Parent has told us how big to be. So be it.
- width = widthSize;
- } else {
- if (mLayout != null && mEllipsize == null) {
- des = desired(mLayout, mUseBoundsForWidth);
+ if (mTextDir == null) {
+ mTextDir = getTextDirectionHeuristic();
}
- if (des < 0) {
- boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
- isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
- mBoring);
- if (boring != null) {
- mBoring = boring;
- }
- } else {
- fromexisting = true;
- }
+ int des = -1;
+ boolean fromexisting = false;
+ final float widthLimit = (widthMode == MeasureSpec.AT_MOST)
+ ? (float) widthSize : Float.MAX_VALUE;
- if (boring == null || boring == UNKNOWN_BORING) {
- if (des < 0) {
- des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0,
- mTransformed.length(), mTextPaint, mTextDir, widthLimit,
- mUseBoundsForWidth));
- }
- width = des;
+ if (widthMode == MeasureSpec.EXACTLY) {
+ // Parent has told us how big to be. So be it.
+ width = widthSize;
} else {
- if (mUseBoundsForWidth) {
- RectF bbox = boring.getDrawingBoundingBox();
- float rightMax = Math.max(bbox.right, boring.width);
- float leftMin = Math.min(bbox.left, 0);
- width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin));
- } else {
- width = boring.width;
+ if (mLayout != null && mEllipsize == null) {
+ des = desired(mLayout, mUseBoundsForWidth);
}
- }
-
- final Drawables dr = mDrawables;
- if (dr != null) {
- width = Math.max(width, dr.mDrawableWidthTop);
- width = Math.max(width, dr.mDrawableWidthBottom);
- }
-
- if (mHint != null) {
- int hintDes = -1;
- int hintWidth;
- if (mHintLayout != null && mEllipsize == null) {
- hintDes = desired(mHintLayout, mUseBoundsForWidth);
- }
-
- if (hintDes < 0) {
- hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
+ if (des < 0) {
+ boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
- mHintBoring);
- if (hintBoring != null) {
- mHintBoring = hintBoring;
+ mBoring);
+ if (boring != null) {
+ mBoring = boring;
}
+ } else {
+ fromexisting = true;
}
- if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
- if (hintDes < 0) {
- hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0,
- mHint.length(), mTextPaint, mTextDir, widthLimit,
+ if (boring == null || boring == UNKNOWN_BORING) {
+ if (des < 0) {
+ des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0,
+ mTransformed.length(), mTextPaint, mTextDir, widthLimit,
mUseBoundsForWidth));
}
- hintWidth = hintDes;
+ width = des;
} else {
- hintWidth = hintBoring.width;
+ if (mUseBoundsForWidth) {
+ RectF bbox = boring.getDrawingBoundingBox();
+ float rightMax = Math.max(bbox.right, boring.width);
+ float leftMin = Math.min(bbox.left, 0);
+ width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin));
+ } else {
+ width = boring.width;
+ }
}
- if (hintWidth > width) {
- width = hintWidth;
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ width = Math.max(width, dr.mDrawableWidthTop);
+ width = Math.max(width, dr.mDrawableWidthBottom);
}
- }
- width += getCompoundPaddingLeft() + getCompoundPaddingRight();
+ if (mHint != null) {
+ int hintDes = -1;
+ int hintWidth;
- if (mMaxWidthMode == EMS) {
- width = Math.min(width, mMaxWidth * getLineHeight());
- } else {
- width = Math.min(width, mMaxWidth);
- }
+ if (mHintLayout != null && mEllipsize == null) {
+ hintDes = desired(mHintLayout, mUseBoundsForWidth);
+ }
- if (mMinWidthMode == EMS) {
- width = Math.max(width, mMinWidth * getLineHeight());
- } else {
- width = Math.max(width, mMinWidth);
- }
+ if (hintDes < 0) {
+ hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
+ isFallbackLineSpacingForBoringLayout(),
+ getResolvedMinimumFontMetrics(),
+ mHintBoring);
+ if (hintBoring != null) {
+ mHintBoring = hintBoring;
+ }
+ }
- // Check against our minimum width
- width = Math.max(width, getSuggestedMinimumWidth());
+ if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
+ if (hintDes < 0) {
+ hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0,
+ mHint.length(), mTextPaint, mTextDir, widthLimit,
+ mUseBoundsForWidth));
+ }
+ hintWidth = hintDes;
+ } else {
+ hintWidth = hintBoring.width;
+ }
- if (widthMode == MeasureSpec.AT_MOST) {
- width = Math.min(widthSize, width);
- }
- }
+ if (hintWidth > width) {
+ width = hintWidth;
+ }
+ }
- int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight();
- int unpaddedWidth = want;
+ width += getCompoundPaddingLeft() + getCompoundPaddingRight();
- if (mHorizontallyScrolling) want = VERY_WIDE;
+ if (mMaxWidthMode == EMS) {
+ width = Math.min(width, mMaxWidth * getLineHeight());
+ } else {
+ width = Math.min(width, mMaxWidth);
+ }
- int hintWant = want;
- int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth();
+ if (mMinWidthMode == EMS) {
+ width = Math.max(width, mMinWidth * getLineHeight());
+ } else {
+ width = Math.max(width, mMinWidth);
+ }
- if (mLayout == null) {
- makeNewLayout(want, hintWant, boring, hintBoring,
- width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
- } else {
- final boolean layoutChanged = (mLayout.getWidth() != want) || (hintWidth != hintWant)
- || (mLayout.getEllipsizedWidth()
- != width - getCompoundPaddingLeft() - getCompoundPaddingRight());
+ // Check against our minimum width
+ width = Math.max(width, getSuggestedMinimumWidth());
+
+ if (widthMode == MeasureSpec.AT_MOST) {
+ width = Math.min(widthSize, width);
+ }
+ }
- final boolean widthChanged = (mHint == null) && (mEllipsize == null)
- && (want > mLayout.getWidth())
- && (mLayout instanceof BoringLayout
- || (fromexisting && des >= 0 && des <= want));
+ int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight();
+ int unpaddedWidth = want;
- final boolean maximumChanged = (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum);
+ if (mHorizontallyScrolling) want = VERY_WIDE;
- if (layoutChanged || maximumChanged) {
- if (!maximumChanged && widthChanged) {
- mLayout.increaseWidthTo(want);
+ int hintWant = want;
+ int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth();
+
+ if (mLayout == null) {
+ makeNewLayout(want, hintWant, boring, hintBoring,
+ width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
+ } else {
+ final boolean layoutChanged =
+ (mLayout.getWidth() != want) || (hintWidth != hintWant)
+ || (mLayout.getEllipsizedWidth()
+ != width - getCompoundPaddingLeft() - getCompoundPaddingRight());
+
+ final boolean widthChanged = (mHint == null) && (mEllipsize == null)
+ && (want > mLayout.getWidth())
+ && (mLayout instanceof BoringLayout
+ || (fromexisting && des >= 0 && des <= want));
+
+ final boolean maximumChanged =
+ (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum);
+
+ if (layoutChanged || maximumChanged) {
+ if (!maximumChanged && widthChanged) {
+ mLayout.increaseWidthTo(want);
+ } else {
+ makeNewLayout(want, hintWant, boring, hintBoring,
+ width - getCompoundPaddingLeft() - getCompoundPaddingRight(),
+ false);
+ }
} else {
- makeNewLayout(want, hintWant, boring, hintBoring,
- width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
+ // Nothing has changed
}
- } else {
- // Nothing has changed
}
- }
- if (heightMode == MeasureSpec.EXACTLY) {
- // Parent has told us how big to be. So be it.
- height = heightSize;
- mDesiredHeightAtMeasure = -1;
- } else {
- int desired = getDesiredHeight();
+ if (heightMode == MeasureSpec.EXACTLY) {
+ // Parent has told us how big to be. So be it.
+ height = heightSize;
+ mDesiredHeightAtMeasure = -1;
+ } else {
+ int desired = getDesiredHeight();
- height = desired;
- mDesiredHeightAtMeasure = desired;
+ height = desired;
+ mDesiredHeightAtMeasure = desired;
- if (heightMode == MeasureSpec.AT_MOST) {
- height = Math.min(desired, heightSize);
+ if (heightMode == MeasureSpec.AT_MOST) {
+ height = Math.min(desired, heightSize);
+ }
}
- }
- int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
- if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
- unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
- }
+ int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
+ if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
+ unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
+ }
- /*
- * We didn't let makeNewLayout() register to bring the cursor into view,
- * so do it here if there is any possibility that it is needed.
- */
- if (mMovement != null
- || mLayout.getWidth() > unpaddedWidth
- || mLayout.getHeight() > unpaddedHeight) {
- registerForPreDraw();
- } else {
- scrollTo(0, 0);
- }
+ /*
+ * We didn't let makeNewLayout() register to bring the cursor into view,
+ * so do it here if there is any possibility that it is needed.
+ */
+ if (mMovement != null
+ || mLayout.getWidth() > unpaddedWidth
+ || mLayout.getHeight() > unpaddedHeight) {
+ registerForPreDraw();
+ } else {
+ scrollTo(0, 0);
+ }
- setMeasuredDimension(width, height);
+ setMeasuredDimension(width, height);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
}
/**
diff --git a/core/java/android/widget/flags/flags.aconfig b/core/java/android/widget/flags/flags.aconfig
index f0ed83be8f1e..d9dc36ccc8c3 100644
--- a/core/java/android/widget/flags/flags.aconfig
+++ b/core/java/android/widget/flags/flags.aconfig
@@ -8,4 +8,12 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
-} \ No newline at end of file
+}
+
+flag {
+ name: "use_wear_material3_ui"
+ namespace: "wear_frameworks"
+ description: "Whether enable material3 style for wear frameworks' widgets."
+ is_exported: true
+ bug: "369480667"
+}
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index 16eb43700aef..b535effd393a 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -67,7 +67,6 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL
.setStiffness(SpringForce.STIFFNESS_MEDIUM)
.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY);
private final SpringForce mButtonSpringForce = new SpringForce()
- .setStiffness(500)
.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY);
private final DynamicAnimation.OnAnimationEndListener mOnAnimationEndListener =
(animation, canceled, value, velocity) -> {
@@ -157,6 +156,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL
/* frameTime */ System.nanoTime() / TimeUtils.NANOS_PER_MS);
if (predictiveBackSwipeEdgeNoneApi()) {
if (event.getSwipeEdge() == EDGE_NONE) {
+ mButtonSpringForce.setStiffness(SpringForce.STIFFNESS_LOW);
mSpring.setSpring(mButtonSpringForce);
mSpring.animateToFinalPosition(SCALE_FACTOR);
} else {
@@ -228,6 +228,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL
* @param finishCallback the callback to be invoked when the progress is reach to 0.
*/
public void onBackCancelled(@NonNull Runnable finishCallback) {
+ mButtonSpringForce.setStiffness(SpringForce.STIFFNESS_MEDIUM);
mBackCancelledFinishRunnable = finishCallback;
mSpring.addEndListener(mOnAnimationEndListener);
mSpring.animateToFinalPosition(0);
diff --git a/core/java/android/window/IBackAnimationHandoffHandler.aidl b/core/java/android/window/IBackAnimationHandoffHandler.aidl
new file mode 100644
index 000000000000..577948dd0abc
--- /dev/null
+++ b/core/java/android/window/IBackAnimationHandoffHandler.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 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.os.Bundle;
+import android.view.RemoteAnimationTarget;
+import android.window.BackMotionEvent;
+import android.window.WindowAnimationState;
+
+
+/**
+ * Interface that allows an {@link OnBackInvokedCallback} object to hand off an animation to another
+ * handler.
+ *
+ * @hide
+ */
+oneway interface IBackAnimationHandoffHandler {
+ /**
+ * Triggers a handoff of the animation of the given targets and their associated states.
+ * Important: since this is a one-way method, the caller must first make sure that the animation
+ * can indeed be taken over.
+ */
+ oneway void handOffAnimation(in RemoteAnimationTarget[] targets,
+ in WindowAnimationState[] states);
+}
diff --git a/core/java/android/window/IOnBackInvokedCallback.aidl b/core/java/android/window/IOnBackInvokedCallback.aidl
index e07d4a9fc61b..81ad4b7bd19e 100644
--- a/core/java/android/window/IOnBackInvokedCallback.aidl
+++ b/core/java/android/window/IOnBackInvokedCallback.aidl
@@ -18,6 +18,7 @@
package android.window;
import android.window.BackMotionEvent;
+import android.window.IBackAnimationHandoffHandler;
/**
* Interface that wraps a {@link OnBackInvokedCallback} object, to be stored in window manager
@@ -61,4 +62,9 @@ oneway interface IOnBackInvokedCallback {
* Sets whether the back gesture is past the trigger threshold.
*/
void setTriggerBack(in boolean triggerBack);
+
+ /**
+ * Sets a {@link IBackAnimationHandoffHandler} that can be used to hand off the back animation.
+ */
+ void setHandoffHandler(in IBackAnimationHandoffHandler handoffHandler);
}
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index c67b9cac250b..d478108d928a 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -392,6 +392,11 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc
// no-op
}
+ @Override
+ public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) {
+ // no-op
+ }
+
private void maybeRunOnAnimationCallback(Consumer<OnBackAnimationCallback> block) {
if (mCallback instanceof OnBackAnimationCallback) {
mHandler.post(() -> block.accept((OnBackAnimationCallback) mCallback));
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 0f2dd10d7f47..2c21417fb790 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -49,6 +49,7 @@ import android.content.ComponentName;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
+import android.os.BinderProxy;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -1089,8 +1090,13 @@ public final class TransitionInfo implements Parcelable {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- sb.append('{'); sb.append(mContainer);
- sb.append(" m="); sb.append(modeToString(mMode));
+ sb.append('{');
+ if (mContainer != null && !(mContainer.asBinder() instanceof BinderProxy)) {
+ // Only log the token if it is not a binder proxy and has additional container info
+ sb.append(mContainer);
+ sb.append(" ");
+ }
+ sb.append("m="); sb.append(modeToString(mMode));
sb.append(" f="); sb.append(flagsToString(mFlags));
if (mParent != null) {
sb.append(" p="); sb.append(mParent);
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 3fe63ab17248..a88a17283482 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -1120,8 +1120,8 @@ public final class WindowContainerTransaction implements Parcelable {
@NonNull
public String toString() {
return "WindowContainerTransaction {"
- + " changes = " + mChanges
- + " hops = " + mHierarchyOps
+ + " changes= " + mChanges
+ + " hops= " + mHierarchyOps
+ " errorCallbackToken=" + mErrorCallbackToken
+ " taskFragmentOrganizer=" + mTaskFragmentOrganizer
+ " }";
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 0ea4bb41d3a4..20e3f6b93bd0 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -546,6 +546,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
}
@Override
+ public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) {
+ // no-op
+ }
+
+ @Override
public void onBackProgressed(BackMotionEvent backEvent) {
// This is only called in some special cases such as when activity embedding is active
// or when the activity is letterboxed. Otherwise mProgressAnimator#onBackProgressed is
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 15adc80add01..6e76d8d345b2 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -19,6 +19,8 @@ import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -104,7 +106,7 @@ public class WindowTokenClient extends Binder {
* @param newConfig the updated {@link Configuration}
* @param newDisplayId the updated {@link android.view.Display} ID
*/
- @VisibleForTesting
+ @VisibleForTesting(visibility = PACKAGE)
@MainThread
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
@@ -113,7 +115,7 @@ public class WindowTokenClient extends Binder {
/**
* Posts an {@link #onConfigurationChanged} to the main thread.
*/
- @VisibleForTesting
+ @VisibleForTesting(visibility = PACKAGE)
public void postOnConfigurationChanged(@NonNull Configuration newConfig, int newDisplayId) {
mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig,
newDisplayId, true /* shouldReportConfigChange */).recycleOnUse());
@@ -232,7 +234,7 @@ public class WindowTokenClient extends Binder {
/**
* Called when the attached window is removed from the display.
*/
- @VisibleForTesting
+ @VisibleForTesting(visibility = PACKAGE)
@MainThread
public void onWindowTokenRemoved() {
final Context context = mContextRef.get();
diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java
index abf7bb15b3d8..fa345956ec4d 100644
--- a/core/java/android/window/WindowTokenClientController.java
+++ b/core/java/android/window/WindowTokenClientController.java
@@ -28,7 +28,7 @@ import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -50,9 +50,9 @@ public class WindowTokenClientController {
private final IApplicationThread mAppThread = ActivityThread.currentActivityThread()
.getApplicationThread();
- /** Mapping from a client defined token to the {@link WindowTokenClient} it represents. */
+ /** Attached {@link WindowTokenClient}. */
@GuardedBy("mLock")
- private final ArrayMap<IBinder, WindowTokenClient> mWindowTokenClientMap = new ArrayMap<>();
+ private final ArraySet<WindowTokenClient> mWindowTokenClients = new ArraySet<>();
/** Gets the singleton controller. */
@NonNull
@@ -85,11 +85,15 @@ public class WindowTokenClientController {
/** Gets the {@link WindowContext} instance for the token. */
@Nullable
public Context getWindowContext(@NonNull IBinder clientToken) {
- final WindowTokenClient windowTokenClient;
+ if (!(clientToken instanceof WindowTokenClient windowTokenClient)) {
+ return null;
+ }
synchronized (mLock) {
- windowTokenClient = mWindowTokenClientMap.get(clientToken);
+ if (!mWindowTokenClients.contains(windowTokenClient)) {
+ return null;
+ }
}
- return windowTokenClient != null ? windowTokenClient.getContext() : null;
+ return windowTokenClient.getContext();
}
/**
@@ -126,8 +130,14 @@ public class WindowTokenClientController {
*/
public boolean attachToDisplayContent(@NonNull WindowTokenClient client, int displayId) {
final IWindowManager wms = getWindowManagerService();
- // #createSystemUiContext may call this method before WindowManagerService is initialized.
if (wms == null) {
+ // #createSystemUiContext may call this method before WindowManagerService is
+ // initialized.
+ // Regardless of whether or not it is ready, keep track of the token so that when WMS
+ // is initialized later, the SystemUiContext will start reporting from
+ // DisplayContent#registerSystemUiContext, and WindowTokenClientController can report
+ // the Configuration to the correct client.
+ recordWindowContextToken(client);
return false;
}
final WindowContextInfo info;
@@ -170,12 +180,18 @@ public class WindowTokenClientController {
/** Detaches a {@link WindowTokenClient} from associated WindowContainer if there's one. */
public void detachIfNeeded(@NonNull WindowTokenClient client) {
synchronized (mLock) {
- if (mWindowTokenClientMap.remove(client) == null) {
+ if (!mWindowTokenClients.remove(client)) {
return;
}
}
+ final IWindowManager wms = getWindowManagerService();
+ if (wms == null) {
+ // #createSystemUiContext may call this method before WindowManagerService is
+ // initialized. If it is GC'ed before WMS is initialized, skip calling into WMS.
+ return;
+ }
try {
- getWindowManagerService().detachWindowContext(client);
+ wms.detachWindowContext(client);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -183,9 +199,7 @@ public class WindowTokenClientController {
private void onWindowContextTokenAttached(@NonNull WindowTokenClient client,
@NonNull WindowContextInfo info, boolean shouldReportConfigChange) {
- synchronized (mLock) {
- mWindowTokenClientMap.put(client, client);
- }
+ recordWindowContextToken(client);
if (shouldReportConfigChange) {
// Should trigger an #onConfigurationChanged callback to the WindowContext. Post the
// dispatch in the next loop to prevent the callback from being dispatched before
@@ -199,10 +213,16 @@ public class WindowTokenClientController {
}
}
+ private void recordWindowContextToken(@NonNull WindowTokenClient client) {
+ synchronized (mLock) {
+ mWindowTokenClients.add(client);
+ }
+ }
+
/** Called when receives {@link WindowContextInfoChangeItem}. */
public void onWindowContextInfoChanged(@NonNull IBinder clientToken,
@NonNull WindowContextInfo info) {
- final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken);
+ final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken);
if (windowTokenClient != null) {
windowTokenClient.onConfigurationChanged(info.getConfiguration(), info.getDisplayId());
}
@@ -210,20 +230,23 @@ public class WindowTokenClientController {
/** Called when receives {@link WindowContextWindowRemovalItem}. */
public void onWindowContextWindowRemoved(@NonNull IBinder clientToken) {
- final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken);
+ final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken);
if (windowTokenClient != null) {
windowTokenClient.onWindowTokenRemoved();
}
}
@Nullable
- private WindowTokenClient getWindowTokenClient(@NonNull IBinder clientToken) {
- final WindowTokenClient windowTokenClient;
- synchronized (mLock) {
- windowTokenClient = mWindowTokenClientMap.get(clientToken);
+ private WindowTokenClient getWindowTokenClientIfAttached(@NonNull IBinder clientToken) {
+ if (!(clientToken instanceof WindowTokenClient windowTokenClient)) {
+ Log.e(TAG, "getWindowTokenClient failed for non-window token " + clientToken);
+ return null;
}
- if (windowTokenClient == null) {
- Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken);
+ synchronized (mLock) {
+ if (!mWindowTokenClients.contains(windowTokenClient)) {
+ Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken);
+ return null;
+ }
}
return windowTokenClient;
}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index f474b34ac390..8019e6791cf1 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -242,6 +242,13 @@ flag {
}
flag {
+ name: "enable_desktop_windowing_app_handle_education_integration"
+ namespace: "lse_desktop_experience"
+ description: "Enables desktop windowing app handle education and integrates new APIs"
+ bug: "380272815"
+}
+
+flag {
name: "enable_desktop_windowing_transitions"
namespace: "lse_desktop_experience"
description: "Enables desktop windowing transition & motion polish changes"
@@ -256,6 +263,16 @@ flag {
}
flag {
+ name: "enable_desktop_windowing_enter_transition_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Enables enter desktop windowing transition & motion polish changes"
+ bug: "380224875"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_desktop_windowing_exit_transitions"
namespace: "lse_desktop_experience"
description: "Enables exit desktop windowing transition & motion polish changes"
@@ -263,6 +280,16 @@ flag {
}
flag {
+ name: "enable_desktop_windowing_exit_transitions_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Enables exit desktop windowing transition & motion polish changes"
+ bug: "380224768"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_compat_ui_visibility_status"
namespace: "lse_desktop_experience"
description: "Enables the tracking of the status for compat ui elements."
@@ -346,6 +373,16 @@ flag {
}
flag {
+ name: "enable_desktop_app_launch_alttab_transitions_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Enables custom transitions for alt-tab app launches in Desktop Mode."
+ bug: "380225486"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_desktop_app_launch_transitions"
namespace: "lse_desktop_experience"
description: "Enables custom transitions for app launches in Desktop Mode."
@@ -353,6 +390,16 @@ flag {
}
flag {
+ name: "enable_desktop_app_launch_transitions_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Enables custom transitions for app launches in Desktop Mode."
+ bug: "380224832"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_desktop_system_dialogs_transitions"
namespace: "lse_desktop_experience"
description: "Enables custom transitions for system dialogs in Desktop Mode."
@@ -402,4 +449,11 @@ flag {
namespace: "lse_desktop_experience"
description: "Enables HSUM on desktop mode."
bug: "366397912"
+}
+
+flag {
+ name: "enable_multiple_desktops"
+ namespace: "lse_desktop_experience"
+ description: "Enable multiple desktop sessions for desktop windowing."
+ bug: "379158791"
} \ No newline at end of file
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 392c307de7ba..bb4770768cb1 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -29,14 +29,6 @@ flag {
flag {
namespace: "window_surfaces"
- name: "secure_window_state"
- description: "Move SC secure flag to WindowState level"
- is_fixed_read_only: true
- bug: "308662081"
-}
-
-flag {
- namespace: "window_surfaces"
name: "trusted_presentation_listener_for_window"
is_exported: true
description: "Enable trustedPresentationListener on windows public API"
@@ -97,3 +89,12 @@ flag {
is_fixed_read_only: true
bug: "308662081"
}
+
+flag {
+ name: "jank_api"
+ namespace: "window_surfaces"
+ description: "Adds the jank data listener to AttachedSurfaceControl"
+ is_fixed_read_only: true
+ is_exported: true
+ bug: "293949943"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 4f924a82c9cc..ebbe4830009c 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -200,6 +200,13 @@ flag {
}
flag {
+ name: "show_app_handle_large_screens"
+ namespace: "windowing_frontend"
+ description: "Show the app handle and the app menu also on large screens that don't enable desktop mode"
+ bug: "377689543"
+}
+
+flag {
name: "filter_irrelevant_input_device_change"
namespace: "windowing_frontend"
description: "Recompute display configuration only for necessary input device changes"
@@ -418,8 +425,27 @@ flag {
}
flag {
+ name: "record_task_snapshots_before_shutdown"
+ namespace: "windowing_frontend"
+ description: "Record task snapshots before shutdown"
+ bug: "376821232"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "predictive_back_three_button_nav"
namespace: "systemui"
description: "Enable Predictive Back Animation for 3-button-nav"
bug: "373544911"
}
+
+flag {
+ name: "predictive_back_default_enable_sdk_36"
+ namespace: "systemui"
+ description: "Enable Predictive Back by default with targetSdk>=36"
+ is_fixed_read_only: true
+ bug: "376407910"
+}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 3ec70649294b..2cfc680a3fe8 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -152,7 +152,7 @@ interface IAppOpsService {
in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation);
int checkOperationRawForDevice(int code, int uid, String packageName,
@nullable String attributionTag, int virtualDeviceId);
- int checkOperationForDevice(int code, int uid, String packageName, int virtualDeviceId);
+ int checkOperationForDevice(int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId);
SyncNotedAppOp noteOperationForDevice(int code, int uid, String packageName,
@nullable String attributionTag, int virtualDeviceId,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage);
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index a21a84261ae0..543adac14d36 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -257,7 +257,6 @@ public final class AssociationState {
if (VALIDATE_TIMES) {
if (mActiveDuration > mAssociationState.mTotalActiveDuration) {
RuntimeException ex = new RuntimeException();
- ex.fillInStackTrace();
Slog.w(TAG, "Source act duration " + mActiveDurations
+ " exceeds total " + mAssociationState.mTotalActiveDuration
+ " in procstate " + mActiveProcState + " in source "
@@ -650,7 +649,6 @@ public final class AssociationState {
+ mySrc.mKey.mProcess + " to assoc " + mName);
if ((mySrc.mDuration + otherSrc.mDuration) > mTotalDuration) {
RuntimeException ex = new RuntimeException();
- ex.fillInStackTrace();
Slog.w(TAG, "Source tot duration " + mySrc.mDuration + "+"
+ otherSrc.mDuration
+ (newSrc ? " (new)" : " (old)") + " exceeds total "
@@ -665,7 +663,6 @@ public final class AssociationState {
+ mySrc.mKey.mProcess + " to assoc " + mName);
if ((mySrc.mActiveDuration + otherSrc.mActiveDuration) > mTotalDuration) {
RuntimeException ex = new RuntimeException();
- ex.fillInStackTrace();
Slog.w(TAG, "Source act duration " + mySrc.mActiveDuration + "+"
+ otherSrc.mActiveDuration
+ (newSrc ? " (new)" : " (old)") + " exceeds total "
@@ -746,14 +743,12 @@ public final class AssociationState {
if (VALIDATE_TIMES) {
if (src.mDuration > mTotalDuration) {
RuntimeException ex = new RuntimeException();
- ex.fillInStackTrace();
Slog.w(TAG, "Reading tot duration " + src.mDuration
+ " exceeds total " + mTotalDuration + " in source "
+ src.mKey.mProcess + " to assoc " + mName, ex);
}
if (src.mActiveDurations == null && src.mActiveDuration > mTotalDuration) {
RuntimeException ex = new RuntimeException();
- ex.fillInStackTrace();
Slog.w(TAG, "Reading act duration " + src.mActiveDuration
+ " exceeds total " + mTotalDuration + " in source "
+ src.mKey.mProcess + " to assoc " + mName, ex);
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 0dbdb36977f4..7523a2d24af8 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -538,7 +538,6 @@ public final class ProcessState {
public void incActiveServices(String serviceName) {
if (DEBUG && "".equals(mName)) {
RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
+ " to " + (mNumActiveServices+1), here);
}
@@ -551,7 +550,6 @@ public final class ProcessState {
public void decActiveServices(String serviceName) {
if (DEBUG && "".equals(mName)) {
RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+ " to " + (mNumActiveServices-1), here);
}
@@ -569,7 +567,6 @@ public final class ProcessState {
public void incStartedServices(int memFactor, long now, String serviceName) {
if (false) {
RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
+ " to " + (mNumStartedServices+1), here);
}
@@ -585,7 +582,6 @@ public final class ProcessState {
public void decStartedServices(int memFactor, long now, String serviceName) {
if (false) {
RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+ " to " + (mNumStartedServices-1), here);
}
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 21c7baab4e83..469ab48385da 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -410,4 +410,15 @@ oneway interface IBackupTransport {
* however backups initiated by the framework will call this method to retrieve one.
*/
void getBackupManagerMonitor(in AndroidFuture<IBackupManagerMonitor> resultFuture);
+
+ /**
+ * Ask the transport whether packages that are about to be backed up or restored should not be
+ * put into a restricted mode by the framework and started normally instead. The
+ * {@code resultFuture} should be completed with a subset of the packages passed in, indicating
+ * which packages should NOT be put into restricted mode for the given operation type.
+ *
+ * @param operationType 0 for backup, 1 for restore.
+ */
+ void getPackagesThatShouldNotUseRestrictedMode(in List<String> packageNames, int operationType,
+ in AndroidFuture<List<String>> resultFuture);
}
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 07e178c0ba27..38593b4a2a99 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -19,6 +19,7 @@ package com.android.internal.content.om;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackagePartitions;
+import android.content.res.AssetManager;
import android.os.Build;
import android.os.Trace;
import android.util.ArrayMap;
@@ -533,7 +534,7 @@ public class OverlayConfig {
*/
@NonNull
public String[] createImmutableFrameworkIdmapsInZygote() {
- final String targetPath = "/system/framework/framework-res.apk";
+ final String targetPath = AssetManager.FRAMEWORK_APK_PATH;
final ArrayList<String> idmapPaths = new ArrayList<>();
final ArrayList<IdmapInvocation> idmapInvocations =
getImmutableFrameworkOverlayIdmapInvocations();
diff --git a/core/java/com/android/internal/content/om/OverlayManagerImpl.java b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
index c4624498138d..fa5cf2a396b9 100644
--- a/core/java/com/android/internal/content/om/OverlayManagerImpl.java
+++ b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
@@ -35,6 +35,7 @@ import android.content.om.OverlayManagerTransaction.Request;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.FrameworkParsingPackageUtils;
+import android.content.res.AssetManager;
import android.os.FabricatedOverlayInfo;
import android.os.FabricatedOverlayInternal;
import android.os.FabricatedOverlayInternalEntry;
@@ -60,8 +61,8 @@ import java.util.List;
import java.util.Objects;
/**
- * This class provides the functionalities of registering an overlay, unregistering an overlay, and
- * getting the list of overlays information.
+ * This class provides the functionalities for managing self-targeting overlays, including
+ * registering an overlay, unregistering an overlay, and getting the list of overlays information.
*/
public class OverlayManagerImpl {
private static final String TAG = "OverlayManagerImpl";
@@ -234,14 +235,17 @@ public class OverlayManagerImpl {
Preconditions.checkArgument(!entryList.isEmpty(), "overlay entries shouldn't be empty");
final String overlayName = checkOverlayNameValid(overlayInternal.overlayName);
checkPackageName(overlayInternal.packageName);
- checkPackageName(overlayInternal.targetPackageName);
- Preconditions.checkStringNotEmpty(
- overlayInternal.targetOverlayable,
- "Target overlayable should be neither null nor empty string.");
+ Preconditions.checkStringNotEmpty(overlayInternal.targetPackageName);
final ApplicationInfo applicationInfo = mContext.getApplicationInfo();
- final String targetPackage = Preconditions.checkStringNotEmpty(
- applicationInfo.getBaseCodePath());
+ String targetPackage = null;
+ if (TextUtils.equals(overlayInternal.targetPackageName, "android")) {
+ targetPackage = AssetManager.FRAMEWORK_APK_PATH;
+ } else {
+ targetPackage = Preconditions.checkStringNotEmpty(
+ applicationInfo.getBaseCodePath());
+ }
+
final Path frroPath = mBasePath.resolve(overlayName + FRRO_EXTENSION);
final Path idmapPath = mBasePath.resolve(overlayName + IDMAP_EXTENSION);
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 44c0bd01d545..2834e6883316 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -139,7 +139,7 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
}
static JankInfo createFromSurfaceControlCallback(SurfaceControl.JankData jankStat) {
- return new JankInfo(jankStat.frameVsyncId).update(jankStat);
+ return new JankInfo(jankStat.getVsyncId()).update(jankStat);
}
private JankInfo(long frameVsyncId) {
@@ -154,10 +154,10 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
private JankInfo update(SurfaceControl.JankData jankStat) {
this.surfaceControlCallbackFired = true;
- this.jankType = jankStat.jankType;
- this.refreshRate = DisplayRefreshRate.getRefreshRate(jankStat.frameIntervalNs);
+ this.jankType = jankStat.getJankType();
+ this.refreshRate = DisplayRefreshRate.getRefreshRate(jankStat.getFrameIntervalNanos());
if (Flags.useSfFrameDuration()) {
- this.totalDurationNanos = jankStat.actualAppFrameTimeNs;
+ this.totalDurationNanos = jankStat.getActualAppFrameTimeNanos();
}
return this;
}
@@ -458,14 +458,14 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
}
for (SurfaceControl.JankData jankStat : jankData) {
- if (!isInRange(jankStat.frameVsyncId)) {
+ if (!isInRange(jankStat.getVsyncId())) {
continue;
}
- JankInfo info = findJankInfo(jankStat.frameVsyncId);
+ JankInfo info = findJankInfo(jankStat.getVsyncId());
if (info != null) {
info.update(jankStat);
} else {
- mJankInfos.put((int) jankStat.frameVsyncId,
+ mJankInfos.put((int) jankStat.getVsyncId(),
JankInfo.createFromSurfaceControlCallback(jankStat));
}
}
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 6b6b81f1f805..48d0d6c777de 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -410,6 +410,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
private int mLocaleConfigRes;
private boolean mAllowCrossUidActivitySwitchFromBelow;
+ @Nullable
+ private int[] mAlternateLauncherIconResIds;
+ @Nullable
+ private int[] mAlternateLauncherLabelResIds;
+
private List<AndroidPackageSplit> mSplits;
@NonNull
@@ -874,6 +879,18 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
return adoptPermissions;
}
+ @Nullable
+ @Override
+ public int[] getAlternateLauncherIconResIds() {
+ return mAlternateLauncherIconResIds;
+ }
+
+ @Nullable
+ @Override
+ public int[] getAlternateLauncherLabelResIds() {
+ return mAlternateLauncherLabelResIds;
+ }
+
@NonNull
@Override
public List<ParsedApexSystemService> getApexSystemServices() {
@@ -1888,6 +1905,19 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
+ public PackageImpl setAlternateLauncherIconResIds(@Nullable int[] alternateLauncherIconResIds) {
+ this.mAlternateLauncherIconResIds = alternateLauncherIconResIds;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAlternateLauncherLabelResIds(
+ @Nullable int[] alternateLauncherLabelResIds) {
+ this.mAlternateLauncherLabelResIds = alternateLauncherLabelResIds;
+ return this;
+ }
+
+ @Override
public PackageImpl setTaskReparentingAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value);
}
@@ -3273,6 +3303,8 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
dest.writeLong(this.mBooleans2);
dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
dest.writeInt(this.mIntentMatchingFlags);
+ dest.writeIntArray(this.mAlternateLauncherIconResIds);
+ dest.writeIntArray(this.mAlternateLauncherLabelResIds);
}
private void writeFeatureFlagState(@NonNull Parcel dest) {
@@ -3465,6 +3497,8 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
this.mBooleans2 = in.readLong();
this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
this.mIntentMatchingFlags = in.readInt();
+ this.mAlternateLauncherIconResIds = in.createIntArray();
+ this.mAlternateLauncherLabelResIds = in.createIntArray();
assignDerivedFields();
assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index f4bceb880617..67b985a61455 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -413,6 +413,18 @@ public interface ParsingPackage {
ParsingPackage setOnBackInvokedCallbackEnabled(boolean enableOnBackInvokedCallback);
+ /**
+ * Set the drawable resources id array of the alternate icons that are parsing from the
+ * AndroidManifest file
+ */
+ ParsingPackage setAlternateLauncherIconResIds(int[] alternateLauncherIconResIds);
+
+ /**
+ * Set the string resources id array of the alternate labels that are parsing from the
+ * AndroidManifest file
+ */
+ ParsingPackage setAlternateLauncherLabelResIds(int[] alternateLauncherLabelResIds);
+
@CallSuper
ParsedPackage hideAsParsed();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 5db7b4197658..5fc1276dd9f9 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -46,6 +46,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
@@ -154,6 +155,13 @@ public class ParsingPackageUtils {
private static final String TAG = ParsingUtils.TAG;
+ // It is the maximum length of the typedArray of {@link android.R.attr#alternateIcons}
+ // and {@link android.R.attr#alternateLabels}.
+ private static final int MAXIMUM_LAUNCHER_ALTERNATE_IDS_LENGTH = 500;
+
+ private static final String TYPE_STRING = "string";
+ private static final String TYPE_DRAWABLE = "drawable";
+
public static final boolean DEBUG_JAR = false;
public static final boolean DEBUG_BACKUP = false;
public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
@@ -2021,6 +2029,24 @@ public class ParsingPackageUtils {
pkg.setManageSpaceActivityName(manageSpaceActivityName);
}
+ if (Flags.changeLauncherBadging()) {
+ ParseResult<int[]> result = drawableResIdArray(input, sa, res,
+ R.styleable.AndroidManifestApplication_alternateLauncherIcons,
+ MAXIMUM_LAUNCHER_ALTERNATE_IDS_LENGTH);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ pkg.setAlternateLauncherIconResIds(result.getResult());
+
+ result = stringResIdArray(input, sa, res,
+ R.styleable.AndroidManifestApplication_alternateLauncherLabels,
+ MAXIMUM_LAUNCHER_ALTERNATE_IDS_LENGTH);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ pkg.setAlternateLauncherLabelResIds(result.getResult());
+ }
+
if (pkg.isBackupAllowed()) {
// backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
// and restoreAnyVersion are only relevant if backup is possible for the
@@ -2351,6 +2377,7 @@ public class ParsingPackageUtils {
* Flags are separated by type and by default value. They are sorted alphabetically within each
* section.
*/
+ @SuppressWarnings("AndroidFrameworkCompatChange")
private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) {
int targetSdk = pkg.getTargetSdkVersion();
//@formatter:off
@@ -2388,12 +2415,20 @@ public class ParsingPackageUtils {
.setResetEnabledSettingsOnAppDataCleared(bool(false,
R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
sa))
- .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
// targetSdkVersion gated
.setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
.setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
.setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa))
.setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
+ // CompatChange.isChangeEnabled() can't be used here because this is called during
+ // PackageManagerService initialization. PlatformCompat can't be used because this
+ // code is not guaranteed to be called from the system_server process. Therefore
+ // accessing Build.VERSION_CODES directly and suppressing
+ // AndroidFrameworkCompatChange warning
+ .setOnBackInvokedCallbackEnabled(bool(
+ com.android.window.flags.Flags.predictiveBackDefaultEnableSdk36()
+ && targetSdk > Build.VERSION_CODES.VANILLA_ICE_CREAM,
+ R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
// Ints Default 0
.setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa))
// Ints
@@ -3395,6 +3430,95 @@ public class ParsingPackageUtils {
return sa.getResourceId(attribute, 0);
}
+ /**
+ * Parse the drawable resource id array in the typed array {@code resourceId}
+ * if available. If {@code maxSize} is not zero, only parse and preserve at most
+ * {@code maxSize} ids.
+ */
+ private static ParseResult<int[]> drawableResIdArray(ParseInput input, @NonNull TypedArray sa,
+ @NonNull Resources res, int resourceId, int maxSize) {
+ return resIdArray(input, sa, res, resourceId, TYPE_DRAWABLE, maxSize);
+ }
+
+ /**
+ * Parse the string resource id array in the typed array {@code resourceId}
+ * if available. If {@code maxSize} is not zero, only parse and preserve at most
+ * {@code maxSize} ids.
+ */
+ private static ParseResult<int[]> stringResIdArray(ParseInput input, @NonNull TypedArray sa,
+ @NonNull Resources res, int resourceId, int maxSize) {
+ return resIdArray(input, sa, res, resourceId, TYPE_STRING, maxSize);
+ }
+
+ /**
+ * Parse the resource id array in the typed array {@code resourceId}
+ * if available. If {@code maxSize} is larger than zero, only parse and preserve
+ * at most {@code maxSize} ids that type is matched to the {@code expectedTypeName}.
+ * Because the TypedArray allows mixed types in an array, if {@code expectedTypeName}
+ * is null, it means don't check the type.
+ */
+ private static ParseResult<int[]> resIdArray(ParseInput input, @NonNull TypedArray sa,
+ @NonNull Resources res, int resourceId, @Nullable String expectedTypeName,
+ int maxSize) {
+ if (!sa.hasValue(resourceId)) {
+ return input.success(null);
+ }
+
+ final int typeArrayResId = sa.getResourceId(resourceId, /* defValue= */ 0);
+ if (typeArrayResId == 0) {
+ return input.success(null);
+ }
+
+ // Parse the typedArray
+ try (TypedArray typedArray = res.obtainTypedArray(typeArrayResId)) {
+ final String typedArrayName = res.getResourceName(typeArrayResId);
+ final int length = typedArray.length();
+ if (maxSize > 0 && length > maxSize) {
+ return input.error(TextUtils.formatSimple(
+ "The length of the typedArray (%s) is larger than %d.",
+ typedArrayName, maxSize));
+ }
+ Set<Integer> resourceIdSet = new ArraySet<>();
+ for (int i = 0; i < length; i++) {
+ final int id = typedArray.getResourceId(i, /* defValue= */ 0);
+ // Add the id when the conditions are all matched:
+ // 1. The resource Id is not 0
+ // 2. The type is the expected type
+ // 3. The id is not duplicated
+ if (id == 0) {
+ return input.error(TextUtils.formatSimple(
+ "There is an item that is not a resource id in the typedArray (%s).",
+ typedArrayName));
+ }
+
+ try {
+ if (resourceIdSet.contains(id)) {
+ return input.error(TextUtils.formatSimple(
+ "There is a duplicated resource (%s) in the typedArray (%s).",
+ res.getResourceName(id), typedArrayName));
+ }
+ final String typeName = res.getResourceTypeName(id);
+ if (expectedTypeName != null
+ && !TextUtils.equals(typeName, expectedTypeName)) {
+ return input.error(TextUtils.formatSimple(
+ "There is a resource (%s) in the typedArray (%s) that is not a"
+ + " %s type.", res.getResourceName(id), typedArrayName,
+ expectedTypeName));
+ }
+ } catch (Resources.NotFoundException e) {
+ return input.error(TextUtils.formatSimple(
+ "There is a resource in the typedArray (%s) that is not found in"
+ + " the app resources.", typedArrayName));
+ }
+ resourceIdSet.add(id);
+ }
+ if (resourceIdSet.isEmpty()) {
+ return input.success(null);
+ }
+ return input.success(resourceIdSet.stream().mapToInt(i -> i).toArray());
+ }
+ }
+
private static String string(@StyleableRes int attribute, TypedArray sa) {
return sa.getString(attribute);
}
diff --git a/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl b/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl
new file mode 100644
index 000000000000..cc626f699d43
--- /dev/null
+++ b/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+oneway interface IDeviceLockedStateListener {
+ void onDeviceLockedStateChanged(boolean isDeviceLocked);
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
index 8771cde1de46..be3bbb2d1d94 100644
--- a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
@@ -70,7 +70,7 @@ public class LegacyProtoLogImpl implements IProtoLog {
private final TraceBuffer mBuffer;
private final LegacyProtoLogViewerConfigReader mViewerConfig;
private final Map<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
- private final Runnable mCacheUpdater;
+ private final ProtoLogCacheUpdater mCacheUpdater;
private final int mPerChunkSize;
private boolean mProtoLogEnabled;
@@ -78,14 +78,14 @@ public class LegacyProtoLogImpl implements IProtoLog {
private final Object mProtoLogEnabledLock = new Object();
public LegacyProtoLogImpl(String outputFile, String viewerConfigFilename,
- Runnable cacheUpdater) {
+ ProtoLogCacheUpdater cacheUpdater) {
this(new File(outputFile), viewerConfigFilename, BUFFER_CAPACITY,
new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE, cacheUpdater);
}
public LegacyProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
LegacyProtoLogViewerConfigReader viewerConfig, int perChunkSize,
- Runnable cacheUpdater) {
+ ProtoLogCacheUpdater cacheUpdater) {
mLogFile = file;
mBuffer = new TraceBuffer(bufferCapacity);
mLegacyViewerConfigFilename = viewerConfigFilename;
@@ -298,7 +298,7 @@ public class LegacyProtoLogImpl implements IProtoLog {
}
}
- mCacheUpdater.run();
+ mCacheUpdater.update(this);
return 0;
}
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index a1c987f79304..05a33fe830e8 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -51,7 +51,6 @@ import android.os.ServiceManager;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.text.TextUtils;
-import android.tracing.perfetto.DataSourceParams;
import android.tracing.perfetto.InitArguments;
import android.tracing.perfetto.Producer;
import android.tracing.perfetto.TracingContext;
@@ -86,7 +85,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.stream.Stream;
/**
* A service for the ProtoLog logging system.
@@ -98,10 +96,12 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
@NonNull
protected final ProtoLogDataSource mDataSource;
+ @Nullable
+ protected final IProtoLogConfigurationService mConfigurationService;
@NonNull
protected final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
@NonNull
- private final Runnable mCacheUpdater;
+ private final ProtoLogCacheUpdater mCacheUpdater;
@NonNull
private final int[] mDefaultLogLevelCounts = new int[LogLevel.values().length];
@@ -117,10 +117,10 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
private boolean mLogcatReady = false;
protected PerfettoProtoLogImpl(
- @NonNull Runnable cacheUpdater,
+ @NonNull ProtoLogDataSource dataSource,
+ @NonNull ProtoLogCacheUpdater cacheUpdater,
@NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
- this(cacheUpdater, groups,
- ProtoLogDataSource::new,
+ this(dataSource, cacheUpdater, groups,
android.tracing.Flags.clientSideProtoLogging() ?
IProtoLogConfigurationService.Stub.asInterface(
ServiceManager.getServiceOrThrow(PROTOLOG_CONFIGURATION_SERVICE)
@@ -129,49 +129,62 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
}
protected PerfettoProtoLogImpl(
- @NonNull Runnable cacheUpdater,
+ @NonNull ProtoLogDataSource dataSource,
+ @NonNull ProtoLogCacheUpdater cacheUpdater,
@NonNull IProtoLogGroup[] groups,
- @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
@Nullable IProtoLogConfigurationService configurationService) {
- mDataSource = dataSourceBuilder.build(
- this::onTracingInstanceStart,
- this::onTracingFlush,
- this::onTracingInstanceStop);
- Producer.init(InitArguments.DEFAULTS);
- DataSourceParams params =
- new DataSourceParams.Builder()
- .setBufferExhaustedPolicy(
- DataSourceParams
- .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
- .build();
- // NOTE: Registering that datasource is an async operation, so there may be no data traced
- // for some messages logged right after the construction of this class.
- mDataSource.register(params);
-
- this.mCacheUpdater = cacheUpdater;
+ mDataSource = dataSource;
+ mCacheUpdater = cacheUpdater;
+ mConfigurationService = configurationService;
registerGroupsLocally(groups);
+ }
+
+ /**
+ * To be called to enable the ProtoLogImpl to start tracing to ProtoLog and register with all
+ * the expected ProtoLog components.
+ */
+ public void enable() {
+ Producer.init(InitArguments.DEFAULTS);
if (android.tracing.Flags.clientSideProtoLogging()) {
- Objects.requireNonNull(configurationService,
- "A null ProtoLog Configuration Service was provided!");
+ connectToConfigurationService();
+ }
- try {
- var args = createConfigurationServiceRegisterClientArgs();
+ mDataSource.registerOnStartCallback(this::onTracingInstanceStart);
+ mDataSource.registerOnFlushCallback(this::onTracingFlush);
+ mDataSource.registerOnStopCallback(this::onTracingInstanceStop);
+ }
- final var groupArgs = Stream.of(groups)
- .map(group -> new RegisterClientArgs
- .GroupConfig(group.name(), group.isLogToLogcat()))
- .toArray(RegisterClientArgs.GroupConfig[]::new);
- args.setGroups(groupArgs);
+ private void connectToConfigurationService() {
+ Objects.requireNonNull(mConfigurationService,
+ "A null ProtoLog Configuration Service was provided!");
- configurationService.registerClient(this, args);
- } catch (RemoteException e) {
- throw new RuntimeException("Failed to register ProtoLog client");
- }
+ try {
+ var args = createConfigurationServiceRegisterClientArgs();
+
+ final var groupArgs = mLogGroups.values().stream()
+ .map(group -> new RegisterClientArgs
+ .GroupConfig(group.name(), group.isLogToLogcat()))
+ .toArray(RegisterClientArgs.GroupConfig[]::new);
+ args.setGroups(groupArgs);
+
+ mConfigurationService.registerClient(this, args);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed to register ProtoLog client");
}
}
+ /**
+ * Should be called when we no longer want to use the ProtoLog logger to unlink ourselves from
+ * the datasource and the configuration service to ensure we no longer receive the callback.
+ */
+ public void disable() {
+ mDataSource.unregisterOnStartCallback(this::onTracingInstanceStart);
+ mDataSource.unregisterOnFlushCallback(this::onTracingFlush);
+ mDataSource.unregisterOnStopCallback(this::onTracingInstanceStop);
+ }
+
@NonNull
protected abstract RegisterClientArgs createConfigurationServiceRegisterClientArgs();
@@ -676,19 +689,34 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
return internMap.get(string);
}
+ protected boolean validateGroups(ILogger logger, String[] groups) {
+ for (int i = 0; i < groups.length; i++) {
+ String group = groups[i];
+ IProtoLogGroup g = mLogGroups.get(group);
+ if (g == null) {
+ logger.log("No IProtoLogGroup named " + group);
+ return false;
+ }
+ }
+ return true;
+ }
+
private int setTextLogging(boolean value, ILogger logger, String... groups) {
+ if (!validateGroups(logger, groups)) {
+ return -1;
+ }
+
for (int i = 0; i < groups.length; i++) {
String group = groups[i];
IProtoLogGroup g = mLogGroups.get(group);
if (g != null) {
g.setLogToLogcat(value);
} else {
- logger.log("No IProtoLogGroup named " + group);
- return -1;
+ throw new RuntimeException("No IProtoLogGroup named " + group);
}
}
- mCacheUpdater.run();
+ mCacheUpdater.update(this);
return 0;
}
@@ -731,7 +759,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
}
}
- mCacheUpdater.run();
+ mCacheUpdater.update(this);
this.mTracingInstances.incrementAndGet();
@@ -771,7 +799,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
}
}
- mCacheUpdater.run();
+ mCacheUpdater.update(this);
Log.d(LOG_TAG, "Finished onTracingInstanceStop");
}
diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
index 70d148a311f6..e0a77d2be724 100644
--- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
@@ -42,10 +42,11 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
private final String mViewerConfigFilePath;
public ProcessedPerfettoProtoLogImpl(
+ @NonNull ProtoLogDataSource datasource,
@NonNull String viewerConfigFilePath,
- @NonNull Runnable cacheUpdater,
+ @NonNull ProtoLogCacheUpdater cacheUpdater,
@NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
- this(viewerConfigFilePath, new ViewerConfigInputStreamProvider() {
+ this(datasource, viewerConfigFilePath, new ViewerConfigInputStreamProvider() {
@NonNull
@Override
public AutoClosableProtoInputStream getInputStream() {
@@ -64,11 +65,12 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
@VisibleForTesting
public ProcessedPerfettoProtoLogImpl(
+ @NonNull ProtoLogDataSource datasource,
@NonNull String viewerConfigFilePath,
@NonNull ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
- @NonNull Runnable cacheUpdater,
+ @NonNull ProtoLogCacheUpdater cacheUpdater,
@NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
- super(cacheUpdater, groups);
+ super(datasource, cacheUpdater, groups);
this.mViewerConfigFilePath = viewerConfigFilePath;
@@ -80,15 +82,15 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
@VisibleForTesting
public ProcessedPerfettoProtoLogImpl(
+ @NonNull ProtoLogDataSource datasource,
@NonNull String viewerConfigFilePath,
@NonNull ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
@NonNull ProtoLogViewerConfigReader viewerConfigReader,
- @NonNull Runnable cacheUpdater,
+ @NonNull ProtoLogCacheUpdater cacheUpdater,
@NonNull IProtoLogGroup[] groups,
- @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
@Nullable IProtoLogConfigurationService configurationService)
throws ServiceManager.ServiceNotFoundException {
- super(cacheUpdater, groups, dataSourceBuilder, configurationService);
+ super(datasource, cacheUpdater, groups, configurationService);
this.mViewerConfigFilePath = viewerConfigFilePath;
@@ -113,6 +115,10 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
*/
@Override
public int startLoggingToLogcat(String[] groups, @NonNull ILogger logger) {
+ if (!validateGroups(logger, groups)) {
+ return -1;
+ }
+
mViewerConfigReader.loadViewerConfig(groups, logger);
return super.startLoggingToLogcat(groups, logger);
}
@@ -125,8 +131,19 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
*/
@Override
public int stopLoggingToLogcat(String[] groups, @NonNull ILogger logger) {
+ if (!validateGroups(logger, groups)) {
+ return -1;
+ }
+
+ var status = super.stopLoggingToLogcat(groups, logger);
+
+ if (status != 0) {
+ throw new RuntimeException("Failed to stop logging to logcat");
+ }
+
+ // If we successfully disabled logging, unload the viewer config.
mViewerConfigReader.unloadViewerConfig(groups, logger);
- return super.stopLoggingToLogcat(groups, logger);
+ return status;
}
@Deprecated
diff --git a/core/java/com/android/internal/protolog/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java
index d117e93d7de7..c81af959f36c 100644
--- a/core/java/com/android/internal/protolog/ProtoLog.java
+++ b/core/java/com/android/internal/protolog/ProtoLog.java
@@ -17,6 +17,9 @@
package com.android.internal.protolog;
import android.os.ServiceManager;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
import com.android.internal.protolog.common.IProtoLog;
import com.android.internal.protolog.common.IProtoLogGroup;
@@ -54,6 +57,8 @@ public class ProtoLog {
private static IProtoLog sProtoLogInstance;
+ private static ProtoLogDataSource sDataSource;
+
private static final Object sInitLock = new Object();
/**
@@ -69,26 +74,45 @@ public class ProtoLog {
// files to extract out the log strings. Otherwise, the trace calls are replaced with calls
// directly to the generated tracing implementations.
if (android.tracing.Flags.perfettoProtologTracing()) {
- synchronized (sInitLock) {
- final var allGroups = new HashSet<>(Arrays.stream(groups).toList());
- if (sProtoLogInstance != null) {
- // The ProtoLog instance has already been initialized in this process
- final var alreadyRegisteredGroups = sProtoLogInstance.getRegisteredGroups();
- allGroups.addAll(alreadyRegisteredGroups);
- }
-
- try {
- sProtoLogInstance = new UnprocessedPerfettoProtoLogImpl(
- allGroups.toArray(new IProtoLogGroup[0]));
- } catch (ServiceManager.ServiceNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
+ initializePerfettoProtoLog(groups);
} else {
sProtoLogInstance = new LogcatOnlyProtoLogImpl();
}
}
+ private static void initializePerfettoProtoLog(IProtoLogGroup... groups) {
+ var datasource = getSharedSingleInstanceDataSource();
+
+ synchronized (sInitLock) {
+ final var allGroups = new HashSet<>(Arrays.stream(groups).toList());
+ final var previousProtoLogImpl = sProtoLogInstance;
+ if (previousProtoLogImpl != null) {
+ // The ProtoLog instance has already been initialized in this process
+ final var alreadyRegisteredGroups = previousProtoLogImpl.getRegisteredGroups();
+ allGroups.addAll(alreadyRegisteredGroups);
+ }
+
+ sProtoLogInstance = createAndEnableNewPerfettoProtoLogImpl(
+ datasource, allGroups.toArray(new IProtoLogGroup[0]));
+ if (previousProtoLogImpl instanceof PerfettoProtoLogImpl) {
+ ((PerfettoProtoLogImpl) previousProtoLogImpl).disable();
+ }
+ }
+ }
+
+ private static PerfettoProtoLogImpl createAndEnableNewPerfettoProtoLogImpl(
+ ProtoLogDataSource datasource, IProtoLogGroup[] groups) {
+ try {
+ var unprocessedPerfettoProtoLogImpl =
+ new UnprocessedPerfettoProtoLogImpl(datasource, groups);
+ unprocessedPerfettoProtoLogImpl.enable();
+
+ return unprocessedPerfettoProtoLogImpl;
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* DEBUG level log.
*
@@ -190,6 +214,32 @@ public class ProtoLog {
return sProtoLogInstance;
}
+ /**
+ * Gets or creates if it doesn't exist yet the protolog datasource to use in this process.
+ * We should re-use the same datasource to avoid registering the datasource multiple times in
+ * the same process, since there is no way to unregister the datasource after registration.
+ *
+ * @return The single ProtoLog datasource instance to be shared across all ProtoLog tracing
+ * objects.
+ */
+ public static synchronized ProtoLogDataSource getSharedSingleInstanceDataSource() {
+ if (sDataSource == null) {
+ Producer.init(InitArguments.DEFAULTS);
+ sDataSource = new ProtoLogDataSource();
+ DataSourceParams params =
+ new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(
+ DataSourceParams
+ .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
+ .build();
+ // NOTE: Registering that datasource is an async operation, so there may be no data
+ // traced for some messages logged right after the construction of this class.
+ sDataSource.register(params);
+ }
+
+ return sDataSource;
+ }
+
private static void logStringMessage(LogLevel logLevel, IProtoLogGroup group,
String stringMessage, Object... args) {
if (sProtoLogInstance == null) {
diff --git a/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java b/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java
new file mode 100644
index 000000000000..4f8655c6377b
--- /dev/null
+++ b/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import com.android.internal.protolog.common.IProtoLog;
+
+public interface ProtoLogCacheUpdater {
+ /**
+ * Update the cache based on the latest state of the active tracing configurations.
+ *
+ * @param protoLogInstance the instance to use to query the latest state of tracing.
+ */
+ void update(IProtoLog protoLogInstance);
+}
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
index e9a8770deb73..23f7c2a3d987 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
@@ -34,9 +34,6 @@ import android.content.Context;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.tracing.perfetto.DataSourceParams;
-import android.tracing.perfetto.InitArguments;
-import android.tracing.perfetto.Producer;
import android.util.Log;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
@@ -110,39 +107,31 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
private final ViewerConfigFileTracer mViewerConfigFileTracer;
public ProtoLogConfigurationServiceImpl() {
- this(ProtoLogDataSource::new, ProtoLogConfigurationServiceImpl::dumpViewerConfig);
+ this(ProtoLog.getSharedSingleInstanceDataSource(),
+ ProtoLogConfigurationServiceImpl::dumpViewerConfig);
}
@VisibleForTesting
- public ProtoLogConfigurationServiceImpl(@NonNull ProtoLogDataSourceBuilder dataSourceBuilder) {
- this(dataSourceBuilder, ProtoLogConfigurationServiceImpl::dumpViewerConfig);
+ public ProtoLogConfigurationServiceImpl(@NonNull ProtoLogDataSource datasource) {
+ this(datasource, ProtoLogConfigurationServiceImpl::dumpViewerConfig);
}
@VisibleForTesting
public ProtoLogConfigurationServiceImpl(@NonNull ViewerConfigFileTracer tracer) {
- this(ProtoLogDataSource::new, tracer);
+ this(ProtoLog.getSharedSingleInstanceDataSource(), tracer);
}
@VisibleForTesting
public ProtoLogConfigurationServiceImpl(
- @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
+ @NonNull ProtoLogDataSource datasource,
@NonNull ViewerConfigFileTracer tracer) {
- mDataSource = dataSourceBuilder.build(
- this::onTracingInstanceStart,
- this::onTracingInstanceFlush,
- this::onTracingInstanceStop
- );
-
- // Initialize the Perfetto producer and register the Perfetto ProtoLog datasource to be
- // receive the lifecycle callbacks of the datasource and write the viewer configs if and
- // when required to the datasource.
- Producer.init(InitArguments.DEFAULTS);
- final var params = new DataSourceParams.Builder()
- .setBufferExhaustedPolicy(DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
- .build();
- mDataSource.register(params);
-
mViewerConfigFileTracer = tracer;
+
+ datasource.registerOnStartCallback(this::onTracingInstanceStart);
+ datasource.registerOnFlushCallback(this::onTracingInstanceFlush);
+ datasource.registerOnStopCallback(this::onTracingInstanceStop);
+
+ mDataSource = datasource;
}
public static class RegisterClientArgs extends IRegisterClientArgs.Stub {
diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
index 0afb135ac6d9..ea452494b88d 100644
--- a/core/java/com/android/internal/protolog/ProtoLogDataSource.java
+++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
@@ -46,36 +46,30 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance,
ProtoLogDataSource.TlsState,
ProtoLogDataSource.IncrementalState> {
private static final String DATASOURCE_NAME = "android.protolog";
+ private final Map<Integer, ProtoLogConfig> mRunningInstances = new TreeMap<>();
+
@NonNull
- private final Instance.TracingInstanceStartCallback mOnStart;
+ private final Set<Instance.TracingInstanceStartCallback> mOnStartCallbacks = new HashSet<>();
@NonNull
- private final Runnable mOnFlush;
+ private final Set<Runnable> mOnFlushCallbacks = new HashSet<>();
@NonNull
- private final Instance.TracingInstanceStopCallback mOnStop;
+ private final Set<Instance.TracingInstanceStopCallback> mOnStopCallbacks = new HashSet<>();
- public ProtoLogDataSource(
- @NonNull Instance.TracingInstanceStartCallback onStart,
- @NonNull Runnable onFlush,
- @NonNull Instance.TracingInstanceStopCallback onStop) {
- this(onStart, onFlush, onStop, DATASOURCE_NAME);
+ public ProtoLogDataSource() {
+ this(DATASOURCE_NAME);
}
@VisibleForTesting
public ProtoLogDataSource(
- @NonNull Instance.TracingInstanceStartCallback onStart,
- @NonNull Runnable onFlush,
- @NonNull Instance.TracingInstanceStopCallback onStop,
@NonNull String dataSourceName) {
super(dataSourceName);
- this.mOnStart = onStart;
- this.mOnFlush = onFlush;
- this.mOnStop = onStop;
}
@Override
@@ -106,7 +100,8 @@ public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance,
}
return new Instance(
- this, instanceIndex, config, mOnStart, mOnFlush, mOnStop);
+ this, instanceIndex, config, this::executeOnStartCallbacks,
+ this::executeOnFlushCallbacks, this::executeOnStopCallbacks);
}
@Override
@@ -128,6 +123,84 @@ public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance,
return new IncrementalState();
}
+ /**
+ * Register an onStart callback that will be called when a tracing instance is started.
+ * The callback will be called immediately for all currently running tracing instances on
+ * registration.
+ * @param onStartCallback The callback to call on starting a tracing instance.
+ */
+ public synchronized void registerOnStartCallback(
+ Instance.TracingInstanceStartCallback onStartCallback) {
+ mOnStartCallbacks.add(onStartCallback);
+
+ for (var instanceIndex : mRunningInstances.keySet()) {
+ var config = mRunningInstances.get(instanceIndex);
+ onStartCallback.run(instanceIndex, config);
+ }
+ }
+
+ /**
+ * Register an onFlush callback that will be called when a tracing instance is about to flush.
+ * @param onFlushCallback The callback to call on flushing a tracing instance
+ */
+ public void registerOnFlushCallback(Runnable onFlushCallback) {
+ mOnFlushCallbacks.add(onFlushCallback);
+ }
+
+ /**
+ * Register an onStop callback that will be called when a tracing instance is being stopped.
+ * @param onStopCallback The callback to call on stopping a tracing instance.
+ */
+ public void registerOnStopCallback(Instance.TracingInstanceStopCallback onStopCallback) {
+ mOnStopCallbacks.add(onStopCallback);
+ }
+
+ /**
+ * Unregister an onStart callback.
+ * @param onStartCallback The callback object to unregister.
+ */
+ public void unregisterOnStartCallback(Instance.TracingInstanceStartCallback onStartCallback) {
+ mOnStartCallbacks.add(onStartCallback);
+ }
+
+ /**
+ * Unregister an onFlush callback.
+ * @param onFlushCallback The callback object to unregister.
+ */
+ public void unregisterOnFlushCallback(Runnable onFlushCallback) {
+ mOnFlushCallbacks.add(onFlushCallback);
+ }
+
+ /**
+ * Unregister an onStop callback.
+ * @param onStopCallback The callback object to unregister.
+ */
+ public void unregisterOnStopCallback(Instance.TracingInstanceStopCallback onStopCallback) {
+ mOnStopCallbacks.add(onStopCallback);
+ }
+
+ private synchronized void executeOnStartCallbacks(int instanceIdx, ProtoLogConfig config) {
+ mRunningInstances.put(instanceIdx, config);
+
+ for (var onStart : mOnStartCallbacks) {
+ onStart.run(instanceIdx, config);
+ }
+ }
+
+ private void executeOnFlushCallbacks() {
+ for (var onFlush : mOnFlushCallbacks) {
+ onFlush.run();
+ }
+ }
+
+ private synchronized void executeOnStopCallbacks(int instanceIdx, ProtoLogConfig config) {
+ mRunningInstances.remove(instanceIdx, config);
+
+ for (var onStop : mOnStopCallbacks) {
+ onStop.run(instanceIdx, config);
+ }
+ }
+
public static class TlsState {
@NonNull
private final ProtoLogConfig mConfig;
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 3378d08e7761..c2d4b21181b7 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -56,7 +56,7 @@ public class ProtoLogImpl {
private static TreeMap<String, IProtoLogGroup> sLogGroups;
@ProtoLogToolInjected(CACHE_UPDATER)
- private static Runnable sCacheUpdater;
+ private static ProtoLogCacheUpdater sCacheUpdater;
/** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
public static void d(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) {
@@ -93,7 +93,12 @@ public class ProtoLogImpl {
* and log level.
*/
public static boolean isEnabled(IProtoLogGroup group, LogLevel level) {
- return getSingleInstance().isEnabled(group, level);
+ return isEnabled(getSingleInstance(), group, level);
+ }
+
+ private static boolean isEnabled(
+ IProtoLog protoLogInstance, IProtoLogGroup group, LogLevel level) {
+ return protoLogInstance.isEnabled(group, level);
}
/**
@@ -106,36 +111,37 @@ public class ProtoLogImpl {
final var groups = sLogGroups.values().toArray(new IProtoLogGroup[0]);
if (android.tracing.Flags.perfettoProtologTracing()) {
- sServiceInstance = createProtoLogImpl(groups);
+ var viewerConfigFile = new File(sViewerConfigPath);
+ if (!viewerConfigFile.exists()) {
+ // TODO(b/353530422): Remove - temporary fix to unblock b/352290057
+ // In robolectric tests the viewer config file isn't current available, so we
+ // cannot use the ProcessedPerfettoProtoLogImpl.
+ Log.e(LOG_TAG, "Failed to find viewer config file " + sViewerConfigPath
+ + " when setting up " + ProtoLogImpl.class.getSimpleName() + ". "
+ + "ProtoLog will not work here!");
+
+ sServiceInstance = new NoViewerConfigProtoLogImpl();
+ } else {
+ var datasource = ProtoLog.getSharedSingleInstanceDataSource();
+ try {
+ var processedProtoLogImpl =
+ new ProcessedPerfettoProtoLogImpl(datasource, sViewerConfigPath,
+ sCacheUpdater, groups);
+ sServiceInstance = processedProtoLogImpl;
+ processedProtoLogImpl.enable();
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
} else {
sServiceInstance = createLegacyProtoLogImpl(groups);
}
- sCacheUpdater.run();
+ sCacheUpdater.update(sServiceInstance);
}
return sServiceInstance;
}
- private static IProtoLog createProtoLogImpl(IProtoLogGroup[] groups) {
- try {
- File f = new File(sViewerConfigPath);
- if (!f.exists()) {
- // TODO(b/353530422): Remove - temporary fix to unblock b/352290057
- // In robolectric tests the viewer config file isn't current available, so we cannot
- // use the ProcessedPerfettoProtoLogImpl.
- Log.e(LOG_TAG, "Failed to find viewer config file " + sViewerConfigPath
- + " when setting up " + ProtoLogImpl.class.getSimpleName() + ". "
- + "ProtoLog will not work here!");
-
- return new NoViewerConfigProtoLogImpl();
- } else {
- return new ProcessedPerfettoProtoLogImpl(sViewerConfigPath, sCacheUpdater, groups);
- }
- } catch (ServiceManager.ServiceNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
-
private static LegacyProtoLogImpl createLegacyProtoLogImpl(IProtoLogGroup[] groups) {
var protologImpl = new LegacyProtoLogImpl(
sLegacyOutputFilePath, sLegacyViewerConfigPath, sCacheUpdater);
diff --git a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
index f3fe58070fa9..ebb07a04270d 100644
--- a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
@@ -23,14 +23,10 @@ import com.android.internal.protolog.ProtoLogConfigurationServiceImpl.RegisterCl
import com.android.internal.protolog.common.IProtoLogGroup;
public class UnprocessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
- public UnprocessedPerfettoProtoLogImpl(@NonNull IProtoLogGroup[] groups)
+ public UnprocessedPerfettoProtoLogImpl(
+ @NonNull ProtoLogDataSource dataSource, @NonNull IProtoLogGroup[] groups)
throws ServiceManager.ServiceNotFoundException {
- this(() -> {}, groups);
- }
-
- public UnprocessedPerfettoProtoLogImpl(@NonNull Runnable cacheUpdater,
- @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
- super(cacheUpdater, groups);
+ super(dataSource, (instance) -> {}, groups);
readyToLogToLogcat();
}
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
index 3303d875c427..8df3f2abcafd 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -88,15 +88,19 @@ public final class RavenwoodEnvironment {
/** @hide */
public static class CompatIdsForTest {
// Enabled by default
+ /** Used for testing */
@ChangeId
public static final long TEST_COMPAT_ID_1 = 368131859L;
+ /** Used for testing */
@Disabled
@ChangeId public static final long TEST_COMPAT_ID_2 = 368131701L;
+ /** Used for testing */
@EnabledAfter(targetSdkVersion = S)
@ChangeId public static final long TEST_COMPAT_ID_3 = 368131659L;
+ /** Used for testing */
@EnabledAfter(targetSdkVersion = UPSIDE_DOWN_CAKE)
@ChangeId public static final long TEST_COMPAT_ID_4 = 368132057L;
}
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 0e85e046e1b6..bf8a56508f54 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -20,6 +20,7 @@ import android.telephony.BarringInfo;
import android.telephony.CallState;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
+import android.telephony.CellularIdentifierDisclosure;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.LinkCapacityEstimate;
import android.telephony.TelephonyDisplayInfo;
@@ -28,6 +29,7 @@ import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.satellite.NtnSignalStrength;
+import android.telephony.SecurityAlgorithmUpdate;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.emergency.EmergencyNumber;
@@ -87,4 +89,6 @@ oneway interface IPhoneStateListener {
void onCarrierRoamingNtnEligibleStateChanged(in boolean eligible);
void onCarrierRoamingNtnAvailableServicesChanged(in int[] availableServices);
void onCarrierRoamingNtnSignalStrengthChanged(in NtnSignalStrength ntnSignalStrength);
+ void onSecurityAlgorithmsChanged(in SecurityAlgorithmUpdate update);
+ void onCellularIdentifierDisclosedChanged(in CellularIdentifierDisclosure disclosure);
}
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 0f268d5de62b..a296fbd1cfe4 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -23,6 +23,7 @@ import android.telephony.BarringInfo;
import android.telephony.CallQuality;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
+import android.telephony.CellularIdentifierDisclosure;
import android.telephony.LinkCapacityEstimate;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.ims.ImsReasonInfo;
@@ -30,6 +31,7 @@ import android.telephony.PhoneCapability;
import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseDataConnectionState;
import android.telephony.satellite.NtnSignalStrength;
+import android.telephony.SecurityAlgorithmUpdate;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.emergency.EmergencyNumber;
@@ -132,4 +134,7 @@ interface ITelephonyRegistry {
void removeSatelliteStateChangeListener(ISatelliteStateChangeListener listener, String pkg);
void notifySatelliteStateChanged(boolean isEnabled);
+ void notifySecurityAlgorithmsChanged(int phoneId, int subId, in SecurityAlgorithmUpdate update);
+ void notifyCellularIdentifierDisclosedChanged(
+ int phoneId, int subId, in CellularIdentifierDisclosure disclosure);
}
diff --git a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
index 862f7cb1d476..5eedec6a63e4 100644
--- a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
+++ b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
@@ -17,6 +17,7 @@
package com.android.internal.vibrator.persistence;
import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_MS;
+import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_TYPE;
import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_NAME;
import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_SCALE;
import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE;
@@ -25,9 +26,11 @@ import static com.android.internal.vibrator.persistence.XmlConstants.TAG_PRIMITI
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.VibrationEffect;
+import android.os.vibrator.Flags;
import android.os.vibrator.PrimitiveSegment;
import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment;
+import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType;
import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -46,17 +49,26 @@ final class SerializedCompositionPrimitive implements SerializedSegment {
private final PrimitiveEffectName mPrimitiveName;
private final float mPrimitiveScale;
private final int mPrimitiveDelayMs;
+ @Nullable
+ private final PrimitiveDelayType mDelayType;
- SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs) {
+ SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs,
+ @Nullable PrimitiveDelayType delayType) {
mPrimitiveName = primitiveName;
mPrimitiveScale = scale;
mPrimitiveDelayMs = delayMs;
+ mDelayType = delayType;
}
@Override
public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) {
- composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
- mPrimitiveDelayMs);
+ if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) {
+ composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
+ mPrimitiveDelayMs, mDelayType.getDelayType());
+ } else {
+ composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
+ mPrimitiveDelayMs);
+ }
}
@Override
@@ -72,6 +84,12 @@ final class SerializedCompositionPrimitive implements SerializedSegment {
serializer.attributeInt(NAMESPACE, ATTRIBUTE_DELAY_MS, mPrimitiveDelayMs);
}
+ if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) {
+ if (mDelayType.getDelayType() != PrimitiveSegment.DEFAULT_DELAY_TYPE) {
+ serializer.attribute(NAMESPACE, ATTRIBUTE_DELAY_TYPE, mDelayType.toString());
+ }
+ }
+
serializer.endTag(NAMESPACE, TAG_PRIMITIVE_EFFECT);
}
@@ -81,6 +99,7 @@ final class SerializedCompositionPrimitive implements SerializedSegment {
+ "name=" + mPrimitiveName
+ ", scale=" + mPrimitiveScale
+ ", delayMs=" + mPrimitiveDelayMs
+ + ", delayType=" + mDelayType
+ '}';
}
@@ -91,8 +110,14 @@ final class SerializedCompositionPrimitive implements SerializedSegment {
static SerializedCompositionPrimitive parseNext(@NonNull TypedXmlPullParser parser)
throws XmlParserException, IOException {
XmlValidator.checkStartTag(parser, TAG_PRIMITIVE_EFFECT);
- XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
- ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE);
+
+ if (Flags.primitiveCompositionAbsoluteDelay()) {
+ XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
+ ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE, ATTRIBUTE_DELAY_TYPE);
+ } else {
+ XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
+ ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE);
+ }
PrimitiveEffectName primitiveName = parsePrimitiveName(
parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME));
@@ -100,11 +125,13 @@ final class SerializedCompositionPrimitive implements SerializedSegment {
parser, ATTRIBUTE_SCALE, 0, 1, PrimitiveSegment.DEFAULT_SCALE);
int delayMs = XmlReader.readAttributeIntNonNegative(
parser, ATTRIBUTE_DELAY_MS, PrimitiveSegment.DEFAULT_DELAY_MILLIS);
+ PrimitiveDelayType delayType = parseDelayType(
+ parser.getAttributeValue(NAMESPACE, ATTRIBUTE_DELAY_TYPE));
// Consume tag
XmlReader.readEndTag(parser);
- return new SerializedCompositionPrimitive(primitiveName, scale, delayMs);
+ return new SerializedCompositionPrimitive(primitiveName, scale, delayMs, delayType);
}
@NonNull
@@ -119,5 +146,21 @@ final class SerializedCompositionPrimitive implements SerializedSegment {
}
return effectName;
}
+
+ @Nullable
+ private static PrimitiveDelayType parseDelayType(@Nullable String name)
+ throws XmlParserException {
+ if (name == null) {
+ return null;
+ }
+ if (!Flags.primitiveCompositionAbsoluteDelay()) {
+ throw new XmlParserException("Unexpected primitive delay type " + name);
+ }
+ PrimitiveDelayType delayType = PrimitiveDelayType.findByName(name);
+ if (delayType == null) {
+ throw new XmlParserException("Unexpected primitive delay type " + name);
+ }
+ return delayType;
+ }
}
}
diff --git a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
index d74a23d47f4a..cb834a5eac7e 100644
--- a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
+++ b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
@@ -27,6 +27,7 @@ import android.os.vibrator.VibrationEffectSegment;
import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment;
import com.android.internal.vibrator.persistence.XmlConstants.PredefinedEffectName;
+import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType;
import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName;
import java.util.List;
@@ -170,8 +171,20 @@ public final class VibrationEffectXmlSerializer {
XmlValidator.checkSerializerCondition(primitiveName != null,
"Unsupported primitive effect id %s", primitive.getPrimitiveId());
+ PrimitiveDelayType delayType = null;
+
+ if (Flags.primitiveCompositionAbsoluteDelay()) {
+ delayType = PrimitiveDelayType.findByType(primitive.getDelayType());
+ XmlValidator.checkSerializerCondition(delayType != null,
+ "Unsupported primitive delay type %s", primitive.getDelayType());
+ } else {
+ XmlValidator.checkSerializerCondition(
+ primitive.getDelayType() == PrimitiveSegment.DEFAULT_DELAY_TYPE,
+ "Unsupported primitive delay type %s", primitive.getDelayType());
+ }
+
return new SerializedCompositionPrimitive(
- primitiveName, primitive.getScale(), primitive.getDelay());
+ primitiveName, primitive.getScale(), primitive.getDelay(), delayType);
}
private static int toAmplitudeInt(float amplitude) {
diff --git a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
index 2a55d999bc0f..4122215a2b04 100644
--- a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
+++ b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.VibrationEffect;
+import android.os.VibrationEffect.Composition.DelayType;
import android.os.VibrationEffect.Composition.PrimitiveType;
import java.lang.annotation.Retention;
@@ -51,6 +52,7 @@ public final class XmlConstants {
public static final String ATTRIBUTE_AMPLITUDE = "amplitude";
public static final String ATTRIBUTE_SCALE = "scale";
public static final String ATTRIBUTE_DELAY_MS = "delayMs";
+ public static final String ATTRIBUTE_DELAY_TYPE = "delayType";
public static final String VALUE_AMPLITUDE_DEFAULT = "default";
@@ -87,7 +89,7 @@ public final class XmlConstants {
/**
* Return the {@link PrimitiveEffectName} that represents given primitive id, or null if
- * none of the available names maps to the given id.
+ * none of the available names map to the given id.
*/
@Nullable
public static PrimitiveEffectName findById(int primitiveId) {
@@ -200,4 +202,53 @@ public final class XmlConstants {
return name().toLowerCase(Locale.ROOT);
}
}
+
+ /** Represent supported values for attribute delay type in {@link #TAG_PRIMITIVE_EFFECT} */
+ public enum PrimitiveDelayType {
+ PAUSE(VibrationEffect.Composition.DELAY_TYPE_PAUSE),
+ RELATIVE_START_OFFSET(VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET);
+
+ @DelayType private final int mDelayType;
+
+ PrimitiveDelayType(@DelayType int type) {
+ mDelayType = type;
+ }
+
+ /**
+ * Return the {@link PrimitiveEffectName} that represents given primitive id, or null if
+ * none of the available names maps to the given id.
+ */
+ @Nullable
+ public static PrimitiveDelayType findByType(int delayType) {
+ for (PrimitiveDelayType type : PrimitiveDelayType.values()) {
+ if (type.mDelayType == delayType) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the {@link PrimitiveEffectName} that represents given primitive name, or null if
+ * none of the available names maps to the given name.
+ */
+ @Nullable
+ public static PrimitiveDelayType findByName(@NonNull String delayType) {
+ try {
+ return PrimitiveDelayType.valueOf(delayType.toUpperCase(Locale.ROOT));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ @DelayType
+ public int getDelayType() {
+ return mDelayType;
+ }
+
+ @Override
+ public String toString() {
+ return name().toLowerCase(Locale.ROOT);
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index f2b36c3b9981..8cd7843fe1d9 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -59,6 +59,8 @@ import java.util.TreeSet;
public final class NotificationProgressBar extends ProgressBar {
private static final String TAG = "NotificationProgressBar";
+ private NotificationProgressDrawable mNotificationProgressDrawable;
+
private NotificationProgressModel mProgressModel;
@Nullable
@@ -66,12 +68,18 @@ public final class NotificationProgressBar extends ProgressBar {
@Nullable
private Drawable mTracker = null;
+
+ /** @see R.styleable#NotificationProgressBar_trackerHeight */
private final int mTrackerHeight;
private int mTrackerWidth;
private int mTrackerPos;
private final Matrix mMatrix = new Matrix();
private Matrix mTrackerDrawMatrix = null;
+ private float mScale = 0;
+ /** Indicates whether mTrackerPos needs to be recalculated before the tracker is drawn. */
+ private boolean mTrackerPosIsDirty = false;
+
public NotificationProgressBar(Context context) {
this(context, null);
}
@@ -94,13 +102,19 @@ public final class NotificationProgressBar extends ProgressBar {
defStyleAttr,
defStyleRes);
+ try {
+ mNotificationProgressDrawable = getNotificationProgressDrawable();
+ } catch (IllegalStateException ex) {
+ Log.e(TAG, "Can't get NotificationProgressDrawable", ex);
+ }
+
// Supports setting the tracker in xml, but ProgressStyle notifications set/override it
// via {@code setProgressTrackerIcon}.
final Drawable tracker = a.getDrawable(R.styleable.NotificationProgressBar_tracker);
setTracker(tracker);
- // If this is configured to be non-zero, will scale the tracker drawable and ensure its
- // aspect ration is between 2:1 to 1:2.
+ // If this is configured to be a non-zero size, will scale and crop the tracker drawable to
+ // ensure its aspect ratio is between 2:1 to 1:2.
mTrackerHeight = a.getDimensionPixelSize(R.styleable.NotificationProgressBar_trackerHeight,
0);
}
@@ -131,11 +145,8 @@ public final class NotificationProgressBar extends ProgressBar {
progressMax,
mProgressModel.isStyledByProgress());
- try {
- final NotificationProgressDrawable drawable = getNotificationProgressDrawable();
- drawable.setParts(mProgressDrawableParts);
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Can't set parts because can't get NotificationProgressDrawable", ex);
+ if (mNotificationProgressDrawable != null) {
+ mNotificationProgressDrawable.setParts(mProgressDrawableParts);
}
setMax(progressMax);
@@ -195,12 +206,9 @@ public final class NotificationProgressBar extends ProgressBar {
}
private void setTracker(@Nullable Drawable tracker) {
- if (isIndeterminate() && tracker != null) {
- return;
- }
+ if (tracker == mTracker) return;
- final boolean needUpdate = mTracker != null && tracker != mTracker;
- if (needUpdate) {
+ if (mTracker != null) {
mTracker.setCallback(null);
}
@@ -213,30 +221,41 @@ public final class NotificationProgressBar extends ProgressBar {
if (canResolveLayoutDirection()) {
tracker.setLayoutDirection(getLayoutDirection());
}
-
- // If we're updating get the new states
- if (needUpdate && (tracker.getIntrinsicWidth() != mTracker.getIntrinsicWidth()
- || tracker.getIntrinsicHeight() != mTracker.getIntrinsicHeight())) {
- requestLayout();
- }
}
+ final boolean trackerSizeChanged = trackerSizeChanged(tracker, mTracker);
+
mTracker = tracker;
+ if (mNotificationProgressDrawable != null) {
+ mNotificationProgressDrawable.setHasTrackerIcon(mTracker != null);
+ }
configureTrackerBounds();
+ updateTrackerAndBarPos(getWidth(), getHeight());
+
+ // Change in tracker size may lead to change in measured view size.
+ // @see #onMeasure.
+ if (trackerSizeChanged) requestLayout();
invalidate();
- if (needUpdate) {
- updateTrackerAndBarPos(getWidth(), getHeight());
- if (tracker != null && tracker.isStateful()) {
- // Note that if the states are different this won't work.
- // For now, let's consider that an app bug.
- tracker.setState(getDrawableState());
- }
+ if (tracker != null && tracker.isStateful()) {
+ // Note that if the states are different this won't work.
+ // For now, let's consider that an app bug.
+ tracker.setState(getDrawableState());
}
}
+ private static boolean trackerSizeChanged(@Nullable Drawable newTracker,
+ @Nullable Drawable oldTracker) {
+ if (newTracker == null && oldTracker == null) return false;
+ if (newTracker == null && oldTracker != null) return true;
+ if (newTracker != null && oldTracker == null) return true;
+
+ return newTracker.getIntrinsicWidth() != oldTracker.getIntrinsicWidth()
+ || newTracker.getIntrinsicHeight() != oldTracker.getIntrinsicHeight();
+ }
+
private void configureTrackerBounds() {
// Reset the tracker draw matrix to null
mTrackerDrawMatrix = null;
@@ -275,13 +294,41 @@ public final class NotificationProgressBar extends ProgressBar {
}
@Override
- @RemotableViewMethod
- public synchronized void setIndeterminate(boolean indeterminate) {
- super.setIndeterminate(indeterminate);
+ public synchronized void setProgress(int progress) {
+ super.setProgress(progress);
- if (isIndeterminate()) {
- setTracker(null);
- }
+ onMaybeVisualProgressChanged();
+ }
+
+ @Override
+ public void setProgress(int progress, boolean animate) {
+ // Animation isn't supported by NotificationProgressBar.
+ super.setProgress(progress, false);
+
+ onMaybeVisualProgressChanged();
+ }
+
+ @Override
+ public synchronized void setMin(int min) {
+ super.setMin(min);
+
+ onMaybeVisualProgressChanged();
+ }
+
+ @Override
+ public synchronized void setMax(int max) {
+ super.setMax(max);
+
+ onMaybeVisualProgressChanged();
+ }
+
+ private void onMaybeVisualProgressChanged() {
+ float scale = getScale();
+ if (mScale == scale) return;
+
+ mScale = scale;
+ mTrackerPosIsDirty = true;
+ invalidate();
}
@Override
@@ -334,7 +381,7 @@ public final class NotificationProgressBar extends ProgressBar {
// parameter does.
final int barHeight = Math.min(getMaxHeight(), paddedHeight);
final int trackerHeight = tracker == null ? 0
- : ((mTrackerHeight == 0) ? tracker.getIntrinsicHeight() : mTrackerHeight);
+ : ((mTrackerHeight <= 0) ? tracker.getIntrinsicHeight() : mTrackerHeight);
// Apply offset to whichever item is taller.
final int barOffsetY;
@@ -355,7 +402,7 @@ public final class NotificationProgressBar extends ProgressBar {
}
if (tracker != null) {
- setTrackerPos(w, tracker, getScale(), trackerOffsetY);
+ setTrackerPos(w, tracker, mScale, trackerOffsetY);
}
}
@@ -379,7 +426,7 @@ public final class NotificationProgressBar extends ProgressBar {
int available = w - mPaddingLeft - mPaddingRight;
final int trackerWidth = tracker.getIntrinsicWidth();
final int trackerHeight = tracker.getIntrinsicHeight();
- available -= ((mTrackerHeight == 0) ? trackerWidth : mTrackerWidth);
+ available -= ((mTrackerHeight <= 0) ? trackerWidth : mTrackerWidth);
final int trackerPos = (int) (scale * available + 0.5f);
@@ -407,6 +454,8 @@ public final class NotificationProgressBar extends ProgressBar {
// Canvas will be translated, so 0,0 is where we start drawing
tracker.setBounds(left, top, right, bottom);
+
+ mTrackerPosIsDirty = false;
}
@Override
@@ -421,6 +470,8 @@ public final class NotificationProgressBar extends ProgressBar {
@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
+
+ if (isIndeterminate()) return;
drawTracker(canvas);
}
@@ -428,18 +479,26 @@ public final class NotificationProgressBar extends ProgressBar {
* Draw the tracker.
*/
private void drawTracker(Canvas canvas) {
- if (mTracker != null) {
- final int saveCount = canvas.save();
- // Translate the canvas origin to tracker position to make the draw matrix and the RtL
- // transformations work.
- canvas.translate(mPaddingLeft + mTrackerPos, mPaddingTop);
+ if (mTracker == null) return;
+
+ if (mTrackerPosIsDirty) {
+ setTrackerPos(getWidth(), mTracker, mScale, Integer.MIN_VALUE);
+ }
+
+ final int saveCount = canvas.save();
+ // Translate the canvas origin to tracker position to make the draw matrix and the RtL
+ // transformations work.
+ canvas.translate(mPaddingLeft + mTrackerPos, mPaddingTop);
+
+ if (mTrackerHeight > 0) {
canvas.clipRect(0, 0, mTrackerWidth, mTrackerHeight);
- if (mTrackerDrawMatrix != null) {
- canvas.concat(mTrackerDrawMatrix);
- }
- mTracker.draw(canvas);
- canvas.restoreToCount(saveCount);
}
+
+ if (mTrackerDrawMatrix != null) {
+ canvas.concat(mTrackerDrawMatrix);
+ }
+ mTracker.draw(canvas);
+ canvas.restoreToCount(saveCount);
}
@Override
@@ -472,7 +531,7 @@ public final class NotificationProgressBar extends ProgressBar {
final Drawable tracker = mTracker;
if (tracker != null) {
- setTrackerPos(getWidth(), tracker, getScale(), Integer.MIN_VALUE);
+ setTrackerPos(getWidth(), tracker, mScale, Integer.MIN_VALUE);
// Since we draw translated, the drawable's bounds that it signals
// for invalidation won't be the actual bounds we want invalidated,
diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
index fb6937c94a3e..e95225eede99 100644
--- a/core/java/com/android/internal/widget/NotificationProgressDrawable.java
+++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
@@ -23,7 +23,6 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
-import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -62,21 +61,15 @@ public final class NotificationProgressDrawable extends Drawable {
private boolean mMutated;
private final ArrayList<Part> mParts = new ArrayList<>();
+ private boolean mHasTrackerIcon;
private final RectF mSegRectF = new RectF();
private final Rect mPointRect = new Rect();
private final RectF mPointRectF = new RectF();
- private final Paint mStrokePaint = new Paint();
- private final Paint mDashedStrokePaint = new Paint();
private final Paint mFillPaint = new Paint();
{
- mStrokePaint.setStyle(Paint.Style.STROKE);
- mStrokePaint.setStrokeCap(Paint.Cap.ROUND);
-
- mDashedStrokePaint.setStyle(Paint.Style.STROKE);
-
mFillPaint.setStyle(Paint.Style.FILL);
}
@@ -87,49 +80,15 @@ public final class NotificationProgressDrawable extends Drawable {
}
/**
- * <p>Set the stroke width and default color for the drawable.</p>
- * <p>Note: changing this property will affect all instances of a drawable loaded from a
- * resource. It is recommended to invoke
- * {@link #mutate()} before changing this property.</p>
- *
- * @param width The width in pixels of the stroke
- * @param color The color of the stroke
- * @see #mutate()
- * @see #setStroke(int, int, float, float)
- */
- public void setStroke(int width, @ColorInt int color) {
- setStroke(width, color, 0, 0);
- }
-
- /**
- * <p>Set the stroke width and default color for the drawable. This method can also be used
- * to dash the stroke for the dashed segments.</p>
- * <p>Note: changing this property will affect all instances of a drawable loaded from a
- * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
- *
- * @param width The width in pixels of the stroke
- * @param color The color of the stroke
- * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes
- * @param dashGap The gap in pixels between dashes
- * @see #mutate()
- * @see #setStroke(int, int)
- */
- public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) {
- mState.setStroke(width, color, dashWidth, dashGap);
- setStrokeInternal(width, dashWidth, dashGap);
- }
-
- /**
- * <p>Set the stroke default color for the drawable.</p>
+ * <p>Set the segment default color for the drawable.</p>
* <p>Note: changing this property will affect all instances of a drawable loaded from a
* resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
*
* @param color The color of the stroke
* @see #mutate()
- * @see #setStroke(int, int, float, float)
*/
- public void setStrokeDefaultColor(@ColorInt int color) {
- mState.setStrokeColor(color);
+ public void setSegmentDefaultColor(@ColorInt int color) {
+ mState.setSegmentColor(color);
}
/**
@@ -144,25 +103,14 @@ public final class NotificationProgressDrawable extends Drawable {
mState.setPointRectColor(color);
}
- private void setStrokeInternal(int width, float dashWidth, float dashGap) {
- mStrokePaint.setStrokeWidth(width);
-
- mDashedStrokePaint.setStrokeWidth(width);
- DashPathEffect e = null;
- if (dashWidth > 0) {
- e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0);
- }
- mDashedStrokePaint.setPathEffect(e);
-
- invalidateSelf();
- }
-
/**
* Set the segments and points that constitute the drawable.
*/
public void setParts(List<Part> parts) {
mParts.clear();
mParts.addAll(parts);
+
+ invalidateSelf();
}
/**
@@ -172,6 +120,16 @@ public final class NotificationProgressDrawable extends Drawable {
setParts(Arrays.asList(parts));
}
+ /**
+ * Set whether a tracker is drawn on top of this NotificationProgressDrawable.
+ */
+ public void setHasTrackerIcon(boolean hasTrackerIcon) {
+ if (mHasTrackerIcon != hasTrackerIcon) {
+ mHasTrackerIcon = hasTrackerIcon;
+ invalidateSelf();
+ }
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
final float pointRadius =
@@ -181,6 +139,7 @@ public final class NotificationProgressDrawable extends Drawable {
float x = (float) getBounds().left;
final float centerY = (float) getBounds().centerY();
final float totalWidth = (float) getBounds().width();
+ float segPointGap = mState.mSegPointGap;
final int numParts = mParts.size();
for (int iPart = 0; iPart < numParts; iPart++) {
@@ -188,15 +147,19 @@ public final class NotificationProgressDrawable extends Drawable {
final Part prevPart = iPart == 0 ? null : mParts.get(iPart - 1);
final Part nextPart = iPart + 1 == numParts ? null : mParts.get(iPart + 1);
if (part instanceof Segment segment) {
+ // Update the segment-point gap to 2X upon seeing the first faded segment.
+ // (Assuming that all segments before are solid, and all segments after are faded.)
+ if (segment.mFaded) {
+ segPointGap = mState.mSegPointGap * 2;
+ }
final float segWidth = segment.mFraction * totalWidth;
// Advance the start position to account for a point immediately prior.
- final float startOffset = getSegStartOffset(prevPart, pointRadius,
- mState.mSegPointGap, x);
+ final float startOffset = getSegStartOffset(prevPart, pointRadius, segPointGap, x);
final float start = x + startOffset;
// Retract the end position to account for the padding and a point immediately
// after.
- final float endOffset = getSegEndOffset(nextPart, pointRadius, mState.mSegPointGap,
- mState.mSegSegGap, x + segWidth, totalWidth);
+ final float endOffset = getSegEndOffset(segment, nextPart, pointRadius, segPointGap,
+ mState.mSegSegGap, x + segWidth, totalWidth, mHasTrackerIcon);
final float end = x + segWidth - endOffset;
// Advance the current position to account for the segment's fraction of the total
@@ -206,35 +169,15 @@ public final class NotificationProgressDrawable extends Drawable {
// No space left to draw the segment
if (start > end) continue;
- if (segment.mDashed) {
- // No caps when the segment is dashed.
-
- mDashedStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
- : mState.mFadedStrokeColor);
- canvas.drawLine(start, centerY, end, centerY, mDashedStrokePaint);
- } else if (end - start < mState.mStrokeWidth) {
- // Not enough segment length to draw the caps
-
- final float rad = (end - start) / 2F;
- final float capWidth = mStrokePaint.getStrokeWidth() / 2F;
-
- mFillPaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
- : mState.mStrokeColor);
-
- mSegRectF.set(start, centerY - capWidth, end, centerY + capWidth);
- canvas.drawRoundRect(mSegRectF, rad, rad, mFillPaint);
- } else {
- // Leave space for the rounded line cap which extends beyond start/end.
- final float capWidth = mStrokePaint.getStrokeWidth() / 2F;
+ final float radiusY = segment.mFaded ? mState.mFadedSegmentHeight / 2F
+ : mState.mSegmentHeight / 2F;
+ final float cornerRadius = mState.mSegmentCornerRadius;
- // Transparent is not allowed (and also is the default in the data), so use that
- // as a sentinel to be replaced by default
- mStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
- : mState.mStrokeColor);
+ mFillPaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
+ : (segment.mFaded ? mState.mFadedSegmentColor : mState.mSegmentColor));
- canvas.drawLine(start + capWidth, centerY, end - capWidth, centerY,
- mStrokePaint);
- }
+ mSegRectF.set(start, centerY - radiusY, end, centerY + radiusY);
+ canvas.drawRoundRect(mSegRectF, cornerRadius, cornerRadius, mFillPaint);
} else if (part instanceof Point point) {
final float pointWidth = 2 * pointRadius;
float start = x - pointRadius;
@@ -275,10 +218,17 @@ public final class NotificationProgressDrawable extends Drawable {
return pointOffset + pointRadius + segPointGap;
}
- private static float getSegEndOffset(Part nextPart, float pointRadius, float segPointGap,
- float segSegGap, float endX, float totalWidth) {
+ private static float getSegEndOffset(Segment seg, Part nextPart, float pointRadius,
+ float segPointGap,
+ float segSegGap, float endX, float totalWidth, boolean hasTrackerIcon) {
if (nextPart == null) return 0F;
- if (!(nextPart instanceof Point)) return segSegGap;
+ if (nextPart instanceof Segment nextSeg) {
+ if (!seg.mFaded && nextSeg.mFaded) {
+ // @see Segment#mFaded
+ return hasTrackerIcon ? 0F : segSegGap * 4F;
+ }
+ return segSegGap;
+ }
final float pointWidth = 2 * pointRadius;
final float pointOffset = (endX + pointRadius > totalWidth && totalWidth > pointWidth)
@@ -439,21 +389,17 @@ public final class NotificationProgressDrawable extends Drawable {
// Extract the theme attributes, if any.
state.mThemeAttrsSegments = a.extractThemeAttrs();
- final int width = a.getDimensionPixelSize(
- R.styleable.NotificationProgressDrawableSegments_width, state.mStrokeWidth);
- final float dashWidth = a.getDimension(
- R.styleable.NotificationProgressDrawableSegments_dashWidth, state.mStrokeDashWidth);
-
+ state.mSegmentHeight = a.getDimension(
+ R.styleable.NotificationProgressDrawableSegments_height, state.mSegmentHeight);
+ state.mFadedSegmentHeight = a.getDimension(
+ R.styleable.NotificationProgressDrawableSegments_fadedHeight,
+ state.mFadedSegmentHeight);
+ state.mSegmentCornerRadius = a.getDimension(
+ R.styleable.NotificationProgressDrawableSegments_cornerRadius,
+ state.mSegmentCornerRadius);
final int color = a.getColor(R.styleable.NotificationProgressDrawableSegments_color,
- state.mStrokeColor);
-
- if (dashWidth != 0.0f) {
- final float dashGap = a.getDimension(
- R.styleable.NotificationProgressDrawableSegments_dashGap, state.mStrokeDashGap);
- setStroke(width, color, dashWidth, dashGap);
- } else {
- setStroke(width, color);
- }
+ state.mSegmentColor);
+ setSegmentDefaultColor(color);
}
private void updatePointsFromTypedArray(TypedArray a) {
@@ -532,11 +478,24 @@ public final class NotificationProgressDrawable extends Drawable {
/**
* A segment is a part of the progress bar with non-zero length. For example, it can
* represent a portion in a navigation journey with certain traffic condition.
+ *
*/
public static final class Segment implements Part {
private final float mFraction;
@ColorInt private final int mColor;
- private final boolean mDashed;
+ /** Whether the segment is faded or not.
+ * <p>
+ * <pre>
+ * When mFaded is set to true, a combination of the following is done to the segment:
+ * 1. The drawing color is mColor with opacity updated to 15%.
+ * 2. The segment-point gap is 2X the segment-point gap for non-faded segments.
+ * 3. The gap between faded and non-faded segments is:
+ * 4X the segment-segment gap, when there is no tracker icon
+ * 0, when there is tracker icon
+ * </pre>
+ * </p>
+ */
+ private final boolean mFaded;
public Segment(float fraction) {
this(fraction, Color.TRANSPARENT);
@@ -546,10 +505,10 @@ public final class NotificationProgressDrawable extends Drawable {
this(fraction, color, false);
}
- public Segment(float fraction, @ColorInt int color, boolean dashed) {
+ public Segment(float fraction, @ColorInt int color, boolean faded) {
mFraction = fraction;
mColor = color;
- mDashed = dashed;
+ mFaded = faded;
}
public float getFraction() {
@@ -560,14 +519,14 @@ public final class NotificationProgressDrawable extends Drawable {
return this.mColor;
}
- public boolean getDashed() {
- return this.mDashed;
+ public boolean getFaded() {
+ return this.mFaded;
}
@Override
public String toString() {
- return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", dashed="
- + this.mDashed + ')';
+ return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", faded="
+ + this.mFaded + ')';
}
// Needed for unit tests
@@ -580,12 +539,12 @@ public final class NotificationProgressDrawable extends Drawable {
Segment that = (Segment) other;
if (Float.compare(this.mFraction, that.mFraction) != 0) return false;
if (this.mColor != that.mColor) return false;
- return this.mDashed == that.mDashed;
+ return this.mFaded == that.mFaded;
}
@Override
public int hashCode() {
- return Objects.hash(mFraction, mColor, mDashed);
+ return Objects.hash(mFraction, mColor, mFaded);
}
}
@@ -675,11 +634,11 @@ public final class NotificationProgressDrawable extends Drawable {
int mChangingConfigurations;
float mSegSegGap = 0.0f;
float mSegPointGap = 0.0f;
- int mStrokeWidth = 0;
- int mStrokeColor;
- int mFadedStrokeColor;
- float mStrokeDashWidth = 0.0f;
- float mStrokeDashGap = 0.0f;
+ float mSegmentHeight;
+ float mFadedSegmentHeight;
+ float mSegmentCornerRadius;
+ int mSegmentColor;
+ int mFadedSegmentColor;
float mPointRadius;
float mPointRectInset;
float mPointRectCornerRadius;
@@ -699,11 +658,11 @@ public final class NotificationProgressDrawable extends Drawable {
mChangingConfigurations = orig.mChangingConfigurations;
mSegSegGap = orig.mSegSegGap;
mSegPointGap = orig.mSegPointGap;
- mStrokeWidth = orig.mStrokeWidth;
- mStrokeColor = orig.mStrokeColor;
- mFadedStrokeColor = orig.mFadedStrokeColor;
- mStrokeDashWidth = orig.mStrokeDashWidth;
- mStrokeDashGap = orig.mStrokeDashGap;
+ mSegmentHeight = orig.mSegmentHeight;
+ mFadedSegmentHeight = orig.mFadedSegmentHeight;
+ mSegmentCornerRadius = orig.mSegmentCornerRadius;
+ mSegmentColor = orig.mSegmentColor;
+ mFadedSegmentColor = orig.mFadedSegmentColor;
mPointRadius = orig.mPointRadius;
mPointRectInset = orig.mPointRectInset;
mPointRectCornerRadius = orig.mPointRectCornerRadius;
@@ -721,17 +680,17 @@ public final class NotificationProgressDrawable extends Drawable {
}
private void applyDensityScaling(int sourceDensity, int targetDensity) {
- if (mStrokeWidth > 0) {
- mStrokeWidth = scaleFromDensity(
- mStrokeWidth, sourceDensity, targetDensity, true);
+ if (mSegmentHeight > 0) {
+ mSegmentHeight = scaleFromDensity(
+ mSegmentHeight, sourceDensity, targetDensity);
}
- if (mStrokeDashWidth > 0) {
- mStrokeDashWidth = scaleFromDensity(
- mStrokeDashWidth, sourceDensity, targetDensity);
+ if (mFadedSegmentHeight > 0) {
+ mFadedSegmentHeight = scaleFromDensity(
+ mFadedSegmentHeight, sourceDensity, targetDensity);
}
- if (mStrokeDashGap > 0) {
- mStrokeDashGap = scaleFromDensity(
- mStrokeDashGap, sourceDensity, targetDensity);
+ if (mSegmentCornerRadius > 0) {
+ mSegmentCornerRadius = scaleFromDensity(
+ mSegmentCornerRadius, sourceDensity, targetDensity);
}
if (mPointRadius > 0) {
mPointRadius = scaleFromDensity(
@@ -788,17 +747,9 @@ public final class NotificationProgressDrawable extends Drawable {
}
}
- public void setStroke(int width, int color, float dashWidth, float dashGap) {
- mStrokeWidth = width;
- mStrokeDashWidth = dashWidth;
- mStrokeDashGap = dashGap;
-
- setStrokeColor(color);
- }
-
- public void setStrokeColor(int color) {
- mStrokeColor = color;
- mFadedStrokeColor = getFadedColor(color);
+ public void setSegmentColor(int color) {
+ mSegmentColor = color;
+ mFadedSegmentColor = getFadedColor(color);
}
public void setPointRectColor(int color) {
@@ -808,11 +759,14 @@ public final class NotificationProgressDrawable extends Drawable {
}
/**
- * Get a color with an opacity that's 50% of the input color.
+ * Get a color with an opacity that's 25% of the input color.
*/
@ColorInt
static int getFadedColor(@ColorInt int color) {
- return Color.argb(Color.alpha(color) / 2, Color.red(color), Color.green(color),
+ return Color.argb(
+ (int) (Color.alpha(color) * 0.25f + 0.5f),
+ Color.red(color),
+ Color.green(color),
Color.blue(color));
}
@@ -836,15 +790,6 @@ public final class NotificationProgressDrawable extends Drawable {
}
private void updateLocalState() {
- final State state = mState;
-
- mStrokePaint.setStrokeWidth(state.mStrokeWidth);
- mDashedStrokePaint.setStrokeWidth(state.mStrokeWidth);
-
- if (state.mStrokeDashWidth != 0.0f) {
- final DashPathEffect e = new DashPathEffect(
- new float[] { state.mStrokeDashWidth, state.mStrokeDashGap }, 0);
- mDashedStrokePaint.setPathEffect(e);
- }
+ // NO-OP
}
}
diff --git a/core/java/com/android/internal/widget/NotificationRowIconView.java b/core/java/com/android/internal/widget/NotificationRowIconView.java
index 5fc61b00e331..c96e979138dd 100644
--- a/core/java/com/android/internal/widget/NotificationRowIconView.java
+++ b/core/java/com/android/internal/widget/NotificationRowIconView.java
@@ -19,12 +19,7 @@ package com.android.internal.widget;
import android.annotation.Nullable;
import android.app.Flags;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
@@ -41,7 +36,6 @@ import android.widget.RemoteViews;
public class NotificationRowIconView extends CachingIconView {
private NotificationIconProvider mIconProvider;
- private boolean mApplyCircularCrop = false;
private Drawable mAppIcon = null;
// Padding, background and colors set on the view prior to being overridden when showing the app
@@ -221,84 +215,6 @@ public class NotificationRowIconView extends CachingIconView {
}
}
- @Nullable
- @Override
- Drawable loadSizeRestrictedIcon(@Nullable Icon icon) {
- final Drawable original = super.loadSizeRestrictedIcon(icon);
- final Drawable result;
- if (mApplyCircularCrop) {
- result = makeCircularDrawable(original);
- } else {
- result = original;
- }
-
- return result;
- }
-
- /**
- * Enables circle crop that makes given image circular
- */
- @RemotableViewMethod(asyncImpl = "setApplyCircularCropAsync")
- public void setApplyCircularCrop(boolean applyCircularCrop) {
- mApplyCircularCrop = applyCircularCrop;
- }
-
- /**
- * Async version of {@link NotificationRowIconView#setApplyCircularCrop}
- */
- public Runnable setApplyCircularCropAsync(boolean applyCircularCrop) {
- mApplyCircularCrop = applyCircularCrop;
- return () -> {
- };
- }
-
- @Nullable
- private Drawable makeCircularDrawable(@Nullable Drawable original) {
- if (original == null) {
- return original;
- }
-
- final Bitmap source = drawableToBitmap(original);
-
- int size = Math.min(source.getWidth(), source.getHeight());
-
- Bitmap squared = Bitmap.createScaledBitmap(source, size, size, /* filter= */ false);
- Bitmap result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
-
- final Canvas canvas = new Canvas(result);
- final Paint paint = new Paint();
- paint.setShader(
- new BitmapShader(squared, BitmapShader.TileMode.CLAMP,
- BitmapShader.TileMode.CLAMP));
- paint.setAntiAlias(true);
- float radius = size / 2f;
- canvas.drawCircle(radius, radius, radius, paint);
- return new BitmapDrawable(getResources(), result);
- }
-
- private static Bitmap drawableToBitmap(Drawable drawable) {
- if (drawable instanceof BitmapDrawable bitmapDrawable) {
- final Bitmap bitmap = bitmapDrawable.getBitmap();
- if (bitmap.getConfig() == Bitmap.Config.HARDWARE) {
- return bitmap.copy(Bitmap.Config.ARGB_8888, false);
- } else {
- return bitmap;
- }
- }
-
- int width = drawable.getIntrinsicWidth();
- width = width > 0 ? width : 1;
- int height = drawable.getIntrinsicHeight();
- height = height > 0 ? height : 1;
-
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
-
- return bitmap;
- }
-
/**
* A provider that allows this view to verify whether it should use the app icon instead of the
* icon provided to it via setImageIcon, as well as actually fetching the app icon. It should
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java
index 244bb3d6380b..b5d389540185 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core;
+import android.annotation.NonNull;
+
import java.util.List;
/** Interface for the companion operations */
@@ -25,5 +27,5 @@ public interface CompanionOperation {
* @param buffer data to read to create operation
* @param operations command is to be added
*/
- void read(WireBuffer buffer, List<Operation> operations);
+ void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index 0761a244b9f2..370289a84502 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -19,6 +19,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.IntegerExpression;
import com.android.internal.widget.remotecompose.core.operations.NamedVariable;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
@@ -53,15 +54,16 @@ public class CoreDocument {
private static final boolean DEBUG = false;
- ArrayList<Operation> mOperations;
+ @NonNull ArrayList<Operation> mOperations = new ArrayList<>();
@Nullable RootLayoutComponent mRootLayoutComponent = null;
- RemoteComposeState mRemoteComposeState = new RemoteComposeState();
+ @NonNull RemoteComposeState mRemoteComposeState = new RemoteComposeState();
@NonNull TimeVariables mTimeVariables = new TimeVariables();
// Semantic version of the document
@NonNull Version mVersion = new Version(0, 1, 0);
+ @Nullable
String mContentDescription; // text description of the document (used for accessibility)
long mRequiredCapabilities = 0L; // bitmask indicating needed capabilities of the player(unused)
@@ -74,19 +76,22 @@ public class CoreDocument {
int mContentAlignment = RootContentBehavior.ALIGNMENT_CENTER;
- RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(mRemoteComposeState);
+ @NonNull RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(mRemoteComposeState);
private final HashMap<Long, IntegerExpression> mIntegerExpressions = new HashMap<>();
+ private final HashMap<Integer, FloatExpression> mFloatExpressions = new HashMap<>();
+
private HashSet<Component> mAppliedTouchOperations = new HashSet<>();
private int mLastId = 1; // last component id when inflating the file
+ @Nullable
public String getContentDescription() {
return mContentDescription;
}
- public void setContentDescription(String contentDescription) {
+ public void setContentDescription(@Nullable String contentDescription) {
this.mContentDescription = contentDescription;
}
@@ -116,19 +121,21 @@ public class CoreDocument {
mRemoteComposeState.setWindowHeight(height);
}
+ @NonNull
public RemoteComposeBuffer getBuffer() {
return mBuffer;
}
- public void setBuffer(RemoteComposeBuffer buffer) {
+ public void setBuffer(@NonNull RemoteComposeBuffer buffer) {
this.mBuffer = buffer;
}
+ @NonNull
public RemoteComposeState getRemoteComposeState() {
return mRemoteComposeState;
}
- public void setRemoteComposeState(RemoteComposeState remoteComposeState) {
+ public void setRemoteComposeState(@NonNull RemoteComposeState remoteComposeState) {
this.mRemoteComposeState = remoteComposeState;
}
@@ -171,7 +178,7 @@ public class CoreDocument {
* @param h vertical dimension of the rendering area
* @param scaleOutput will contain the computed scale factor
*/
- public void computeScale(float w, float h, float[] scaleOutput) {
+ public void computeScale(float w, float h, @NonNull float[] scaleOutput) {
float contentScaleX = 1f;
float contentScaleY = 1f;
if (mContentSizing == RootContentBehavior.SIZING_SCALE) {
@@ -236,7 +243,11 @@ public class CoreDocument {
* @param translateOutput will contain the computed translation
*/
private void computeTranslate(
- float w, float h, float contentScaleX, float contentScaleY, float[] translateOutput) {
+ float w,
+ float h,
+ float contentScaleX,
+ float contentScaleY,
+ @NonNull float[] translateOutput) {
int horizontalContentAlignment = mContentAlignment & 0xF0;
int verticalContentAlignment = mContentAlignment & 0xF;
float translateX = 0f;
@@ -350,6 +361,22 @@ public class CoreDocument {
}
}
+ /**
+ * Execute an integer expression with the given id and put its value on the targetId
+ *
+ * @param expressionId the id of the integer expression
+ * @param targetId the id of the value to update with the expression
+ * @param context the current context
+ */
+ public void evaluateFloatExpression(
+ int expressionId, int targetId, @NonNull RemoteContext context) {
+ FloatExpression expression = mFloatExpressions.get(expressionId);
+ if (expression != null) {
+ float v = expression.evaluate(context);
+ context.overrideFloat(targetId, v);
+ }
+ }
+
// ============== Haptic support ==================
public interface HapticEngine {
void haptic(int type);
@@ -375,7 +402,7 @@ public class CoreDocument {
/** Callback interface for host actions */
public interface ActionCallback {
- void onAction(String name, Object value);
+ void onAction(@NonNull String name, Object value);
}
@NonNull HashSet<ActionCallback> mActionListeners = new HashSet<ActionCallback>();
@@ -386,7 +413,7 @@ public class CoreDocument {
* @param name the action name
* @param value a parameter to the action
*/
- public void runNamedAction(String name, Object value) {
+ public void runNamedAction(@NonNull String name, Object value) {
// TODO: we might add an interface to group all valid parameter types
for (ActionCallback callback : mActionListeners) {
callback.onAction(name, value);
@@ -398,7 +425,7 @@ public class CoreDocument {
*
* @param callback
*/
- public void addActionCallback(ActionCallback callback) {
+ public void addActionCallback(@NonNull ActionCallback callback) {
mActionListeners.add(callback);
}
@@ -408,7 +435,7 @@ public class CoreDocument {
}
public interface ClickCallbacks {
- void click(int id, String metadata);
+ void click(int id, @Nullable String metadata);
}
@NonNull HashSet<ClickCallbacks> mClickListeners = new HashSet<>();
@@ -429,21 +456,21 @@ public class CoreDocument {
public static class ClickAreaRepresentation {
int mId;
- String mContentDescription;
+ @Nullable final String mContentDescription;
float mLeft;
float mTop;
float mRight;
float mBottom;
- String mMetadata;
+ @Nullable final String mMetadata;
public ClickAreaRepresentation(
int id,
- String contentDescription,
+ @Nullable String contentDescription,
float left,
float top,
float right,
float bottom,
- String metadata) {
+ @Nullable String metadata) {
this.mId = id;
this.mContentDescription = contentDescription;
this.mLeft = left;
@@ -484,10 +511,11 @@ public class CoreDocument {
return mId;
}
- public String getContentDescription() {
+ public @Nullable String getContentDescription() {
return mContentDescription;
}
+ @Nullable
public String getMetadata() {
return mMetadata;
}
@@ -502,6 +530,10 @@ public class CoreDocument {
IntegerExpression expression = (IntegerExpression) op;
mIntegerExpressions.put((long) expression.mId, expression);
}
+ if (op instanceof FloatExpression) {
+ FloatExpression expression = (FloatExpression) op;
+ mFloatExpressions.put(expression.mId, expression);
+ }
}
mOperations = inflateComponents(mOperations);
mBuffer = buffer;
@@ -605,7 +637,8 @@ public class CoreDocument {
@NonNull private HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>();
- private void registerVariables(RemoteContext context, @NonNull ArrayList<Operation> list) {
+ private void registerVariables(
+ @NonNull RemoteContext context, @NonNull ArrayList<Operation> list) {
for (Operation op : list) {
if (op instanceof VariableSupport) {
((VariableSupport) op).updateVariables(context);
@@ -701,12 +734,12 @@ public class CoreDocument {
*/
public void addClickArea(
int id,
- String contentDescription,
+ @Nullable String contentDescription,
float left,
float top,
float right,
float bottom,
- String metadata) {
+ @Nullable String metadata) {
mClickAreas.add(
new ClickAreaRepresentation(
id, contentDescription, left, top, right, bottom, metadata));
@@ -726,7 +759,7 @@ public class CoreDocument {
*
* @param callback called when a click area has been hit, passing the click are id and metadata.
*/
- public void addClickListener(ClickCallbacks callback) {
+ public void addClickListener(@NonNull ClickCallbacks callback) {
mClickListeners.add(callback);
}
@@ -744,7 +777,7 @@ public class CoreDocument {
* Passing a click event to the document. This will possibly result in calling the click
* listeners.
*/
- public void onClick(RemoteContext context, float x, float y) {
+ public void onClick(@NonNull RemoteContext context, float x, float y) {
for (ClickAreaRepresentation clickArea : mClickAreas) {
if (clickArea.contains(x, y)) {
warnClickListeners(clickArea);
@@ -802,6 +835,14 @@ public class CoreDocument {
for (TouchListener clickArea : mTouchListeners) {
clickArea.touchDrag(context, x, y);
}
+ if (mRootLayoutComponent != null) {
+ for (Component component : mAppliedTouchOperations) {
+ component.onTouchDrag(context, this, x, y, true);
+ }
+ if (!mAppliedTouchOperations.isEmpty()) {
+ return true;
+ }
+ }
if (!mTouchListeners.isEmpty()) {
return true;
}
@@ -940,6 +981,7 @@ public class CoreDocument {
*/
public void paint(@NonNull RemoteContext context, int theme) {
context.getPaintContext().clearNeedsRepaint();
+ context.loadFloat(RemoteContext.ID_DENSITY, context.getDensity());
context.mMode = RemoteContext.ContextMode.UNSET;
// current theme starts as UNSPECIFIED, until a Theme setter
// operation gets executed and modify it.
@@ -1097,6 +1139,7 @@ public class CoreDocument {
}
}
+ @NonNull
public List<Operation> getOperations() {
return mOperations;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operation.java b/core/java/com/android/internal/widget/remotecompose/core/Operation.java
index f1885f942ee1..102003e2e371 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operation.java
@@ -15,22 +15,22 @@
*/
package com.android.internal.widget.remotecompose.core;
-import android.annotation.Nullable;
+import android.annotation.NonNull;
/** Base interface for RemoteCompose operations */
public interface Operation {
/** add the operation to the buffer */
- void write(WireBuffer buffer);
+ void write(@NonNull WireBuffer buffer);
/**
* paint an operation
*
* @param context the paint context used to paint the operation
*/
- void apply(RemoteContext context);
+ void apply(@NonNull RemoteContext context);
/** Debug utility to display an operation + indentation */
- @Nullable
- String deepToString(String indent);
+ @NonNull
+ String deepToString(@NonNull String indent);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 53c45fac826c..687a99baff83 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -98,7 +98,9 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatChangeActionOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatExpressionChangeActionOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueIntegerChangeActionOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueIntegerExpressionChangeActionOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueStringChangeActionOperation;
@@ -214,6 +216,7 @@ public class Operations {
public static final int MODIFIER_OFFSET = 221;
public static final int MODIFIER_ZINDEX = 223;
public static final int MODIFIER_GRAPHICS_LAYER = 224;
+ public static final int MODIFIER_SCROLL = 226;
public static final int LOOP_START = 215;
public static final int LOOP_END = 216;
@@ -226,6 +229,7 @@ public class Operations {
public static final int VALUE_STRING_CHANGE_ACTION = 213;
public static final int VALUE_INTEGER_EXPRESSION_CHANGE_ACTION = 218;
public static final int VALUE_FLOAT_CHANGE_ACTION = 222;
+ public static final int VALUE_FLOAT_EXPRESSION_CHANGE_ACTION = 227;
public static final int ANIMATION_SPEC = 14;
@@ -235,7 +239,7 @@ public class Operations {
static class UniqueIntMap<T> extends IntMap<T> {
@Override
- public T put(int key, T value) {
+ public T put(int key, @NonNull T value) {
assert null == get(key) : "Opcode " + key + " already used in Operations !";
return super.put(key, value);
}
@@ -316,6 +320,7 @@ public class Operations {
map.put(MODIFIER_OFFSET, OffsetModifierOperation::read);
map.put(MODIFIER_ZINDEX, ZIndexModifierOperation::read);
map.put(MODIFIER_GRAPHICS_LAYER, GraphicsLayerModifierOperation::read);
+ map.put(MODIFIER_SCROLL, ScrollModifierOperation::read);
map.put(OPERATIONS_LIST_END, OperationsListEnd::read);
@@ -327,6 +332,9 @@ public class Operations {
ValueIntegerExpressionChangeActionOperation::read);
map.put(VALUE_STRING_CHANGE_ACTION, ValueStringChangeActionOperation::read);
map.put(VALUE_FLOAT_CHANGE_ACTION, ValueFloatChangeActionOperation::read);
+ map.put(
+ VALUE_FLOAT_EXPRESSION_CHANGE_ACTION,
+ ValueFloatExpressionChangeActionOperation::read);
map.put(LAYOUT_ROOT, RootLayoutComponent::read);
map.put(LAYOUT_CONTENT, LayoutComponentContent::read);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
index 1a71afe068bd..38b08e9b0ab3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
/** Specify an abstract paint context used by RemoteCompose commands to draw */
@@ -22,9 +24,10 @@ public abstract class PaintContext {
public static final int TEXT_MEASURE_MONOSPACE_WIDTH = 0x01;
public static final int TEXT_MEASURE_FONT_HEIGHT = 0x02;
- protected RemoteContext mContext;
+ protected @NonNull RemoteContext mContext;
private boolean mNeedsRepaint = false;
+ @NonNull
public RemoteContext getContext() {
return mContext;
}
@@ -37,11 +40,11 @@ public abstract class PaintContext {
mNeedsRepaint = false;
}
- public PaintContext(RemoteContext context) {
+ public PaintContext(@NonNull RemoteContext context) {
this.mContext = context;
}
- public void setContext(RemoteContext context) {
+ public void setContext(@NonNull RemoteContext context) {
this.mContext = context;
}
@@ -117,7 +120,8 @@ public abstract class PaintContext {
* descent of the font (not just of the measured text)
* @param bounds the bounds (left, top, right, bottom)
*/
- public abstract void getTextBounds(int textId, int start, int end, int flags, float[] bounds);
+ public abstract void getTextBounds(
+ int textId, int start, int end, int flags, @NonNull float[] bounds);
/**
* Draw a text starting ast x,y
@@ -158,7 +162,7 @@ public abstract class PaintContext {
*
* @param mPaintData the list of changes
*/
- public abstract void applyPaint(PaintBundle mPaintData);
+ public abstract void applyPaint(@NonNull PaintBundle mPaintData);
/**
* Scale the rendering by scaleX and saleY (1.0 = no scale). Scaling is done about
@@ -264,7 +268,7 @@ public abstract class PaintContext {
*
* @param content the content to log
*/
- public void log(String content) {
+ public void log(@NonNull String content) {
System.out.println("[LOG] " + content);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
index 049e47744ce8..9999182b53fc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
@@ -35,17 +35,17 @@ public abstract class PaintOperation implements Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
- public abstract void paint(PaintContext context);
+ public abstract void paint(@NonNull PaintContext context);
/**
* Will return true if the operation is similar enough to the current one, in the context of an
* animated transition.
*/
- public boolean suitableForTransition(Operation op) {
+ public boolean suitableForTransition(@NonNull Operation op) {
// by default expects the op to not be suitable
return false;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Platform.java b/core/java/com/android/internal/widget/remotecompose/core/Platform.java
index 7fbcfae54bcb..dcb8efebeecc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Platform.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Platform.java
@@ -15,19 +15,20 @@
*/
package com.android.internal.widget.remotecompose.core;
+import android.annotation.NonNull;
import android.annotation.Nullable;
/** Services that are needed to be provided by the platform during encoding. */
public interface Platform {
@Nullable
- byte[] imageToByteArray(Object image);
+ byte[] imageToByteArray(@NonNull Object image);
- int getImageWidth(Object image);
+ int getImageWidth(@NonNull Object image);
- int getImageHeight(Object image);
+ int getImageHeight(@NonNull Object image);
@Nullable
- float[] pathToFloatArray(Object path);
+ float[] pathToFloatArray(@NonNull Object path);
enum LogCategory {
DEBUG,
@@ -42,22 +43,22 @@ public interface Platform {
Platform None =
new Platform() {
@Override
- public byte[] imageToByteArray(Object image) {
+ public byte[] imageToByteArray(@NonNull Object image) {
throw new UnsupportedOperationException();
}
@Override
- public int getImageWidth(Object image) {
+ public int getImageWidth(@NonNull Object image) {
throw new UnsupportedOperationException();
}
@Override
- public int getImageHeight(Object image) {
+ public int getImageHeight(@NonNull Object image) {
throw new UnsupportedOperationException();
}
@Override
- public float[] pathToFloatArray(Object path) {
+ public float[] pathToFloatArray(@NonNull Object path) {
throw new UnsupportedOperationException();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index 7d9439dd186b..c05079e34505 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.widget.remotecompose.core;
+import static com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression.ADD;
+import static com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression.MUL;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -89,6 +92,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
@@ -117,9 +121,9 @@ public class RemoteComposeBuffer {
public static final int EASING_SPLINE_CUSTOM = FloatAnimation.SPLINE_CUSTOM;
public static final int EASING_EASE_OUT_BOUNCE = FloatAnimation.EASE_OUT_BOUNCE;
public static final int EASING_EASE_OUT_ELASTIC = FloatAnimation.EASE_OUT_ELASTIC;
- WireBuffer mBuffer = new WireBuffer();
- @Nullable Platform mPlatform = null;
- RemoteComposeState mRemoteComposeState;
+ private @NonNull WireBuffer mBuffer = new WireBuffer();
+ @Nullable private Platform mPlatform = null;
+ @NonNull private final RemoteComposeState mRemoteComposeState;
private static final boolean DEBUG = false;
private int mLastComponentId = 0;
@@ -130,7 +134,7 @@ public class RemoteComposeBuffer {
*
* @param remoteComposeState the state used while encoding on the buffer
*/
- public RemoteComposeBuffer(RemoteComposeState remoteComposeState) {
+ public RemoteComposeBuffer(@NonNull RemoteComposeState remoteComposeState) {
this.mRemoteComposeState = remoteComposeState;
}
@@ -155,15 +159,15 @@ public class RemoteComposeBuffer {
return mPlatform;
}
- public void setPlatform(Platform platform) {
+ public void setPlatform(@NonNull Platform platform) {
this.mPlatform = platform;
}
- public WireBuffer getBuffer() {
+ public @NonNull WireBuffer getBuffer() {
return mBuffer;
}
- public void setBuffer(WireBuffer buffer) {
+ public void setBuffer(@NonNull WireBuffer buffer) {
this.mBuffer = buffer;
}
@@ -200,7 +204,7 @@ public class RemoteComposeBuffer {
* @param height the height of the document in pixels
* @param contentDescription content description of the document
*/
- public void header(int width, int height, String contentDescription) {
+ public void header(int width, int height, @Nullable String contentDescription) {
header(width, height, contentDescription, 1f, 0);
}
@@ -220,7 +224,7 @@ public class RemoteComposeBuffer {
* @param dstBottom bottom coordinate of the destination area
*/
public void drawBitmap(
- Object image,
+ @NonNull Object image,
int imageWidth,
int imageHeight,
int srcLeft,
@@ -235,8 +239,9 @@ public class RemoteComposeBuffer {
int imageId = mRemoteComposeState.dataGetId(image);
if (imageId == -1) {
imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image);
- BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data);
+ byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
+ BitmapData.apply(
+ mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe
}
int contentDescriptionId = 0;
if (contentDescription != null) {
@@ -387,7 +392,7 @@ public class RemoteComposeBuffer {
* @param contentDescription content description of the image
*/
public void addDrawBitmap(
- Object image,
+ @NonNull Object image,
float left,
float top,
float right,
@@ -396,11 +401,12 @@ public class RemoteComposeBuffer {
int imageId = mRemoteComposeState.dataGetId(image);
if (imageId == -1) {
imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image);
+ byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
int imageWidth = mPlatform.getImageWidth(image);
int imageHeight = mPlatform.getImageHeight(image);
- BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data);
+ BitmapData.apply(
+ mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe
}
int contentDescriptionId = 0;
if (contentDescription != null) {
@@ -446,7 +452,7 @@ public class RemoteComposeBuffer {
* @param contentDescription associate a string with image for accessibility
*/
public void drawScaledBitmap(
- Object image,
+ @NonNull Object image,
float srcLeft,
float srcTop,
float srcRight,
@@ -461,11 +467,11 @@ public class RemoteComposeBuffer {
int imageId = mRemoteComposeState.dataGetId(image);
if (imageId == -1) {
imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image);
+ byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
int imageWidth = mPlatform.getImageWidth(image);
int imageHeight = mPlatform.getImageHeight(image);
- BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data);
+ BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential pe
}
int contentDescriptionId = 0;
if (contentDescription != null) {
@@ -493,11 +499,11 @@ public class RemoteComposeBuffer {
* @param image drawScaledBitmap
* @return id of the image useful with
*/
- public int addBitmap(Object image) {
+ public int addBitmap(@NonNull Object image) {
int imageId = mRemoteComposeState.dataGetId(image);
if (imageId == -1) {
imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image);
+ byte[] data = mPlatform.imageToByteArray(image); // tODO: potential npe
int imageWidth = mPlatform.getImageWidth(image);
int imageHeight = mPlatform.getImageHeight(image);
@@ -512,11 +518,11 @@ public class RemoteComposeBuffer {
* @param image drawScaledBitmap
* @return id of the image useful with
*/
- public int addBitmap(Object image, @NonNull String name) {
+ public int addBitmap(@NonNull Object image, @NonNull String name) {
int imageId = mRemoteComposeState.dataGetId(image);
if (imageId == -1) {
imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image);
+ byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
int imageWidth = mPlatform.getImageWidth(image);
int imageHeight = mPlatform.getImageHeight(image);
@@ -629,7 +635,7 @@ public class RemoteComposeBuffer {
*
* @param path The path to be drawn
*/
- public void addDrawPath(Object path) {
+ public void addDrawPath(@NonNull Object path) {
int id = mRemoteComposeState.dataGetId(path);
if (id == -1) { // never been seen before
id = addPathData(path);
@@ -681,7 +687,8 @@ public class RemoteComposeBuffer {
* @param hOffset The distance along the path to add to the text's starting position
* @param vOffset The distance above(-) or below(+) the path to position the text
*/
- public void addDrawTextOnPath(@NonNull String text, Object path, float hOffset, float vOffset) {
+ public void addDrawTextOnPath(
+ @NonNull String text, @NonNull Object path, float hOffset, float vOffset) {
int pathId = mRemoteComposeState.dataGetId(path);
if (pathId == -1) { // never been seen before
pathId = addPathData(path);
@@ -752,7 +759,7 @@ public class RemoteComposeBuffer {
* <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y
* </ul>
*
- * Setting panY to NaN results in y being the baseline of the text.
+ * <p>Setting panY to NaN results in y being the baseline of the text.
*
* @param text text to draw
* @param x Coordinate of the Anchor
@@ -836,7 +843,7 @@ public class RemoteComposeBuffer {
* <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y
* </ul>
*
- * Setting panY to NaN results in y being the baseline of the text.
+ * <p>Setting panY to NaN results in y being the baseline of the text.
*
* @param textId text to draw
* @param x Coordinate of the Anchor
@@ -861,7 +868,8 @@ public class RemoteComposeBuffer {
* @param start The start of the subrange of paths to draw 0 = start form start 0.5 is half way
* @param stop The end of the subrange of paths to draw 1 = end at the end 0.5 is end half way
*/
- public void addDrawTweenPath(Object path1, Object path2, float tween, float start, float stop) {
+ public void addDrawTweenPath(
+ @NonNull Object path1, @NonNull Object path2, float tween, float start, float stop) {
int path1Id = mRemoteComposeState.dataGetId(path1);
if (path1Id == -1) { // never been seen before
path1Id = addPathData(path1);
@@ -892,7 +900,7 @@ public class RemoteComposeBuffer {
* @param path
* @return the id of the path on the wire
*/
- public int addPathData(Object path) {
+ public int addPathData(@NonNull Object path) {
float[] pathData = mPlatform.pathToFloatArray(path);
int id = mRemoteComposeState.cacheData(path);
PathData.apply(mBuffer, id, pathData);
@@ -910,7 +918,7 @@ public class RemoteComposeBuffer {
///////////////////////////////////////////////////////////////////////////////////////////////
- public void inflateFromBuffer(ArrayList<Operation> operations) {
+ public void inflateFromBuffer(@NonNull ArrayList<Operation> operations) {
mBuffer.setIndex(0);
while (mBuffer.available()) {
int opId = mBuffer.readByte();
@@ -926,7 +934,7 @@ public class RemoteComposeBuffer {
}
public static void readNextOperation(
- @NonNull WireBuffer buffer, ArrayList<Operation> operations) {
+ @NonNull WireBuffer buffer, @NonNull ArrayList<Operation> operations) {
int opId = buffer.readByte();
if (DEBUG) {
Utils.log(">> " + opId);
@@ -957,15 +965,16 @@ public class RemoteComposeBuffer {
@NonNull
public static RemoteComposeBuffer fromFile(
- @NonNull String path, RemoteComposeState remoteComposeState) throws IOException {
+ @NonNull String path, @NonNull RemoteComposeState remoteComposeState)
+ throws IOException {
RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState);
read(new File(path), buffer);
return buffer;
}
@NonNull
- public RemoteComposeBuffer fromFile(@NonNull File file, RemoteComposeState remoteComposeState)
- throws IOException {
+ public RemoteComposeBuffer fromFile(
+ @NonNull File file, @NonNull RemoteComposeState remoteComposeState) throws IOException {
RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState);
read(file, buffer);
return buffer;
@@ -973,7 +982,7 @@ public class RemoteComposeBuffer {
@NonNull
public static RemoteComposeBuffer fromInputStream(
- @NonNull InputStream inputStream, RemoteComposeState remoteComposeState) {
+ @NonNull InputStream inputStream, @NonNull RemoteComposeState remoteComposeState) {
RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState);
read(inputStream, buffer);
return buffer;
@@ -1205,6 +1214,7 @@ public class RemoteComposeBuffer {
/**
* Add a touch handle system
*
+ * @param id the float NaN id used for the returned position
* @param value the default value
* @param min the minimum value
* @param max the maximum value
@@ -1213,9 +1223,9 @@ public class RemoteComposeBuffer {
* @param touchMode the touch up handling behaviour
* @param touchSpec the touch up handling parameters
* @param easingSpec the easing parameter TODO support in v2
- * @return id of the variable to be used controlled by touch handling
*/
- public float addTouchExpression(
+ public void addTouchExpression(
+ float id,
float value,
float min,
float max,
@@ -1225,9 +1235,45 @@ public class RemoteComposeBuffer {
int touchMode,
float[] touchSpec,
float[] easingSpec) {
- int id = mRemoteComposeState.nextId();
TouchExpression.apply(
mBuffer,
+ Utils.idFromNan(id),
+ value,
+ min,
+ max,
+ velocityId,
+ touchEffects,
+ exp,
+ touchMode,
+ touchSpec,
+ easingSpec);
+ }
+
+ /**
+ * Add a touch handle system
+ *
+ * @param value the default value
+ * @param min the minimum value
+ * @param max the maximum value
+ * @param velocityId the id for the velocity TODO support in v2
+ * @param exp The Float Expression
+ * @param touchMode the touch up handling behaviour
+ * @param touchSpec the touch up handling parameters
+ * @param easingSpec the easing parameter TODO support in v2
+ * @return id of the variable to be used controlled by touch handling
+ */
+ public float addTouchExpression(
+ float value,
+ float min,
+ float max,
+ float velocityId,
+ int touchEffects,
+ float[] exp,
+ int touchMode,
+ float[] touchSpec,
+ float[] easingSpec) {
+ float id = Utils.asNan(mRemoteComposeState.nextId());
+ addTouchExpression(
id,
value,
min,
@@ -1238,7 +1284,7 @@ public class RemoteComposeBuffer {
touchMode,
touchSpec,
easingSpec);
- return Utils.asNan(id);
+ return id;
}
/**
@@ -1248,7 +1294,7 @@ public class RemoteComposeBuffer {
* @param animation Array of floats that represents animation
* @return NaN id of the result of the calculation
*/
- public float addAnimatedFloat(@NonNull float[] value, float[] animation) {
+ public float addAnimatedFloat(@NonNull float[] value, @Nullable float[] animation) {
int id = mRemoteComposeState.cacheData(value);
FloatExpression.apply(mBuffer, id, value, animation);
return Utils.asNan(id);
@@ -1345,7 +1391,7 @@ public class RemoteComposeBuffer {
* @param listId
* @return the id of the map, encoded as a float NaN
*/
- public int addMap(@NonNull String[] keys, byte[] types, int[] listId) {
+ public int addMap(@NonNull String[] keys, @Nullable byte[] types, @NonNull int[] listId) {
int id = mRemoteComposeState.cacheData(listId, NanMap.TYPE_ARRAY);
DataMapIds.apply(mBuffer, id, keys, types, listId);
return id;
@@ -1354,14 +1400,18 @@ public class RemoteComposeBuffer {
/**
* This provides access to text in RemoteList
*
+ * <p>TODO: do we want both a float and an int index version of this method? bbade@ TODO
+ * for @hoford - add a unit test for this method
+ *
* @param dataSet
* @param index index as a float variable
* @return
*/
public int textLookup(float dataSet, float index) {
long hash =
- ((long) Float.floatToRawIntBits(dataSet))
- << (32 + Float.floatToRawIntBits(index)); // TODO: is this the correct ()s?
+ (((long) Float.floatToRawIntBits(dataSet)) << 32)
+ + Float.floatToRawIntBits(
+ index); // TODO: is this the correct ()s? -- bbade@
int id = mRemoteComposeState.cacheData(hash);
TextLookup.apply(mBuffer, id, Utils.idFromNan(dataSet), index);
return id;
@@ -1370,14 +1420,16 @@ public class RemoteComposeBuffer {
/**
* This provides access to text in RemoteList
*
+ * <p>TODO for hoford - add a unit test for this method
+ *
* @param dataSet
* @param index index as an int variable
* @return
*/
public int textLookup(float dataSet, int index) {
long hash =
- ((long) Float.floatToRawIntBits(dataSet))
- << (32 + Float.floatToRawIntBits(index)); // TODO: is this the correct ()s?
+ (((long) Float.floatToRawIntBits(dataSet)) << 32)
+ + Float.floatToRawIntBits(index); // TODO: is this the correct ()s?
int id = mRemoteComposeState.cacheData(hash);
TextLookupInt.apply(mBuffer, id, Utils.idFromNan(dataSet), index);
return id;
@@ -1521,8 +1573,8 @@ public class RemoteComposeBuffer {
* @param wrap the wraps value so (e.g 360 so angles 355 would animate to 5)
* @return
*/
- public static float[] packAnimation(
- float duration, int type, float[] spec, float initialValue, float wrap) {
+ public static @NonNull float[] packAnimation(
+ float duration, int type, @Nullable float[] spec, float initialValue, float wrap) {
return FloatAnimation.packToFloatArray(duration, type, spec, initialValue, wrap);
}
@@ -1591,6 +1643,43 @@ public class RemoteComposeBuffer {
}
/**
+ * Add a scroll modifier
+ *
+ * @param direction HORIZONTAL(0) or VERTICAL(1)
+ * @param positionId the position id as a NaN
+ * @param notches
+ */
+ public void addModifierScroll(int direction, float positionId, int notches) {
+ // TODO: add support for non-notch behaviors etc.
+ float max = this.addFloat(0f);
+ float notchMax = this.addFloat(0f);
+ float touchExpressionDirection =
+ direction != 0 ? RemoteContext.FLOAT_TOUCH_POS_X : RemoteContext.FLOAT_TOUCH_POS_Y;
+ this.addTouchExpression(
+ positionId,
+ 0f,
+ 0f,
+ max,
+ 0f,
+ 3,
+ new float[] {
+ touchExpressionDirection,
+ -1,
+ // TODO: remove this CONTINUOUS_SEC hack...
+ MUL,
+ RemoteContext.FLOAT_CONTINUOUS_SEC,
+ 0f,
+ MUL,
+ ADD
+ },
+ TouchExpression.STOP_NOTCHES_EVEN,
+ new float[] {notches, notchMax},
+ null);
+
+ ScrollModifierOperation.apply(mBuffer, direction, positionId, max, notchMax);
+ }
+
+ /**
* Add a background modifier of provided color
*
* @param color the color of the background
@@ -1869,4 +1958,8 @@ public class RemoteComposeBuffer {
public int createID(int type) {
return mRemoteComposeState.nextId(type);
}
+
+ public int nextId() {
+ return mRemoteComposeState.nextId();
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index 303932814909..a903e6ee1f27 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -49,7 +49,7 @@ public class RemoteComposeState implements CollectionsAccess {
private final IntMap<Object> mObjectMap = new IntMap<>();
private final boolean[] mColorOverride = new boolean[MAX_COLORS];
- private final IntMap<ArrayAccess> mCollectionMap = new IntMap<>();
+ @NonNull private final IntMap<ArrayAccess> mCollectionMap = new IntMap<>();
private final boolean[] mDataOverride = new boolean[MAX_DATA];
private final boolean[] mIntegerOverride = new boolean[MAX_DATA];
@@ -82,7 +82,7 @@ public class RemoteComposeState implements CollectionsAccess {
}
/** Return the id of an item from the cache. */
- public int dataGetId(Object data) {
+ public int dataGetId(@NonNull Object data) {
Integer res = mDataIntMap.get(data);
if (res == null) {
return -1;
@@ -94,7 +94,7 @@ public class RemoteComposeState implements CollectionsAccess {
* Add an item to the cache. Generates an id for the item and adds it to the cache based on that
* id.
*/
- public int cacheData(Object item) {
+ public int cacheData(@NonNull Object item) {
int id = nextId();
mDataIntMap.put(item, id);
mIntDataMap.put(id, item);
@@ -105,7 +105,7 @@ public class RemoteComposeState implements CollectionsAccess {
* Add an item to the cache. Generates an id for the item and adds it to the cache based on that
* id.
*/
- public int cacheData(Object item, int type) {
+ public int cacheData(@NonNull Object item, int type) {
int id = nextId(type);
mDataIntMap.put(item, id);
mIntDataMap.put(id, item);
@@ -113,13 +113,13 @@ public class RemoteComposeState implements CollectionsAccess {
}
/** Insert an item in the cache */
- public void cacheData(int id, Object item) {
+ public void cacheData(int id, @NonNull Object item) {
mDataIntMap.put(item, id);
mIntDataMap.put(id, item);
}
/** Insert an item in the cache */
- public void updateData(int id, Object item) {
+ public void updateData(int id, @NonNull Object item) {
if (!mDataOverride[id]) {
Object previous = mIntDataMap.get(id);
if (previous != item) {
@@ -137,7 +137,7 @@ public class RemoteComposeState implements CollectionsAccess {
* @param id
* @param item the new value
*/
- public void overrideData(int id, Object item) {
+ public void overrideData(int id, @NonNull Object item) {
Object previous = mIntDataMap.get(id);
if (previous != item) {
mDataIntMap.remove(previous);
@@ -379,7 +379,7 @@ public class RemoteComposeState implements CollectionsAccess {
@NonNull IntMap<ArrayList<VariableSupport>> mVarListeners = new IntMap<>();
@NonNull ArrayList<VariableSupport> mAllVarListeners = new ArrayList<>();
- private void add(int id, VariableSupport variableSupport) {
+ private void add(int id, @NonNull VariableSupport variableSupport) {
ArrayList<VariableSupport> v = mVarListeners.get(id);
if (v == null) {
v = new ArrayList<VariableSupport>();
@@ -395,17 +395,27 @@ public class RemoteComposeState implements CollectionsAccess {
* @param id
* @param variableSupport
*/
- public void listenToVar(int id, VariableSupport variableSupport) {
+ public void listenToVar(int id, @NonNull VariableSupport variableSupport) {
add(id, variableSupport);
}
/**
+ * Is any command listening to this variable
+ *
+ * @param id
+ * @return
+ */
+ public boolean hasListener(int id) {
+ return mVarListeners.get(id) != null;
+ }
+
+ /**
* List of Commands that need to be updated
*
* @param context
* @return
*/
- public int getOpsToUpdate(RemoteContext context) {
+ public int getOpsToUpdate(@NonNull RemoteContext context) {
for (VariableSupport vs : mAllVarListeners) {
vs.updateVariables(context);
}
@@ -439,18 +449,18 @@ public class RemoteComposeState implements CollectionsAccess {
updateFloat(RemoteContext.ID_WINDOW_HEIGHT, height);
}
- public void addCollection(int id, ArrayAccess collection) {
+ public void addCollection(int id, @NonNull ArrayAccess collection) {
mCollectionMap.put(id & 0xFFFFF, collection);
}
@Override
public float getFloatValue(int id, int index) {
- return mCollectionMap.get(id & 0xFFFFF).getFloatValue(index);
+ return mCollectionMap.get(id & 0xFFFFF).getFloatValue(index); // TODO: potential npe
}
@Override
- public float[] getFloats(int id) {
- return mCollectionMap.get(id & 0xFFFFF).getFloats();
+ public @Nullable float[] getFloats(int id) {
+ return mCollectionMap.get(id & 0xFFFFF).getFloats(); // TODO: potential npe
}
@Override
@@ -458,11 +468,11 @@ public class RemoteComposeState implements CollectionsAccess {
return mCollectionMap.get(id & 0xFFFFF).getId(index);
}
- public void putDataMap(int id, DataMap map) {
+ public void putDataMap(int id, @NonNull DataMap map) {
mDataMapMap.put(id, map);
}
- public DataMap getDataMap(int id) {
+ public @Nullable DataMap getDataMap(int id) {
return mDataMapMap.get(id);
}
@@ -471,15 +481,15 @@ public class RemoteComposeState implements CollectionsAccess {
return mCollectionMap.get(id & 0xFFFFF).getLength();
}
- public void setContext(RemoteContext context) {
+ public void setContext(@NonNull RemoteContext context) {
mRemoteContext = context;
}
- public void updateObject(int id, Object value) {
+ public void updateObject(int id, @NonNull Object value) {
mObjectMap.put(id, value);
}
- public Object getObject(int id) {
+ public @Nullable Object getObject(int id) {
return mObjectMap.get(id);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index 23cc5b89d916..26305bf124f7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.widget.remotecompose.core;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
@@ -39,13 +40,15 @@ import java.time.ZoneOffset;
* <p>We also contain a PaintContext, so that any operation can draw as needed.
*/
public abstract class RemoteContext {
- protected CoreDocument mDocument;
- public RemoteComposeState mRemoteComposeState;
+ protected @NonNull CoreDocument mDocument =
+ new CoreDocument(); // todo: is this a valid way to initialize? bbade@
+ public @NonNull RemoteComposeState mRemoteComposeState =
+ new RemoteComposeState(); // todo, is this a valid use of RemoteComposeState -- bbade@
long mStart = System.nanoTime(); // todo This should be set at a hi level
@Nullable protected PaintContext mPaintContext = null;
protected float mDensity = 2.75f;
- ContextMode mMode = ContextMode.UNSET;
+ @NonNull ContextMode mMode = ContextMode.UNSET;
int mDebug = 0;
@@ -57,7 +60,7 @@ public abstract class RemoteContext {
private boolean mAnimate = true;
- public Component lastComponent;
+ public @Nullable Component mLastComponent;
public long currentTime = 0L;
public float getDensity() {
@@ -65,7 +68,9 @@ public abstract class RemoteContext {
}
public void setDensity(float density) {
- mDensity = density;
+ if (density > 0) {
+ mDensity = density;
+ }
}
public boolean isAnimationEnabled() {
@@ -81,7 +86,7 @@ public abstract class RemoteContext {
*
* @return the CollectionsAccess implementation
*/
- public CollectionsAccess getCollectionsAccess() {
+ public @Nullable CollectionsAccess getCollectionsAccess() {
return mRemoteComposeState;
}
@@ -91,7 +96,7 @@ public abstract class RemoteContext {
* @param instanceId
* @param floatPath
*/
- public abstract void loadPathData(int instanceId, float[] floatPath);
+ public abstract void loadPathData(int instanceId, @NonNull float[] floatPath);
/**
* Associate a name with a give id.
@@ -100,7 +105,7 @@ public abstract class RemoteContext {
* @param varId the id (color,integer,float etc.)
* @param varType thetype
*/
- public abstract void loadVariableName(String varName, int varId, int varType);
+ public abstract void loadVariableName(@NonNull String varName, int varId, int varType);
/**
* Save a color under a given id
@@ -135,7 +140,7 @@ public abstract class RemoteContext {
* @param colorName the name of the color to override
* @param color Override the default color
*/
- public abstract void setNamedColorOverride(String colorName, int color);
+ public abstract void setNamedColorOverride(@NonNull String colorName, int color);
/**
* Set the value of a named String. This overrides the string in the document
@@ -143,7 +148,7 @@ public abstract class RemoteContext {
* @param stringName the name of the string to override
* @param value Override the default string
*/
- public abstract void setNamedStringOverride(String stringName, String value);
+ public abstract void setNamedStringOverride(@NonNull String stringName, @NonNull String value);
/**
* Allows to clear a named String.
@@ -152,7 +157,7 @@ public abstract class RemoteContext {
*
* @param stringName the name of the string to override
*/
- public abstract void clearNamedStringOverride(String stringName);
+ public abstract void clearNamedStringOverride(@NonNull String stringName);
/**
* Set the value of a named Integer. This overrides the integer in the document
@@ -160,7 +165,7 @@ public abstract class RemoteContext {
* @param integerName the name of the integer to override
* @param value Override the default integer
*/
- public abstract void setNamedIntegerOverride(String integerName, int value);
+ public abstract void setNamedIntegerOverride(@NonNull String integerName, int value);
/**
* Allows to clear a named Integer.
@@ -169,7 +174,7 @@ public abstract class RemoteContext {
*
* @param integerName the name of the integer to override
*/
- public abstract void clearNamedIntegerOverride(String integerName);
+ public abstract void clearNamedIntegerOverride(@NonNull String integerName);
/**
* Support Collections by registering this collection
@@ -177,20 +182,20 @@ public abstract class RemoteContext {
* @param id id of the collection
* @param collection the collection under this id
*/
- public abstract void addCollection(int id, ArrayAccess collection);
+ public abstract void addCollection(int id, @NonNull ArrayAccess collection);
- public abstract void putDataMap(int id, DataMap map);
+ public abstract void putDataMap(int id, @NonNull DataMap map);
- public abstract DataMap getDataMap(int id);
+ public abstract @Nullable DataMap getDataMap(int id);
- public abstract void runAction(int id, String metadata);
+ public abstract void runAction(int id, @NonNull String metadata);
// TODO: we might add an interface to group all valid parameter types
public abstract void runNamedAction(int textId, Object value);
- public abstract void putObject(int mId, Object command);
+ public abstract void putObject(int mId, @NonNull Object command);
- public abstract Object getObject(int mId);
+ public abstract @Nullable Object getObject(int mId);
public void addTouchListener(TouchListener touchExpression) {}
@@ -220,11 +225,11 @@ public abstract class RemoteContext {
this.mTheme = theme;
}
- public ContextMode getMode() {
+ public @NonNull ContextMode getMode() {
return mMode;
}
- public void setMode(ContextMode mode) {
+ public void setMode(@NonNull ContextMode mode) {
this.mMode = mode;
}
@@ -233,11 +238,11 @@ public abstract class RemoteContext {
return mPaintContext;
}
- public void setPaintContext(PaintContext paintContext) {
+ public void setPaintContext(@NonNull PaintContext paintContext) {
this.mPaintContext = paintContext;
}
- public CoreDocument getDocument() {
+ public @Nullable CoreDocument getDocument() {
return mDocument;
}
@@ -253,7 +258,7 @@ public abstract class RemoteContext {
this.mDebug = debug;
}
- public void setDocument(CoreDocument document) {
+ public void setDocument(@NonNull CoreDocument document) {
this.mDocument = document;
}
@@ -310,11 +315,14 @@ public abstract class RemoteContext {
* Save a bitmap under an imageId
*
* @param imageId the id of the image
+ * @param encoding how the data is encoded 0 = png, 1 = raw, 2 = url
+ * @param type the type of the data 0 = RGBA 8888, 1 = 888, 2 = 8 gray
* @param width the width of the image
* @param height the height of the image
* @param bitmap the bytes that represent the image
*/
- public abstract void loadBitmap(int imageId, int width, int height, byte[] bitmap);
+ public abstract void loadBitmap(
+ int imageId, short encoding, short type, int width, int height, @NonNull byte[] bitmap);
/**
* Save a string under a given id
@@ -322,7 +330,7 @@ public abstract class RemoteContext {
* @param id the id of the string
* @param text the value to set
*/
- public abstract void loadText(int id, String text);
+ public abstract void loadText(int id, @NonNull String text);
/**
* Get a string given an id
@@ -330,7 +338,7 @@ public abstract class RemoteContext {
* @param id the id of the string
* @return
*/
- public abstract String getText(int id);
+ public abstract @Nullable String getText(int id);
/**
* Load a float
@@ -373,12 +381,12 @@ public abstract class RemoteContext {
public abstract void overrideText(int id, int valueId);
/**
- * Load an animated float associated with an id Todo: Remove?
+ * Load an animated float associated with an id Todo: Remove? cc @hoford
*
* @param id the id of the float
* @param animatedFloat The animated float
*/
- public abstract void loadAnimatedFloat(int id, FloatExpression animatedFloat);
+ public abstract void loadAnimatedFloat(int id, @NonNull FloatExpression animatedFloat);
/**
* Save a shader under and ID
@@ -386,7 +394,7 @@ public abstract class RemoteContext {
* @param id the id of the Shader
* @param value the shader
*/
- public abstract void loadShader(int id, ShaderData value);
+ public abstract void loadShader(int id, @NonNull ShaderData value);
/**
* Get a float given an id
@@ -418,7 +426,7 @@ public abstract class RemoteContext {
* @param id track when this id changes value
* @param variableSupport call back when value changes
*/
- public abstract void listensTo(int id, VariableSupport variableSupport);
+ public abstract void listensTo(int id, @NonNull VariableSupport variableSupport);
/**
* Notify commands with variables have changed
@@ -433,6 +441,7 @@ public abstract class RemoteContext {
* @param id get a shader given the id
* @return The shader
*/
+ @Nullable
public abstract ShaderData getShader(int id);
public static final int ID_CONTINUOUS_SEC = 1;
@@ -467,6 +476,10 @@ public abstract class RemoteContext {
public static final int ID_LIGHT = 26;
+ public static final int ID_DENSITY = 27;
+
+ public static final float FLOAT_DENSITY = Utils.asNan(ID_DENSITY);
+
/** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */
public static final float FLOAT_CONTINUOUS_SEC = Utils.asNan(ID_CONTINUOUS_SEC);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java b/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java
index 8f9741dd4195..79ac789a454e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java
@@ -15,8 +15,10 @@
*/
package com.android.internal.widget.remotecompose.core;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
public interface SerializableToString {
- void serializeToString(int indent, StringSerializer serializer);
+ void serializeToString(int indent, @NonNull StringSerializer serializer);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
index 51e58a1aeddd..e9fa8976637e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core;
+import android.annotation.NonNull;
+
/**
* Interface for operators that interact with variables Through this they register to listen to
* particular variables and are notified when they change
@@ -26,12 +28,12 @@ public interface VariableSupport {
*
* @param context
*/
- void registerListening(RemoteContext context);
+ void registerListening(@NonNull RemoteContext context);
/**
* Called to be notified that the variables you are interested have changed.
*
* @param context
*/
- void updateVariables(RemoteContext context);
+ void updateVariables(@NonNull RemoteContext context);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java
index 738e42baae0b..a64b706fea3b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java
@@ -23,7 +23,7 @@ import java.util.Arrays;
public class WireBuffer {
private static final int BUFFER_SIZE = 1024 * 1024 * 1;
int mMaxSize;
- byte[] mBuffer;
+ @NonNull byte[] mBuffer;
int mIndex = 0;
int mStartingIndex = 0;
int mSize = 0;
@@ -44,7 +44,7 @@ public class WireBuffer {
}
}
- public byte[] getBuffer() {
+ public @NonNull byte[] getBuffer() {
return mBuffer;
}
@@ -168,14 +168,14 @@ public class WireBuffer {
return java.lang.Double.longBitsToDouble(readLong());
}
- public byte[] readBuffer() {
+ public @NonNull byte[] readBuffer() {
int count = readInt();
byte[] b = Arrays.copyOfRange(mBuffer, mIndex, mIndex + count);
mIndex += count;
return b;
}
- public byte[] readBuffer(int maxSize) {
+ public @NonNull byte[] readBuffer(int maxSize) {
int count = readInt();
if (count < 0 || count > maxSize) {
throw new RuntimeException(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java
index f6dfe2ebe171..0174ce531d3f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java
@@ -15,10 +15,14 @@
*/
package com.android.internal.widget.remotecompose.core.documentation;
+import android.annotation.NonNull;
+
public interface DocumentationBuilder {
- void add(String value);
+ void add(@NonNull String value);
- DocumentedOperation operation(String category, int id, String name);
+ @NonNull
+ DocumentedOperation operation(@NonNull String category, int id, @NonNull String name);
- DocumentedOperation wipOperation(String category, int id, String name);
+ @NonNull
+ DocumentedOperation wipOperation(@NonNull String category, int id, @NonNull String name);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java
index 4b84291aa5fe..2806a5e1ad1d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.documentation;
+import android.annotation.NonNull;
+
public interface DocumentedCompanionOperation {
- void documentation(DocumentationBuilder doc);
+ void documentation(@NonNull DocumentationBuilder doc);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java
index 5edecaa01f82..bfab62365736 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java
@@ -16,6 +16,7 @@
package com.android.internal.widget.remotecompose.core.documentation;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import java.util.ArrayList;
@@ -34,13 +35,13 @@ public class DocumentedOperation {
public static final int FLOAT_ARRAY = 10;
public static final int INT_ARRAY = 11;
- String mCategory;
+ @NonNull final String mCategory;
int mId;
- String mName;
- String mDescription;
+ @NonNull final String mName;
+ @NonNull String mDescription = "";
boolean mWIP;
- String mTextExamples;
+ @Nullable String mTextExamples;
@NonNull ArrayList<StringPair> mExamples = new ArrayList<>();
@NonNull ArrayList<OperationField> mFields = new ArrayList<>();
@@ -77,14 +78,15 @@ public class DocumentedOperation {
return "UNKNOWN";
}
- public DocumentedOperation(String category, int id, String name, boolean wip) {
+ public DocumentedOperation(
+ @NonNull String category, int id, @NonNull String name, boolean wip) {
mCategory = category;
mId = id;
mName = name;
mWIP = wip;
}
- public DocumentedOperation(String category, int id, String name) {
+ public DocumentedOperation(@NonNull String category, int id, @NonNull String name) {
this(category, id, name, false);
}
@@ -93,7 +95,7 @@ public class DocumentedOperation {
return mFields;
}
- public String getCategory() {
+ public @NonNull String getCategory() {
return mCategory;
}
@@ -101,6 +103,7 @@ public class DocumentedOperation {
return mId;
}
+ @NonNull
public String getName() {
return mName;
}
@@ -126,10 +129,12 @@ public class DocumentedOperation {
return size;
}
+ @Nullable
public String getDescription() {
return mDescription;
}
+ @Nullable
public String getTextExamples() {
return mTextExamples;
}
@@ -148,19 +153,20 @@ public class DocumentedOperation {
}
@NonNull
- public DocumentedOperation field(int type, String name, String description) {
+ public DocumentedOperation field(int type, @NonNull String name, @NonNull String description) {
mFields.add(new OperationField(type, name, description));
return this;
}
@NonNull
- public DocumentedOperation field(int type, String name, String varSize, String description) {
+ public DocumentedOperation field(
+ int type, @NonNull String name, @NonNull String varSize, @NonNull String description) {
mFields.add(new OperationField(type, name, varSize, description));
return this;
}
@NonNull
- public DocumentedOperation possibleValues(String name, int value) {
+ public DocumentedOperation possibleValues(@NonNull String name, int value) {
if (!mFields.isEmpty()) {
mFields.get(mFields.size() - 1).possibleValue(name, "" + value);
}
@@ -168,19 +174,19 @@ public class DocumentedOperation {
}
@NonNull
- public DocumentedOperation description(String description) {
+ public DocumentedOperation description(@NonNull String description) {
mDescription = description;
return this;
}
@NonNull
- public DocumentedOperation examples(String examples) {
+ public DocumentedOperation examples(@NonNull String examples) {
mTextExamples = examples;
return this;
}
@NonNull
- public DocumentedOperation exampleImage(String name, String imagePath) {
+ public DocumentedOperation exampleImage(@NonNull String name, @NonNull String imagePath) {
mExamples.add(new StringPair(name, imagePath));
return this;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java
index cbb5ca9821c3..9febcfe57047 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java
@@ -21,20 +21,21 @@ import android.annotation.Nullable;
import java.util.ArrayList;
public class OperationField {
- int mType;
- String mName;
- String mDescription;
+ final int mType;
+ @NonNull final String mName;
+ @NonNull final String mDescription;
@Nullable String mVarSize = null;
@NonNull ArrayList<StringPair> mPossibleValues = new ArrayList<>();
- public OperationField(int type, String name, String description) {
+ public OperationField(int type, @NonNull String name, @NonNull String description) {
mType = type;
mName = name;
mDescription = description;
}
- public OperationField(int type, String name, String varSize, String description) {
+ public OperationField(
+ int type, @NonNull String name, @Nullable String varSize, @NonNull String description) {
mType = type;
mName = name;
mDescription = description;
@@ -45,10 +46,12 @@ public class OperationField {
return mType;
}
+ @NonNull
public String getName() {
return mName;
}
+ @NonNull
public String getDescription() {
return mDescription;
}
@@ -58,7 +61,7 @@ public class OperationField {
return mPossibleValues;
}
- public void possibleValue(String name, String value) {
+ public void possibleValue(@NonNull String name, @NonNull String value) {
mPossibleValues.add(new StringPair(name, value));
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java
index 5b0cedbaf6af..c1d885806b44 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java
@@ -15,20 +15,22 @@
*/
package com.android.internal.widget.remotecompose.core.documentation;
+import android.annotation.NonNull;
+
public class StringPair {
- String mName;
- String mValue;
+ final @NonNull String mName;
+ final @NonNull String mValue;
- StringPair(String name, String value) {
+ StringPair(@NonNull String name, @NonNull String value) {
mName = name;
mValue = value;
}
- public String getName() {
+ public @NonNull String getName() {
return mName;
}
- public String getValue() {
+ public @NonNull String getValue() {
return mValue;
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
index 8da0e184cbe7..948007699b80 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
@@ -17,6 +17,7 @@ package com.android.internal.widget.remotecompose.core.operations;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY;
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT;
import android.annotation.NonNull;
@@ -41,10 +42,19 @@ public class BitmapData implements Operation, SerializableToString {
int mImageId;
int mImageWidth;
int mImageHeight;
- byte[] mBitmap;
+ short mType;
+ short mEncoding;
+ @NonNull final byte[] mBitmap;
public static final int MAX_IMAGE_DIMENSION = 8000;
-
- public BitmapData(int imageId, int width, int height, byte[] bitmap) {
+ public static final short ENCODING_INLINE = 0;
+ public static final short ENCODING_URL = 1;
+ public static final short ENCODING_FILE = 2;
+ public static final short TYPE_PNG_8888 = 0;
+ public static final short TYPE_PNG = 1;
+ public static final short TYPE_RAW8 = 2;
+ public static final short TYPE_RAW8888 = 3;
+
+ public BitmapData(int imageId, int width, int height, @NonNull byte[] bitmap) {
this.mImageId = imageId;
this.mImageWidth = width;
this.mImageHeight = height;
@@ -92,6 +102,23 @@ public class BitmapData implements Operation, SerializableToString {
buffer.writeBuffer(bitmap);
}
+ public static void apply(
+ @NonNull WireBuffer buffer,
+ int imageId,
+ short type,
+ short width,
+ short encoding,
+ short height,
+ @NonNull byte[] bitmap) {
+ buffer.start(OP_CODE);
+ buffer.writeInt(imageId);
+ int w = (((int) type) << 16) | width;
+ int h = (((int) encoding) << 16) | height;
+ buffer.writeInt(w);
+ buffer.writeInt(h);
+ buffer.writeBuffer(bitmap);
+ }
+
public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
int imageId = buffer.readInt();
int width = buffer.readInt();
@@ -110,19 +137,22 @@ public class BitmapData implements Operation, SerializableToString {
doc.operation("Data Operations", OP_CODE, CLASS_NAME)
.description("Bitmap data")
.field(DocumentedOperation.INT, "id", "id of bitmap data")
+ .field(SHORT, "type", "width of the image")
+ .field(SHORT, "width", "width of the image")
+ .field(SHORT, "encoding", "height of the image")
.field(INT, "width", "width of the image")
- .field(INT, "height", "height of the image")
+ .field(SHORT, "height", "height of the image")
.field(INT_ARRAY, "values", "length", "Array of ints");
}
@Override
public void apply(@NonNull RemoteContext context) {
- context.loadBitmap(mImageId, mImageWidth, mImageHeight, mBitmap);
+ context.loadBitmap(mImageId, mEncoding, mType, mImageWidth, mImageHeight, mBitmap);
}
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
index 83d0ac7a1eb2..310b194ec486 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
@@ -109,7 +109,7 @@ public class ClickArea implements RemoteComposeOperation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
index 929c9a603079..34e93f590dbe 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
@@ -93,7 +93,7 @@ public class ColorConstant implements Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
index 3d840c5b8203..c947d1139a2e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
@@ -255,7 +255,7 @@ public class ColorExpression implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
index 142c97b24d2e..b0ccd1871fd2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -75,7 +74,7 @@ public class ComponentValue implements Operation, SerializableToString {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
// Nothing
}
@@ -123,9 +122,9 @@ public class ComponentValue implements Operation, SerializableToString {
buffer.writeInt(valueId);
}
- @Nullable
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return null;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
index ba02b91b36ed..bfaf139da21b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
@@ -35,17 +35,17 @@ import java.util.List;
public class DataListFloat implements VariableSupport, ArrayAccess, Operation {
private static final int OP_CODE = Operations.FLOAT_LIST;
private static final String CLASS_NAME = "IdListData";
- int mId;
- float[] mValues;
+ private final int mId;
+ @NonNull private final float[] mValues;
private static final int MAX_FLOAT_ARRAY = 2000;
- public DataListFloat(int id, float[] values) {
+ public DataListFloat(int id, @NonNull float[] values) {
mId = id;
mValues = values;
}
@Override
- public void updateVariables(RemoteContext context) {
+ public void updateVariables(@NonNull RemoteContext context) {
// TODO add support for variables in arrays
}
@@ -103,7 +103,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
@@ -117,6 +117,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation {
return mValues[index];
}
+ @NonNull
@Override
public float[] getFloats() {
return mValues;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
index b9820f856a92..9b286b94d553 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
@@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -35,20 +36,20 @@ import java.util.List;
public class DataListIds implements VariableSupport, ArrayAccess, Operation {
private static final int OP_CODE = Operations.ID_LIST;
private static final String CLASS_NAME = "IdListData";
- int mId;
- int[] mIds;
+ private final int mId;
+ @NonNull private final int[] mIds;
private static final int MAX_LIST = 2000;
- public DataListIds(int id, int[] ids) {
+ public DataListIds(int id, @NonNull int[] ids) {
mId = id;
mIds = ids;
}
@Override
- public void updateVariables(RemoteContext context) {}
+ public void updateVariables(@NonNull RemoteContext context) {}
@Override
- public void registerListening(RemoteContext context) {}
+ public void registerListening(@NonNull RemoteContext context) {}
@Override
public void write(@NonNull WireBuffer buffer) {
@@ -94,7 +95,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
@@ -113,6 +114,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation {
return mIds[index];
}
+ @Nullable
@Override
public float[] getFloats() {
return null;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
index fb559bbf1863..643afc85e69f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
@@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -34,7 +35,7 @@ public class DataMapIds implements Operation {
private static final int OP_CODE = Operations.ID_MAP;
private static final String CLASS_NAME = "DataMapIds";
int mId;
- DataMap mDataMap;
+ final DataMap mDataMap;
private static final int MAX_MAP = 2000;
@@ -44,6 +45,7 @@ public class DataMapIds implements Operation {
public static final byte TYPE_LONG = 3;
public static final byte TYPE_BOOLEAN = 4;
+ @NonNull
private String typeString(byte type) {
switch (type) {
case TYPE_STRING:
@@ -60,7 +62,7 @@ public class DataMapIds implements Operation {
return "?";
}
- public DataMapIds(int id, String[] names, byte[] types, int[] ids) {
+ public DataMapIds(int id, @NonNull String[] names, @NonNull byte[] types, @NonNull int[] ids) {
mId = id;
mDataMap = new DataMap(names, types, ids);
}
@@ -88,7 +90,11 @@ public class DataMapIds implements Operation {
}
public static void apply(
- @NonNull WireBuffer buffer, int id, @NonNull String[] names, byte[] type, int[] ids) {
+ @NonNull WireBuffer buffer,
+ int id,
+ @NonNull String[] names,
+ @Nullable byte[] type, // todo: can we make this not nullable?
+ @NonNull int[] ids) {
buffer.start(OP_CODE);
buffer.writeInt(id);
buffer.writeInt(names.length);
@@ -128,7 +134,7 @@ public class DataMapIds implements Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java
index fb5e5d1734e6..eae532c14344 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java
@@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -50,10 +52,11 @@ public class DataMapLookup implements Operation {
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
apply(buffer, mId, mDataMapId, mStringId);
}
+ @NonNull
@Override
public String toString() {
return "DataMapLookup[" + mId + "] = " + Utils.idString(mDataMapId) + " " + mStringId;
@@ -64,6 +67,7 @@ public class DataMapLookup implements Operation {
*
* @return the name of the class
*/
+ @NonNull
public static String name() {
return CLASS_NAME;
}
@@ -85,7 +89,7 @@ public class DataMapLookup implements Operation {
* @param dataMapId the map to extract from
* @param keyStringId the map to extract from
*/
- public static void apply(WireBuffer buffer, int id, int dataMapId, int keyStringId) {
+ public static void apply(@NonNull WireBuffer buffer, int id, int dataMapId, int keyStringId) {
buffer.start(OP_CODE);
buffer.writeInt(id);
buffer.writeInt(dataMapId);
@@ -98,14 +102,14 @@ public class DataMapLookup implements Operation {
* @param buffer buffer
* @param operations the created command is added to the list
*/
- public static void read(WireBuffer buffer, List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
int id = buffer.readInt();
int mapId = buffer.readInt();
int stringId = buffer.readInt();
operations.add(new DataMapLookup(id, mapId, stringId));
}
- public static void documentation(DocumentationBuilder doc) {
+ public static void documentation(@NonNull DocumentationBuilder doc) {
doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
.description("A float and its associated id")
.field(INT, "id", "id of float")
@@ -114,7 +118,7 @@ public class DataMapLookup implements Operation {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
String str = context.getText(mStringId);
DataMap data = context.getDataMap(mDataMapId);
int pos = data.getPos(str);
@@ -141,8 +145,9 @@ public class DataMapLookup implements Operation {
}
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
index 984599e09c19..c1e2e662ca80 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
@@ -60,11 +60,11 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
write(buffer, mV1, mV2);
}
- protected abstract void write(WireBuffer buffer, float v1, float v2);
+ protected abstract void write(@NonNull WireBuffer buffer, float v1, float v2);
protected interface Maker {
DrawBase2 create(float v1, float v2);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
index 825da5240032..6fedea3245a2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
@@ -70,11 +70,11 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
write(buffer, mV1, mV2, mV3);
}
- protected abstract void write(WireBuffer buffer, float v1, float v2, float v3);
+ protected abstract void write(@NonNull WireBuffer buffer, float v1, float v2, float v3);
interface Maker {
DrawBase3 create(float v1, float v2, float v3);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
index a23bcb9dca78..aa9cc68e6552 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
@@ -77,11 +77,12 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
write(buffer, mX1, mY1, mX2, mY2);
}
- protected abstract void write(WireBuffer buffer, float v1, float v2, float v3, float v4);
+ protected abstract void write(
+ @NonNull WireBuffer buffer, float v1, float v2, float v3, float v4);
protected interface Maker {
DrawBase4 create(float v1, float v2, float v3, float v4);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
index 68c9f8cdc462..6c288a35621d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
@@ -91,12 +91,12 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
write(buffer, mV1, mV2, mV3, mV4, mV5, mV6);
}
protected abstract void write(
- WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6);
+ @NonNull WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6);
@NonNull
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
index e20bcd2d79b5..e9f81d52d67f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
@@ -46,6 +46,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport
int mContentDescId;
float mScaleFactor, mOutScaleFactor;
int mScaleType;
+ int mMode;
@NonNull ImageScaling mScaling = new ImageScaling();
public static final int SCALE_NONE = ImageScaling.SCALE_NONE;
@@ -79,7 +80,8 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport
mOutDstTop = mDstTop = dstTop;
mOutDstRight = mDstRight = dstRight;
mOutDstBottom = mDstBottom = dstBottom;
- mScaleType = type;
+ mScaleType = type & 0xFF;
+ mMode = type >> 8;
mOutScaleFactor = mScaleFactor = scale;
this.mContentDescId = cdId;
}
@@ -308,8 +310,14 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport
mOutScaleFactor);
context.save();
context.clipRect(mOutDstLeft, mOutDstTop, mOutDstRight, mOutDstBottom);
+
+ int imageId = mImageId;
+ if ((mMode & 0x1) != 0) {
+ imageId = context.getContext().getInteger(imageId);
+ }
+
context.drawBitmap(
- mImageId,
+ imageId,
(int) mOutSrcLeft,
(int) mOutSrcTop,
(int) mOutSrcRight,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
index 89390acb8c50..17aaf3bb9cd8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
@@ -94,7 +94,7 @@ public class FloatConstant implements com.android.internal.widget.remotecompose.
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
index e1c6c2577860..eef9746ffaf6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -33,6 +33,7 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp
import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.SpringStopEngine;
import java.util.List;
@@ -45,21 +46,26 @@ public class FloatExpression implements Operation, VariableSupport {
private static final int OP_CODE = Operations.ANIMATED_FLOAT;
private static final String CLASS_NAME = "FloatExpression";
public int mId;
- public float[] mSrcValue;
- public float[] mSrcAnimation;
- public FloatAnimation mFloatAnimation;
- public float[] mPreCalcValue;
+ @NonNull public float[] mSrcValue;
+ @Nullable public float[] mSrcAnimation;
+ @Nullable public FloatAnimation mFloatAnimation;
+ @Nullable private SpringStopEngine mSpring;
+ @Nullable public float[] mPreCalcValue;
private float mLastChange = Float.NaN;
private float mLastCalculatedValue = Float.NaN;
@NonNull AnimatedFloatExpression mExp = new AnimatedFloatExpression();
public static final int MAX_EXPRESSION_SIZE = 32;
- public FloatExpression(int id, float[] value, float[] animation) {
+ public FloatExpression(int id, @NonNull float[] value, @Nullable float[] animation) {
this.mId = id;
this.mSrcValue = value;
this.mSrcAnimation = animation;
if (mSrcAnimation != null) {
- mFloatAnimation = new FloatAnimation(mSrcAnimation);
+ if (mSrcAnimation.length > 4 && mSrcAnimation[0] == 0) {
+ mSpring = new SpringStopEngine(mSrcAnimation);
+ } else {
+ mFloatAnimation = new FloatAnimation(mSrcAnimation);
+ }
}
}
@@ -75,12 +81,23 @@ public class FloatExpression implements Operation, VariableSupport {
if (Float.isNaN(v)
&& !AnimatedFloatExpression.isMathOperator(v)
&& !NanMap.isDataVariable(v)) {
+ int id = Utils.idFromNan(v);
float newValue = context.getFloat(Utils.idFromNan(v));
+
+ // TODO: rethink the lifecycle for variable updates
+ if (id == RemoteContext.ID_DENSITY && newValue == 0f) {
+ newValue = 1f;
+ }
if (mFloatAnimation != null) {
if (mPreCalcValue[i] != newValue) {
value_changed = true;
mPreCalcValue[i] = newValue;
}
+ } else if (mSpring != null) {
+ if (mPreCalcValue[i] != newValue) {
+ value_changed = true;
+ mPreCalcValue[i] = newValue;
+ }
} else {
mPreCalcValue[i] = newValue;
}
@@ -106,6 +123,8 @@ public class FloatExpression implements Operation, VariableSupport {
mFloatAnimation.setInitialValue(mFloatAnimation.getTargetValue());
}
mFloatAnimation.setTargetValue(v);
+ } else if (value_changed && mSpring != null) {
+ mSpring.setTargetValue(v);
}
}
@@ -130,6 +149,9 @@ public class FloatExpression implements Operation, VariableSupport {
if (mFloatAnimation != null) {
float f = mFloatAnimation.get(t - mLastChange);
context.loadFloat(mId, f);
+ } else if (mSpring != null) {
+ float f = mSpring.get(t - mLastChange);
+ context.loadFloat(mId, f);
} else {
context.loadFloat(
mId,
@@ -137,6 +159,21 @@ public class FloatExpression implements Operation, VariableSupport {
}
}
+ /**
+ * Evaluate the expression
+ *
+ * @param context current context
+ * @return the resulting value
+ */
+ public float evaluate(@NonNull RemoteContext context) {
+ updateVariables(context);
+ float t = context.getAnimationTime();
+ if (Float.isNaN(mLastChange)) {
+ mLastChange = t;
+ }
+ return mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length);
+ }
+
@Override
public void write(@NonNull WireBuffer buffer) {
apply(buffer, mId, mSrcValue, mSrcAnimation);
@@ -256,7 +293,7 @@ public class FloatExpression implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
index 1979bc5f4331..009aa0339625 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
@@ -111,7 +111,7 @@ public class Header implements RemoteComposeOperation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
index 6375f001c818..c49f74de7893 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
@@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -43,13 +44,13 @@ public class IntegerExpression implements Operation, VariableSupport {
public int mId;
private int mMask;
private int mPreMask;
- public int[] mSrcValue;
- public int[] mPreCalcValue;
+ @NonNull public final int[] mSrcValue;
+ @Nullable public int[] mPreCalcValue;
private float mLastChange = Float.NaN;
public static final int MAX_SIZE = 320;
@NonNull IntegerExpressionEvaluator mExp = new IntegerExpressionEvaluator();
- public IntegerExpression(int id, int mask, int[] value) {
+ public IntegerExpression(int id, int mask, @NonNull int[] value) {
this.mId = id;
this.mMask = mask;
this.mSrcValue = value;
@@ -188,7 +189,7 @@ public class IntegerExpression implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
index 6a620e58570a..4e7ee4d135ee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
@@ -37,7 +37,7 @@ public class MatrixRestore extends PaintOperation {
apply(buffer);
}
- public static void read(WireBuffer buffer, @NonNull List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
MatrixRestore op = new MatrixRestore();
operations.add(op);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
index 1880b19be1a7..09f54a52e6a3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
@@ -41,7 +41,7 @@ public class MatrixSave extends PaintOperation {
return "MatrixSave;";
}
- public static void read(WireBuffer buffer, @NonNull List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
MatrixSave op = new MatrixSave();
operations.add(op);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
index 6310521e4010..5ca91af91f86 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
@@ -33,16 +33,16 @@ import java.util.List;
public class NamedVariable implements Operation {
private static final int OP_CODE = Operations.NAMED_VARIABLE;
private static final String CLASS_NAME = "NamedVariable";
- public int mVarId;
- public String mVarName;
- public int mVarType;
+ public final int mVarId;
+ public final @NonNull String mVarName;
+ public final int mVarType;
public static final int MAX_STRING_SIZE = 4000;
public static final int COLOR_TYPE = 2;
public static final int FLOAT_TYPE = 1;
public static final int STRING_TYPE = 0;
public static final int IMAGE_TYPE = 3;
- public NamedVariable(int varId, int varType, String name) {
+ public NamedVariable(int varId, int varType, @NonNull String name) {
this.mVarId = varId;
this.mVarType = varType;
this.mVarName = name;
@@ -111,7 +111,7 @@ public class NamedVariable implements Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index 527d5610788c..b24df8a6a91e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -90,7 +90,7 @@ public class PaintData extends PaintOperation implements VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
index 06a1fec36196..509f362c02ed 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
@@ -73,7 +73,7 @@ public class PathData implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return pathString(mFloatPath);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
index 6ff9ad73e35f..849412618c2c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
@@ -196,7 +196,7 @@ public class RootContentBehavior implements RemoteComposeOperation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index c2d62a7b3ac4..109945f21ec5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -60,7 +60,7 @@ public class RootContentDescription implements RemoteComposeOperation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
index ae61c3aa01c9..e967ff4f4ff4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -48,7 +48,7 @@ public class ShaderData implements Operation, VariableSupport {
int mShaderID; // allows shaders to be referenced by number
@Nullable HashMap<String, float[]> mUniformRawFloatMap = null;
@Nullable HashMap<String, float[]> mUniformFloatMap = null;
- @Nullable HashMap<String, int[]> mUniformIntMap = null;
+ @Nullable HashMap<String, int[]> mUniformIntMap;
@Nullable HashMap<String, Integer> mUniformBitmapMap = null;
public ShaderData(
@@ -104,8 +104,8 @@ public class ShaderData implements Operation, VariableSupport {
* @param name name of uniform
* @return value of uniform
*/
- public float[] getUniformFloats(String name) {
- return mUniformFloatMap.get(name);
+ public @NonNull float[] getUniformFloats(@NonNull String name) {
+ return mUniformFloatMap != null ? mUniformFloatMap.get(name) : new float[0];
}
/**
@@ -125,8 +125,8 @@ public class ShaderData implements Operation, VariableSupport {
* @param name Name of uniform
* @return value of uniform
*/
- public int[] getUniformInts(String name) {
- return mUniformIntMap.get(name);
+ public @NonNull int[] getUniformInts(@NonNull String name) {
+ return mUniformIntMap != null ? mUniformIntMap.get(name) : new int[0];
}
/**
@@ -146,8 +146,10 @@ public class ShaderData implements Operation, VariableSupport {
* @param name Name of bitmap uniform
* @return Bitmap ID
*/
- public int getUniformBitmapId(String name) {
- return mUniformBitmapMap.get(name);
+ public int getUniformBitmapId(@NonNull String name) {
+ return mUniformBitmapMap != null
+ ? mUniformBitmapMap.get(name)
+ : -1; // TODO: what is the proper return value here? -- bbade@
}
@Override
@@ -169,7 +171,7 @@ public class ShaderData implements Operation, VariableSupport {
@Override
public void updateVariables(@NonNull RemoteContext context) {
- for (String name : mUniformRawFloatMap.keySet()) {
+ for (String name : mUniformRawFloatMap.keySet()) { // TODO: potential npe
float[] value = mUniformRawFloatMap.get(name);
float[] out = null;
for (int i = 0; i < value.length; i++) {
@@ -186,7 +188,7 @@ public class ShaderData implements Operation, VariableSupport {
@Override
public void registerListening(@NonNull RemoteContext context) {
- for (String name : mUniformRawFloatMap.keySet()) {
+ for (String name : mUniformRawFloatMap.keySet()) { // TODO: potential npe
float[] value = mUniformRawFloatMap.get(name);
for (float v : value) {
if (Float.isNaN(v)) {
@@ -340,7 +342,7 @@ public class ShaderData implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index dbaef7ef7ae1..ade008e3bdb4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -34,11 +34,11 @@ import java.util.List;
public class TextData implements Operation, SerializableToString {
private static final int OP_CODE = Operations.DATA_TEXT;
private static final String CLASS_NAME = "TextData";
- public int mTextId;
- public String mText;
+ public final int mTextId;
+ @NonNull public final String mText;
public static final int MAX_STRING_SIZE = 4000;
- public TextData(int textId, String text) {
+ public TextData(int textId, @NonNull String text) {
this.mTextId = textId;
this.mText = text;
}
@@ -90,7 +90,7 @@ public class TextData implements Operation, SerializableToString {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
index fb5087f3fee3..865ee81f2725 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
@@ -185,7 +185,7 @@ public class TextFromFloat implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java
index e148fb9849fc..6ff687b7494e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java
@@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -38,16 +40,17 @@ public class TextLength implements Operation {
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
apply(buffer, mLengthId, mTextId);
}
+ @NonNull
@Override
public String toString() {
return CLASS_NAME + "[" + mLengthId + "] = " + mTextId;
}
- public static String name() {
+ public static @NonNull String name() {
return CLASS_NAME;
}
@@ -62,19 +65,19 @@ public class TextLength implements Operation {
* @param lengthId the id to output
* @param textId the id of the text to measure
*/
- public static void apply(WireBuffer buffer, int lengthId, int textId) {
+ public static void apply(@NonNull WireBuffer buffer, int lengthId, int textId) {
buffer.start(OP_CODE);
buffer.writeInt(lengthId);
buffer.writeInt(textId);
}
- public static void read(WireBuffer buffer, List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
int lengthId = buffer.readInt();
int textId = buffer.readInt();
operations.add(new TextLength(lengthId, textId));
}
- public static void documentation(DocumentationBuilder doc) {
+ public static void documentation(@NonNull DocumentationBuilder doc) {
doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
.description("get the length of the text and store in float table")
.field(INT, "id", "id of float length")
@@ -82,12 +85,13 @@ public class TextLength implements Operation {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
context.loadFloat(mLengthId, context.getText(mTextId).length());
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
index 2129edde2f59..cc812a8e160e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
@@ -126,7 +126,7 @@ public class TextLookup implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
index ea550cbe010c..74be698872fa 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
@@ -119,7 +119,7 @@ public class TextLookupInt implements Operation, VariableSupport {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
index 0281d6980e0f..6d48f67ed8c8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
@@ -19,6 +19,8 @@ import static com.android.internal.widget.remotecompose.core.PaintContext.TEXT_M
import static com.android.internal.widget.remotecompose.core.PaintContext.TEXT_MEASURE_MONOSPACE_WIDTH;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
@@ -55,16 +57,16 @@ public class TextMeasure extends PaintOperation {
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
apply(buffer, mId, mTextId, mType);
}
@Override
- public String toString() {
+ public @NonNull String toString() {
return "FloatConstant[" + mId + "] = " + mTextId + " " + mType;
}
- public static String name() {
+ public static @NonNull String name() {
return CLASS_NAME;
}
@@ -80,21 +82,21 @@ public class TextMeasure extends PaintOperation {
* @param textId the id
* @param type the value of the float
*/
- public static void apply(WireBuffer buffer, int id, int textId, int type) {
+ public static void apply(@NonNull WireBuffer buffer, int id, int textId, int type) {
buffer.start(OP_CODE);
buffer.writeInt(id);
buffer.writeInt(textId);
buffer.writeInt(type);
}
- public static void read(WireBuffer buffer, List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
int id = buffer.readInt();
int textId = buffer.readInt();
int type = buffer.readInt();
operations.add(new TextMeasure(id, textId, type));
}
- public static void documentation(DocumentationBuilder doc) {
+ public static void documentation(@NonNull DocumentationBuilder doc) {
doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
.description("A float and its associated id")
.field(INT, "id", "id of float result of the measure")
@@ -102,15 +104,16 @@ public class TextMeasure extends PaintOperation {
.field(INT, "type", "type: measure 0=width,1=height");
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
- float[] mBounds = new float[4];
+ @NonNull float[] mBounds = new float[4];
@Override
- public void paint(PaintContext context) {
+ public void paint(@NonNull PaintContext context) {
int val = mType & 255;
int flags = mType >> 8;
context.getTextBounds(mTextId, 0, -1, flags, mBounds);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
index fa18b4ddb2a2..ecd5baaf0dd2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
@@ -102,7 +102,7 @@ public class TextMerge implements Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
index 1e90ab128e93..d265070a50bf 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
@@ -68,7 +68,7 @@ public class Theme implements RemoteComposeOperation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
index b25a7f6ea09d..1bb7b2a183a2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
@@ -20,6 +20,8 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -71,6 +73,7 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
boolean mWrapMode = false;
float[] mNotches;
float[] mStopSpec;
+ float[] mOutStopSpec;
int mTouchEffects;
float mVelocityId;
@@ -98,6 +101,9 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
mOutDefValue = mDefValue = defValue;
mMode = STOP_ABSOLUTE_POS == stopMode ? 1 : 0;
mOutMax = mMax = max;
+ if (stopSpec != null) {
+ mOutStopSpec = Arrays.copyOf(stopSpec, stopSpec.length);
+ }
mTouchEffects = touchEffects;
mVelocityId = velocityId;
if (Float.isNaN(min) && Utils.idFromNan(min) == 0) {
@@ -108,10 +114,8 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
mStopMode = stopMode;
mStopSpec = stopSpec;
if (easingSpec != null) {
- Utils.log("easingSpec " + Arrays.toString(easingSpec));
if (easingSpec.length >= 4) {
if (Float.floatToRawIntBits(easingSpec[0]) == 0) {
- Utils.log("easingSpec[2] " + easingSpec[2]);
mMaxTime = easingSpec[1];
mMaxAcceleration = easingSpec[2];
mMaxVelocity = easingSpec[3];
@@ -126,6 +130,9 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
if (mPreCalcValue == null || mPreCalcValue.length != mSrcExp.length) {
mPreCalcValue = new float[mSrcExp.length];
}
+ if (mOutStopSpec == null || mOutStopSpec.length != mStopSpec.length) {
+ mOutStopSpec = new float[mStopSpec.length];
+ }
if (Float.isNaN(mMax)) {
mOutMax = context.getFloat(Utils.idFromNan(mMax));
}
@@ -150,6 +157,15 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
mPreCalcValue[i] = mSrcExp[i];
}
}
+ for (int i = 0; i < mStopSpec.length; i++) {
+ float v = mStopSpec[i];
+ if (Float.isNaN(v)) {
+ float newValue = context.getFloat(Utils.idFromNan(v));
+ mOutStopSpec[i] = newValue;
+ } else {
+ mOutStopSpec[i] = v;
+ }
+ }
float v = mLastCalculatedValue;
if (value_changed) { // inputs changed check if output changed
v = mExp.eval(mPreCalcValue, mPreCalcValue.length);
@@ -181,6 +197,11 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
context.listensTo(Utils.idFromNan(v), this);
}
}
+ for (float v : mStopSpec) {
+ if (Float.isNaN(v)) {
+ context.listensTo(Utils.idFromNan(v), this);
+ }
+ }
}
private float wrap(float pos) {
@@ -211,12 +232,14 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
case STOP_INSTANTLY:
return pos;
case STOP_NOTCHES_EVEN:
- int evenSpacing = (int) mStopSpec[0];
- float step = (mOutMax - min) / evenSpacing;
+ int evenSpacing = (int) mOutStopSpec[0];
+ float notchMax = (mOutStopSpec.length > 1) ? mOutStopSpec[1] : mOutMax;
+ float step = (notchMax - min) / evenSpacing;
float notch = min + step * (int) (0.5f + (target - mOutMin) / step);
-
- notch = Math.max(Math.min(notch, mOutMax), min);
+ if (!mWrapMode) {
+ notch = Math.max(Math.min(notch, mOutMax), min);
+ }
return notch;
case STOP_NOTCHES_PERCENTS:
positions = new float[mStopSpec.length];
@@ -265,7 +288,6 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
float next = mCurrentValue;
mLastValue = next;
- // System.out.println(mStopMode + " " + prev + " -> " + next);
float min = (mWrapMode) ? 0 : mOutMin;
float max = mOutMax;
@@ -309,7 +331,7 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
@Override
public void apply(RemoteContext context) {
- Component comp = context.lastComponent;
+ Component comp = context.mLastComponent;
if (comp != null) {
float x = comp.getX();
float y = comp.getY();
@@ -329,7 +351,6 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
updateVariables(context);
if (mUnmodified) {
mCurrentValue = mOutDefValue;
-
context.loadFloat(mId, wrap(mCurrentValue));
return;
}
@@ -337,7 +358,11 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
float time = context.getAnimationTime() - mTouchUpTime;
float value = mEasyTouch.getPos(time);
mCurrentValue = value;
- value = wrap(value);
+ if (mWrapMode) {
+ value = wrap(value);
+ } else {
+ value = Math.min(Math.max(value, mOutMin), mOutMax);
+ }
context.loadFloat(mId, value);
if (mEasyTouch.getDuration() < time) {
mEasingToStop = false;
@@ -410,7 +435,8 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
mTouchUpTime = context.getAnimationTime();
float dest = getStopPosition(value, slope);
- mEasyTouch.config(value, dest, slope, mMaxTime, mMaxAcceleration, mMaxVelocity, null);
+ float time = mMaxTime * Math.abs(dest - value) / (2 * mMaxVelocity);
+ mEasyTouch.config(value, dest, slope, time, mMaxAcceleration, mMaxVelocity, null);
mEasingToStop = true;
}
@@ -543,7 +569,6 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
int stopLen = stopLogic & 0xFFFF;
int stopMode = stopLogic >> 16;
- Utils.log("stopMode " + stopMode + " stopLen " + stopLen);
float[] stopsData = new float[stopLen];
for (int i = 0; i < stopsData.length; i++) {
stopsData[i] = buffer.readFloat();
@@ -592,8 +617,9 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene
.field(FLOAT, "wrapValue", "> [Wrap value] ");
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return indent + toString();
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
index 03f7e0563eeb..baca3e0dc99a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
@@ -69,7 +69,7 @@ public class Utils {
* @param value
* @return
*/
- public static String floatToString(float idvalue, float value) {
+ public static @NonNull String floatToString(float idvalue, float value) {
if (Float.isNaN(idvalue)) {
if (idFromNan(value) == 0) {
return "NaN";
@@ -85,7 +85,7 @@ public class Utils {
* @param value
* @return
*/
- public static String floatToString(float value) {
+ public static @NonNull String floatToString(float value) {
if (Float.isNaN(value)) {
if (idFromNan(value) == 0) {
return "NaN";
@@ -100,7 +100,7 @@ public class Utils {
*
* @param str
*/
- public static void log(String str) {
+ public static void log(@NonNull String str) {
StackTraceElement s = new Throwable().getStackTrace()[1];
System.out.println(
"("
@@ -119,7 +119,7 @@ public class Utils {
* @param str
* @param n
*/
- public static void logStack(String str, int n) {
+ public static void logStack(@NonNull String str, int n) {
StackTraceElement[] st = new Throwable().getStackTrace();
for (int i = 1; i < n + 1; i++) {
StackTraceElement s = st[i];
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
index bdc2a886ffd6..7f1d101cff16 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -22,8 +24,12 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.Strin
/** Operations representing actions on the document */
public interface ActionOperation extends Operation {
- void serializeToString(int indent, StringSerializer serializer);
+ void serializeToString(int indent, @NonNull StringSerializer serializer);
void runAction(
- RemoteContext context, CoreDocument document, Component component, float x, float y);
+ @NonNull RemoteContext context,
+ @NonNull CoreDocument document,
+ @NonNull Component component,
+ float x,
+ float y);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
index e789710bb113..19f4c2b04956 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
@@ -77,4 +77,9 @@ public class AnimatableValue {
return mValue;
}
+
+ @Override
+ public String toString() {
+ return "AnimatableValue{mId=" + mId + "}";
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
index 988651895bae..aa8f75807141 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
@@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -35,7 +36,7 @@ public class CanvasContent extends Component implements ComponentStartOperation
float y,
float width,
float height,
- Component parent,
+ @Nullable Component parent,
int animationId) {
super(parent, componentId, animationId, x, y, width, height);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
index b567538b1c4e..f44e20ddcdac 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
@@ -16,7 +16,6 @@
package com.android.internal.widget.remotecompose.core.operations.layout;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -80,7 +79,7 @@ public class ClickModifierOperation extends PaintOperation
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
for (Operation op : mList) {
if (op instanceof TextData) {
op.apply(context);
@@ -90,7 +89,7 @@ public class ClickModifierOperation extends PaintOperation
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@@ -137,7 +136,7 @@ public class ClickModifierOperation extends PaintOperation
}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(@NonNull RemoteContext context, float width, float height) {
mWidth = width;
mHeight = height;
}
@@ -154,8 +153,8 @@ public class ClickModifierOperation extends PaintOperation
@Override
public void onClick(
- RemoteContext context,
- CoreDocument document,
+ @NonNull RemoteContext context,
+ @NonNull CoreDocument document,
@NonNull Component component,
float x,
float y) {
@@ -171,6 +170,7 @@ public class ClickModifierOperation extends PaintOperation
((ActionOperation) o).runAction(context, document, component, x, y);
}
}
+ context.hapticEffect(3);
}
@NonNull
@@ -182,7 +182,7 @@ public class ClickModifierOperation extends PaintOperation
buffer.start(OP_CODE);
}
- public static void read(WireBuffer buffer, @NonNull List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
operations.add(new ClickModifierOperation());
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
index f4f4ee2a3416..fbfc796e092a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
@@ -50,12 +50,12 @@ public class Component extends PaintOperation implements Measurable, Serializabl
protected float mY;
protected float mWidth;
protected float mHeight;
- protected Component mParent;
+ @Nullable protected Component mParent;
protected int mAnimationId = -1;
- public Visibility mVisibility = Visibility.VISIBLE;
- public Visibility mScheduledVisibility = Visibility.VISIBLE;
+ @NonNull public Visibility mVisibility = Visibility.VISIBLE;
+ @NonNull public Visibility mScheduledVisibility = Visibility.VISIBLE;
@NonNull public ArrayList<Operation> mList = new ArrayList<>();
- public PaintOperation mPreTranslate;
+ public PaintOperation mPreTranslate; // todo, can we initialize this here and make it NonNull?
public boolean mNeedsMeasure = true;
public boolean mNeedsRepaint = false;
@Nullable public AnimateMeasure mAnimateMeasure;
@@ -99,6 +99,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
return mAnimationId;
}
+ @Nullable
public Component getParent() {
return mParent;
}
@@ -160,7 +161,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
}
public Component(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -177,7 +178,12 @@ public class Component extends PaintOperation implements Measurable, Serializabl
}
public Component(
- int componentId, float x, float y, float width, float height, Component parent) {
+ int componentId,
+ float x,
+ float y,
+ float width,
+ float height,
+ @Nullable Component parent) {
this(parent, componentId, -1, x, y, width, height);
}
@@ -211,7 +217,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
return mNeedsMeasure;
}
- public void setParent(Component parent) {
+ public void setParent(@Nullable Component parent) {
mParent = parent;
}
@@ -222,8 +228,8 @@ public class Component extends PaintOperation implements Measurable, Serializabl
* @param context the current context
*/
public void updateVariables(@NonNull RemoteContext context) {
- Component prev = context.lastComponent;
- context.lastComponent = this;
+ Component prev = context.mLastComponent;
+ context.mLastComponent = this;
if (!mComponentValues.isEmpty()) {
updateComponentValues(context);
@@ -236,13 +242,21 @@ public class Component extends PaintOperation implements Measurable, Serializabl
o.apply(context);
}
}
- context.lastComponent = prev;
+ context.mLastComponent = prev;
}
- public void addComponentValue(ComponentValue v) {
+ public void addComponentValue(@NonNull ComponentValue v) {
mComponentValues.add(v);
}
+ public float intrinsicWidth() {
+ return getWidth();
+ }
+
+ public float intrinsicHeight() {
+ return getHeight();
+ }
+
public enum Visibility {
GONE,
VISIBLE,
@@ -253,13 +267,13 @@ public class Component extends PaintOperation implements Measurable, Serializabl
if (mVisibility != Visibility.VISIBLE || mParent == null) {
return mVisibility == Visibility.VISIBLE;
}
- if (mParent != null) {
+ if (mParent != null) { // TODO: this is always true -- bbade@
return mParent.isVisible();
}
return true;
}
- public void setVisibility(Visibility visibility) {
+ public void setVisibility(@NonNull Visibility visibility) {
if (visibility != mVisibility || visibility != mScheduledVisibility) {
mScheduledVisibility = visibility;
invalidateMeasure();
@@ -267,7 +281,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
}
@Override
- public boolean suitableForTransition(Operation o) {
+ public boolean suitableForTransition(@NonNull Operation o) {
if (!(o instanceof Component)) {
return false;
}
@@ -291,7 +305,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
@Override
public void measure(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
@@ -358,16 +372,27 @@ public class Component extends PaintOperation implements Measurable, Serializabl
return x >= lx1 && x < lx2 && y >= ly1 && y < ly2;
}
- public void onClick(RemoteContext context, CoreDocument document, float x, float y) {
+ public float getScrollX() {
+ return 0;
+ }
+
+ public float getScrollY() {
+ return 0;
+ }
+
+ public void onClick(
+ @NonNull RemoteContext context, @NonNull CoreDocument document, float x, float y) {
if (!contains(x, y)) {
return;
}
+ float cx = x - getScrollX();
+ float cy = y - getScrollY();
for (Operation op : mList) {
if (op instanceof Component) {
- ((Component) op).onClick(context, document, x, y);
+ ((Component) op).onClick(context, document, cx, cy);
}
if (op instanceof ClickHandler) {
- ((ClickHandler) op).onClick(context, document, this, x, y);
+ ((ClickHandler) op).onClick(context, document, this, cx, cy);
}
}
}
@@ -376,12 +401,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl
if (!contains(x, y)) {
return;
}
+ float cx = x - getScrollX();
+ float cy = y - getScrollY();
for (Operation op : mList) {
if (op instanceof Component) {
- ((Component) op).onTouchDown(context, document, x, y);
+ ((Component) op).onTouchDown(context, document, cx, cy);
}
if (op instanceof TouchHandler) {
- ((TouchHandler) op).onTouchDown(context, document, this, x, y);
+ ((TouchHandler) op).onTouchDown(context, document, this, cx, cy);
}
}
}
@@ -391,12 +418,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl
if (!force && !contains(x, y)) {
return;
}
+ float cx = x - getScrollX();
+ float cy = y - getScrollY();
for (Operation op : mList) {
if (op instanceof Component) {
- ((Component) op).onTouchUp(context, document, x, y, force);
+ ((Component) op).onTouchUp(context, document, cx, cy, force);
}
if (op instanceof TouchHandler) {
- ((TouchHandler) op).onTouchUp(context, document, this, x, y);
+ ((TouchHandler) op).onTouchUp(context, document, this, cx, cy);
}
}
}
@@ -406,12 +435,31 @@ public class Component extends PaintOperation implements Measurable, Serializabl
if (!force && !contains(x, y)) {
return;
}
+ float cx = x - getScrollX();
+ float cy = y - getScrollY();
+ for (Operation op : mList) {
+ if (op instanceof Component) {
+ ((Component) op).onTouchCancel(context, document, cx, cy, force);
+ }
+ if (op instanceof TouchHandler) {
+ ((TouchHandler) op).onTouchCancel(context, document, this, cx, cy);
+ }
+ }
+ }
+
+ public void onTouchDrag(
+ RemoteContext context, CoreDocument document, float x, float y, boolean force) {
+ if (!force && !contains(x, y)) {
+ return;
+ }
+ float cx = x - getScrollX();
+ float cy = y - getScrollY();
for (Operation op : mList) {
if (op instanceof Component) {
- ((Component) op).onTouchCancel(context, document, x, y, force);
+ ((Component) op).onTouchDrag(context, document, cx, cy, force);
}
if (op instanceof TouchHandler) {
- ((TouchHandler) op).onTouchCancel(context, document, this, x, y);
+ ((TouchHandler) op).onTouchDrag(context, document, this, cx, cy);
}
}
}
@@ -480,7 +528,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
// nothing
}
@@ -502,7 +550,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
StringBuilder builder = new StringBuilder();
builder.append(indent);
builder.append(toString());
@@ -602,8 +650,8 @@ public class Component extends PaintOperation implements Measurable, Serializabl
if (mPreTranslate != null) {
mPreTranslate.paint(context);
}
- Component prev = context.getContext().lastComponent;
- context.getContext().lastComponent = this;
+ Component prev = context.getContext().mLastComponent;
+ context.getContext().mLastComponent = this;
context.save();
context.translate(mX, mY);
if (context.isVisualDebug()) {
@@ -618,7 +666,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl
}
}
context.restore();
- context.getContext().lastComponent = prev;
+ context.getContext().mLastComponent = prev;
}
public boolean applyAnimationAsNeeded(@NonNull PaintContext context) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
index f370e20677e8..476b73c8fe7d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
@@ -16,7 +16,6 @@
package com.android.internal.widget.remotecompose.core.operations.layout;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -40,13 +39,13 @@ public class ComponentEnd implements Operation {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
// nothing
}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@@ -67,7 +66,7 @@ public class ComponentEnd implements Operation {
return 1 + 4 + 4 + 4;
}
- public static void read(WireBuffer buffer, @NonNull List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
operations.add(new ComponentEnd());
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
index f250d9ac4a01..def9f780ba7f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
@@ -19,7 +19,6 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -96,12 +95,12 @@ public class ComponentStart implements ComponentStartOperation {
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
// nothing
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java
index bb4311996df0..d6170074238a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.RemoteContext;
/**
@@ -22,5 +24,5 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
* measured. Eg borders, background, clips, etc.
*/
public interface DecoratorComponent {
- void layout(RemoteContext context, float width, float height);
+ void layout(@NonNull RemoteContext context, float width, float height);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
index e0923dfb48fb..0041582f7189 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
@@ -24,7 +24,9 @@ import com.android.internal.widget.remotecompose.core.operations.BitmapData;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixSave;
import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate;
+import com.android.internal.widget.remotecompose.core.operations.PaintData;
import com.android.internal.widget.remotecompose.core.operations.TextData;
+import com.android.internal.widget.remotecompose.core.operations.TouchExpression;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentVisibilityOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.DimensionModifierOperation;
@@ -57,12 +59,14 @@ public class LayoutComponent extends Component {
protected float mPaddingBottom = 0f;
@NonNull protected ComponentModifiers mComponentModifiers = new ComponentModifiers();
- @NonNull protected ArrayList<Component> mChildrenComponents = new ArrayList<>();
+
+ @NonNull
+ protected ArrayList<Component> mChildrenComponents = new ArrayList<>(); // members are not null
protected boolean mChildrenHaveZIndex = false;
public LayoutComponent(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -129,6 +133,9 @@ public class LayoutComponent extends Component {
public void inflate() {
ArrayList<TextData> data = new ArrayList<>();
+ ArrayList<TouchExpression> touchExpressions = new ArrayList<>();
+ ArrayList<PaintData> paintData = new ArrayList<>();
+
for (Operation op : mList) {
if (op instanceof LayoutComponentContent) {
mContent = (LayoutComponentContent) op;
@@ -172,6 +179,10 @@ public class LayoutComponent extends Component {
mComponentModifiers.add((ModifierOperation) op);
} else if (op instanceof TextData) {
data.add((TextData) op);
+ } else if (op instanceof TouchExpression) {
+ touchExpressions.add((TouchExpression) op);
+ } else if (op instanceof PaintData) {
+ paintData.add((PaintData) op);
} else {
// nothing
}
@@ -179,6 +190,8 @@ public class LayoutComponent extends Component {
mList.clear();
mList.addAll(data);
+ mList.addAll(touchExpressions);
+ mList.addAll(paintData);
mList.add(mComponentModifiers);
for (Component c : mChildrenComponents) {
c.mParent = this;
@@ -255,11 +268,24 @@ public class LayoutComponent extends Component {
}
@Override
+ public float getScrollX() {
+ return mComponentModifiers.getScrollX();
+ }
+
+ @Override
+ public float getScrollY() {
+ return mComponentModifiers.getScrollY();
+ }
+
+ @Override
public void paintingComponent(@NonNull PaintContext context) {
- Component prev = context.getContext().lastComponent;
- context.getContext().lastComponent = this;
+ Component prev = context.getContext().mLastComponent;
+ context.getContext().mLastComponent = this;
context.save();
context.translate(mX, mY);
+ if (context.isVisualDebug()) {
+ debugBox(this, context);
+ }
if (mGraphicsLayerModifier != null) {
context.startGraphicsLayer((int) getWidth(), (int) getHeight());
float scaleX = mGraphicsLayerModifier.getScaleX();
@@ -285,8 +311,8 @@ public class LayoutComponent extends Component {
renderEffectId);
}
mComponentModifiers.paint(context);
- float tx = mPaddingLeft;
- float ty = mPaddingTop;
+ float tx = mPaddingLeft + getScrollX();
+ float ty = mPaddingTop + getScrollY();
context.translate(tx, ty);
if (mChildrenHaveZIndex) {
// TODO -- should only sort when something has changed
@@ -305,7 +331,7 @@ public class LayoutComponent extends Component {
}
context.translate(-tx, -ty);
context.restore();
- context.getContext().lastComponent = prev;
+ context.getContext().mLastComponent = prev;
}
/** Traverse the modifiers to compute indicated dimension */
@@ -337,7 +363,7 @@ public class LayoutComponent extends Component {
* @param padding output start and end padding values
* @return padding width
*/
- public float computeModifierDefinedPaddingWidth(float[] padding) {
+ public float computeModifierDefinedPaddingWidth(@NonNull float[] padding) {
float s = 0f;
float e = 0f;
for (Operation c : mComponentModifiers.getList()) {
@@ -381,7 +407,7 @@ public class LayoutComponent extends Component {
* @param padding output top and bottom padding values
* @return padding height
*/
- public float computeModifierDefinedPaddingHeight(float[] padding) {
+ public float computeModifierDefinedPaddingHeight(@NonNull float[] padding) {
float t = 0f;
float b = 0f;
for (Operation c : mComponentModifiers.getList()) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
index 0a085b43401c..7eea885f6b6d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
@@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -35,7 +36,7 @@ public class LayoutComponentContent extends Component implements ComponentStartO
float y,
float width,
float height,
- Component parent,
+ @Nullable Component parent,
int animationId) {
super(parent, componentId, animationId, x, y, width, height);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java
index c4df075bb9e8..df960e45736e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.PaintContext;
@@ -59,8 +61,9 @@ public abstract class ListActionsOperation extends PaintOperation
}
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
index c90077b88782..71de2857258b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
@@ -16,7 +16,6 @@
package com.android.internal.widget.remotecompose.core.operations.layout;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -40,13 +39,13 @@ public class LoopEnd implements Operation {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
// nothing
}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@@ -63,7 +62,7 @@ public class LoopEnd implements Operation {
buffer.start(id());
}
- public static void read(WireBuffer buffer, @NonNull List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
operations.add(new LoopEnd());
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
index eeaeafd284c0..d88382dde7e0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
@@ -16,7 +16,6 @@
package com.android.internal.widget.remotecompose.core.operations.layout;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -70,7 +69,7 @@ public class LoopOperation extends PaintOperation {
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
index bd8d1f0ba9dd..ca79003448e7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
@@ -16,7 +16,6 @@
package com.android.internal.widget.remotecompose.core.operations.layout;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -40,13 +39,13 @@ public class OperationsListEnd implements Operation {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
// nothing
}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@@ -63,7 +62,7 @@ public class OperationsListEnd implements Operation {
buffer.start(id());
}
- public static void read(WireBuffer buffer, @NonNull List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
operations.add(new OperationsListEnd());
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
index 524ae59e70ec..85c71537540c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
@@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -45,13 +46,18 @@ public class RootLayoutComponent extends Component implements ComponentStartOper
float y,
float width,
float height,
- Component parent,
+ @Nullable Component parent,
int animationId) {
super(parent, componentId, animationId, x, y, width, height);
}
public RootLayoutComponent(
- int componentId, float x, float y, float width, float height, Component parent) {
+ int componentId,
+ float x,
+ float y,
+ float width,
+ float height,
+ @Nullable Component parent) {
super(parent, componentId, -1, x, y, width, height);
}
@@ -130,7 +136,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper
if (!mNeedsMeasure) {
return;
}
- context.lastComponent = this;
+ context.mLastComponent = this;
mWidth = context.mWidth;
mHeight = context.mHeight;
@@ -149,7 +155,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper
@Override
public void paint(@NonNull PaintContext context) {
mNeedsRepaint = false;
- context.getContext().lastComponent = this;
+ context.getContext().mLastComponent = this;
context.save();
if (mParent == null) { // root layout
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
index 486efbd6e00f..0316f96bfc3e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
@@ -70,6 +70,12 @@ public class TouchCancelModifierOperation extends ListActionsOperation implement
applyActions(context, document, component, x, y, true);
}
+ @Override
+ public void onTouchDrag(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ // nothing
+ }
+
public static String name() {
return "TouchCancelModifier";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
index 5d379fe01d61..d98911f82060 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
@@ -72,6 +72,12 @@ public class TouchDownModifierOperation extends ListActionsOperation implements
// nothing
}
+ @Override
+ public void onTouchDrag(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ // nothing
+ }
+
public static String name() {
return "TouchModifier";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java
index 5adfc33b5ef5..ac9dd908d6a4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java
@@ -46,6 +46,18 @@ public interface TouchHandler {
RemoteContext context, CoreDocument document, Component component, float x, float y);
/**
+ * callback for a touch move event
+ *
+ * @param context the current context
+ * @param document the current document
+ * @param component the component on which the touch has been received
+ * @param x the x position of the click in document coordinates
+ * @param y the y position of the click in document coordinates
+ */
+ void onTouchDrag(
+ RemoteContext context, CoreDocument document, Component component, float x, float y);
+
+ /**
* callback for a touch cancel event
*
* @param context the current context
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
index 263cc43d5e74..f6cb3750906f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
@@ -70,6 +70,12 @@ public class TouchUpModifierOperation extends ListActionsOperation implements To
// nothing
}
+ @Override
+ public void onTouchDrag(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ // nothing
+ }
+
public static String name() {
return "TouchUpModifier";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
index 6036b74efad3..b3430998a520 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
@@ -33,40 +33,40 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.easin
* <p>Handles position, size and visibility
*/
public class AnimateMeasure {
- long mStartTime = System.currentTimeMillis();
- Component mComponent;
- ComponentMeasure mOriginal;
- ComponentMeasure mTarget;
- int mDuration;
- int mDurationVisibilityChange = mDuration;
- AnimationSpec.ANIMATION mEnterAnimation = AnimationSpec.ANIMATION.FADE_IN;
- AnimationSpec.ANIMATION mExitAnimation = AnimationSpec.ANIMATION.FADE_OUT;
- int mMotionEasingType = GeneralEasing.CUBIC_STANDARD;
- int mVisibilityEasingType = GeneralEasing.CUBIC_ACCELERATE;
+ private long mStartTime = System.currentTimeMillis();
+ private final @NonNull Component mComponent;
+ private final @NonNull ComponentMeasure mOriginal;
+ private final @NonNull ComponentMeasure mTarget;
+ private int mDuration;
+ private int mDurationVisibilityChange = mDuration;
+ private @NonNull AnimationSpec.ANIMATION mEnterAnimation = AnimationSpec.ANIMATION.FADE_IN;
+ private @NonNull AnimationSpec.ANIMATION mExitAnimation = AnimationSpec.ANIMATION.FADE_OUT;
+ private int mMotionEasingType = GeneralEasing.CUBIC_STANDARD;
+ private int mVisibilityEasingType = GeneralEasing.CUBIC_ACCELERATE;
- float mP = 0f;
- float mVp = 0f;
+ private float mP = 0f;
+ private float mVp = 0f;
@NonNull
- FloatAnimation mMotionEasing =
+ private FloatAnimation mMotionEasing =
new FloatAnimation(mMotionEasingType, mDuration / 1000f, null, 0f, Float.NaN);
@NonNull
- FloatAnimation mVisibilityEasing =
+ private FloatAnimation mVisibilityEasing =
new FloatAnimation(
mVisibilityEasingType, mDurationVisibilityChange / 1000f, null, 0f, Float.NaN);
- ParticleAnimation mParticleAnimation;
+ private ParticleAnimation mParticleAnimation;
public AnimateMeasure(
long startTime,
@NonNull Component component,
- ComponentMeasure original,
+ @NonNull ComponentMeasure original,
@NonNull ComponentMeasure target,
int duration,
int durationVisibilityChange,
- AnimationSpec.ANIMATION enterAnimation,
- AnimationSpec.ANIMATION exitAnimation,
+ @NonNull AnimationSpec.ANIMATION enterAnimation,
+ @NonNull AnimationSpec.ANIMATION exitAnimation,
int motionEasingType,
int visibilityEasingType) {
this.mStartTime = startTime;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
index 47abadeb70fa..6fb705985711 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.animati
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -36,8 +35,8 @@ public class AnimationSpec implements Operation {
int mMotionEasingType = GeneralEasing.CUBIC_STANDARD;
int mVisibilityDuration = 300;
int mVisibilityEasingType = GeneralEasing.CUBIC_STANDARD;
- ANIMATION mEnterAnimation = ANIMATION.FADE_IN;
- ANIMATION mExitAnimation = ANIMATION.FADE_OUT;
+ @NonNull ANIMATION mEnterAnimation = ANIMATION.FADE_IN;
+ @NonNull ANIMATION mExitAnimation = ANIMATION.FADE_OUT;
public AnimationSpec(
int animationId,
@@ -45,8 +44,8 @@ public class AnimationSpec implements Operation {
int motionEasingType,
int visibilityDuration,
int visibilityEasingType,
- ANIMATION enterAnimation,
- ANIMATION exitAnimation) {
+ @NonNull ANIMATION enterAnimation,
+ @NonNull ANIMATION exitAnimation) {
this.mAnimationId = animationId;
this.mMotionDuration = motionDuration;
this.mMotionEasingType = motionEasingType;
@@ -87,10 +86,12 @@ public class AnimationSpec implements Operation {
return mVisibilityEasingType;
}
+ @NonNull
public ANIMATION getEnterAnimation() {
return mEnterAnimation;
}
+ @NonNull
public ANIMATION getExitAnimation() {
return mExitAnimation;
}
@@ -126,13 +127,13 @@ public class AnimationSpec implements Operation {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
// nothing here
}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java
index 37d20781f4fa..64e2f004cb65 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java
@@ -34,7 +34,7 @@ public class ParticleAnimation {
@NonNull PaintContext context,
@NonNull Component component,
@NonNull ComponentMeasure start,
- ComponentMeasure end,
+ @NonNull ComponentMeasure end,
float progress) {
ArrayList<Particle> particles = mAllParticles.get(component.getComponentId());
if (particles == null) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
index f3e550903a65..47a942187900 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
@@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -45,7 +46,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation
int mVerticalPositioning;
public BoxLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -60,7 +61,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation
}
public BoxLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
int horizontalPositioning,
@@ -104,7 +105,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation
@Override
public void computeWrapSize(
- PaintContext context,
+ @NonNull PaintContext context,
float maxWidth,
float maxHeight,
@NonNull MeasurePass measure,
@@ -122,7 +123,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation
@Override
public void computeSize(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
@@ -134,7 +135,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation
}
@Override
- public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) {
+ public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) {
ComponentMeasure selfMeasure = measure.get(this);
float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight;
float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
index 12ff969530b3..476b1a666fe9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
@@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -32,7 +33,7 @@ import java.util.List;
public class CanvasLayout extends BoxLayout {
public CanvasLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -42,7 +43,7 @@ public class CanvasLayout extends BoxLayout {
super(parent, componentId, animationId, x, y, width, height, 0, 0);
}
- public CanvasLayout(Component parent, int componentId, int animationId) {
+ public CanvasLayout(@Nullable Component parent, int componentId, int animationId) {
this(parent, componentId, animationId, 0, 0, 0, 0);
}
@@ -103,7 +104,7 @@ public class CanvasLayout extends BoxLayout {
}
@Override
- public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) {
+ public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) {
ComponentMeasure selfMeasure = measure.get(this);
float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight;
float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
index 52bf4c54faf6..68e18c699539 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
@@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -53,7 +54,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati
float mSpacedBy = 0f;
public ColumnLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -70,7 +71,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati
}
public ColumnLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
int horizontalPositioning,
@@ -121,7 +122,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati
@Override
public void computeWrapSize(
- PaintContext context,
+ @NonNull PaintContext context,
float maxWidth,
float maxHeight,
@NonNull MeasurePass measure,
@@ -145,7 +146,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati
@Override
public void computeSize(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
@@ -164,7 +165,17 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati
}
@Override
- public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) {
+ public float intrinsicHeight() {
+ float height = computeModifierDefinedHeight();
+ float componentHeights = 0f;
+ for (Component c : mChildrenComponents) {
+ componentHeights += c.intrinsicHeight();
+ }
+ return Math.max(height, componentHeights);
+ }
+
+ @Override
+ public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) {
ComponentMeasure selfMeasure = measure.get(this);
DebugLog.s(
() ->
@@ -188,6 +199,16 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati
float childrenWidth = 0f;
float childrenHeight = 0f;
+ if (mComponentModifiers.hasHorizontalScroll()) {
+ selfWidth =
+ mComponentModifiers.getHorizontalScrollDimension()
+ - mPaddingLeft
+ - mPaddingRight;
+ }
+ if (mComponentModifiers.hasVerticalScroll()) {
+ selfHeight =
+ mComponentModifiers.getVerticalScrollDimension() - mPaddingTop - mPaddingBottom;
+ }
boolean hasWeights = false;
float totalWeights = 0f;
for (Component child : mChildrenComponents) {
@@ -286,6 +307,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati
ty = verticalGap / 2f;
break;
}
+
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
switch (mHorizontalPositioning) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
index 0c4d24a4561a..3b5aaf38fb5b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
@@ -16,6 +16,7 @@
package com.android.internal.widget.remotecompose.core.operations.layout.managers;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -32,7 +33,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
@NonNull Size mCachedWrapSize = new Size(0f, 0f);
public LayoutManager(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -43,24 +44,46 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
}
/** Implemented by subclasses to provide a layout/measure pass */
- public void internalLayoutMeasure(PaintContext context, MeasurePass measure) {
+ public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) {
// nothing here
}
/** Subclasses can implement this to provide wrap sizing */
public void computeWrapSize(
- PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) {
+ @NonNull PaintContext context,
+ float maxWidth,
+ float maxHeight,
+ @NonNull MeasurePass measure,
+ @NonNull Size size) {
// nothing here
}
+ @Override
+ public float intrinsicHeight() {
+ float height = computeModifierDefinedHeight();
+ for (Component c : mChildrenComponents) {
+ height = Math.max(c.intrinsicHeight(), height);
+ }
+ return height;
+ }
+
+ @Override
+ public float intrinsicWidth() {
+ float width = computeModifierDefinedWidth();
+ for (Component c : mChildrenComponents) {
+ width = Math.max(c.intrinsicWidth(), width);
+ }
+ return width;
+ }
+
/** Subclasses can implement this when not in wrap sizing */
public void computeSize(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
float maxHeight,
- MeasurePass measure) {
+ @NonNull MeasurePass measure) {
// nothing here
}
@@ -99,7 +122,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
/** Base implementation of the measure resolution */
@Override
public void measure(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
@@ -112,7 +135,13 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
Math.min(maxHeight, computeModifierDefinedHeight() - mMarginTop - mMarginBottom);
float insetMaxWidth = maxWidth - mMarginLeft - mMarginRight;
float insetMaxHeight = maxHeight - mMarginTop - mMarginBottom;
- if (mWidthModifier.isWrap() || mHeightModifier.isWrap()) {
+ if (mWidthModifier.isIntrinsicMin()) {
+ maxWidth = intrinsicWidth();
+ }
+ if (mHeightModifier.isIntrinsicMin()) {
+ maxHeight = intrinsicHeight();
+ }
+ if (mWidthModifier.isWrap() || mHeightModifier.isWrap()) { // TODO: potential npe -- bbade@
mCachedWrapSize.setWidth(0f);
mCachedWrapSize.setHeight(0f);
computeWrapSize(context, maxWidth, maxHeight, measure, mCachedWrapSize);
@@ -129,7 +158,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
measuredWidth = Math.max(measuredWidth, minWidth);
measuredWidth = Math.min(measuredWidth, insetMaxWidth);
}
- if (isInVerticalFill()) {
+ if (isInVerticalFill()) { // todo: potential npe -- bbade@
measuredHeight = insetMaxHeight;
} else if (mHeightModifier.hasWeight()) {
measuredHeight = Math.max(measuredHeight, computeModifierDefinedHeight());
@@ -146,7 +175,23 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
measuredWidth = Math.min(measuredWidth, insetMaxWidth);
measuredHeight = Math.min(measuredHeight, insetMaxHeight);
if (!hasWrap) {
- computeSize(context, 0f, measuredWidth, 0f, measuredHeight, measure);
+ if (hasHorizontalScroll()) {
+ mCachedWrapSize.setWidth(0f);
+ mCachedWrapSize.setHeight(0f);
+ computeWrapSize(context, Float.MAX_VALUE, maxHeight, measure, mCachedWrapSize);
+ float w = mCachedWrapSize.getWidth();
+ computeSize(context, 0f, w, 0, measuredHeight, measure);
+ mComponentModifiers.setHorizontalScrollDimension(measuredWidth, w);
+ } else if (hasVerticalScroll()) {
+ mCachedWrapSize.setWidth(0f);
+ mCachedWrapSize.setHeight(0f);
+ computeWrapSize(context, maxWidth, Float.MAX_VALUE, measure, mCachedWrapSize);
+ float h = mCachedWrapSize.getHeight();
+ computeSize(context, 0f, measuredWidth, 0, h, measure);
+ mComponentModifiers.setVerticalScrollDimension(measuredHeight, h);
+ } else {
+ computeSize(context, 0f, measuredWidth, 0f, measuredHeight, measure);
+ }
}
if (mContent != null) {
@@ -168,6 +213,14 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
internalLayoutMeasure(context, measure);
}
+ private boolean hasHorizontalScroll() {
+ return mComponentModifiers.hasHorizontalScroll();
+ }
+
+ private boolean hasVerticalScroll() {
+ return mComponentModifiers.hasVerticalScroll();
+ }
+
/** basic layout of internal components */
@Override
public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
index a366dc804758..0ce634f9c1ab 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
@@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -51,7 +52,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation
float mSpacedBy = 0f;
public RowLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -68,7 +69,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation
}
public RowLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
int horizontalPositioning,
@@ -119,7 +120,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation
@Override
public void computeWrapSize(
- PaintContext context,
+ @NonNull PaintContext context,
float maxWidth,
float maxHeight,
@NonNull MeasurePass measure,
@@ -143,7 +144,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation
@Override
public void computeSize(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
@@ -162,7 +163,17 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation
}
@Override
- public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) {
+ public float intrinsicWidth() {
+ float width = computeModifierDefinedWidth();
+ float componentWidths = 0f;
+ for (Component c : mChildrenComponents) {
+ componentWidths += c.intrinsicWidth();
+ }
+ return Math.max(width, componentWidths);
+ }
+
+ @Override
+ public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) {
ComponentMeasure selfMeasure = measure.get(this);
DebugLog.s(
() ->
@@ -186,6 +197,17 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation
float childrenWidth = 0f;
float childrenHeight = 0f;
+ if (mComponentModifiers.hasHorizontalScroll()) {
+ selfWidth =
+ mComponentModifiers.getHorizontalScrollDimension()
+ - mPaddingLeft
+ - mPaddingRight;
+ }
+ if (mComponentModifiers.hasVerticalScroll()) {
+ selfHeight =
+ mComponentModifiers.getVerticalScrollDimension() - mPaddingTop - mPaddingBottom;
+ }
+
boolean hasWeights = false;
float totalWeights = 0f;
for (Component child : mChildrenComponents) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
index e47ffdebb253..73a104bcafa6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
@@ -16,6 +16,7 @@
package com.android.internal.widget.remotecompose.core.operations.layout.managers;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -60,7 +61,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio
public boolean inTransition = false;
public StateLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -132,21 +133,21 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio
@Override
public void computeSize(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
float maxHeight,
- MeasurePass measure) {
+ @NonNull MeasurePass measure) {
LayoutManager layout = getLayout(currentLayoutIndex);
layout.computeSize(context, minWidth, maxWidth, minHeight, maxHeight, measure);
}
@Override
public void internalLayoutMeasure(
- PaintContext context,
+ @NonNull PaintContext context,
// layoutInfo: LayoutInfo,
- MeasurePass measure) {
+ @NonNull MeasurePass measure) {
LayoutManager layout = getLayout(currentLayoutIndex);
// layout.internalLayoutMeasure(context, layoutInfo, measure)
layout.internalLayoutMeasure(context, measure);
@@ -155,13 +156,18 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio
/** Subclasses can implement this to provide wrap sizing */
@Override
public void computeWrapSize(
- PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) {
+ @NonNull PaintContext context,
+ float maxWidth,
+ float maxHeight,
+ @NonNull MeasurePass measure,
+ @NonNull Size size) {
LayoutManager layout = getLayout(currentLayoutIndex);
layout.computeWrapSize(context, maxWidth, maxHeight, measure, size);
}
@Override
- public void onClick(RemoteContext context, CoreDocument document, float x, float y) {
+ public void onClick(
+ @NonNull RemoteContext context, @NonNull CoreDocument document, float x, float y) {
if (!contains(x, y)) {
return;
}
@@ -352,7 +358,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio
}
}
- public LayoutManager getLayout(int idx) {
+ public @NonNull LayoutManager getLayout(int idx) {
int index = 0;
for (Component pane : mChildrenComponents) {
if (pane instanceof LayoutComponent) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
index 8aa7712635fc..a527e5ad4077 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
@@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -52,8 +53,9 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation
private float mTextX;
private float mTextY;
private float mTextW;
+ private float mTextH;
- private String mCachedString = "";
+ @Nullable private String mCachedString = "";
@Override
public void registerListening(@NonNull RemoteContext context) {
@@ -89,7 +91,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation
}
public TextLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
float x,
@@ -114,7 +116,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation
}
public TextLayout(
- Component parent,
+ @Nullable Component parent,
int componentId,
int animationId,
int textId,
@@ -162,6 +164,9 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation
mPaint.setTextSize(mFontSize);
mPaint.setTextStyle(mType, (int) mFontWeight, mFontStyle == 1);
context.applyPaint(mPaint);
+ if (mCachedString == null) {
+ return;
+ }
int length = mCachedString.length();
context.drawTextRun(mTextId, 0, length, 0, 0, mTextX, mTextY, false);
if (DEBUG) {
@@ -241,7 +246,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation
@NonNull PaintContext context,
float maxWidth,
float maxHeight,
- MeasurePass measure,
+ @NonNull MeasurePass measure,
@NonNull Size size) {
context.savePaint();
mPaint.reset();
@@ -250,6 +255,9 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation
context.applyPaint(mPaint);
float[] bounds = new float[4];
int flags = PaintContext.TEXT_MEASURE_FONT_HEIGHT;
+ if (mCachedString == null) {
+ return;
+ }
context.getTextBounds(mTextId, 0, mCachedString.length(), flags, bounds);
context.restorePaint();
float w = bounds[2] - bounds[0];
@@ -259,6 +267,17 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation
size.setHeight(h);
mTextY = -bounds[1];
mTextW = w;
+ mTextH = h;
+ }
+
+ @Override
+ public float intrinsicHeight() {
+ return mTextH;
+ }
+
+ @Override
+ public float intrinsicWidth() {
+ return mTextW;
}
@NonNull
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java
index 426e02337f5b..82f23cdcf766 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java
@@ -26,7 +26,7 @@ public class ComponentMeasure {
float mY;
float mW;
float mH;
- Component.Visibility mVisibility = Component.Visibility.VISIBLE;
+ @NonNull Component.Visibility mVisibility = Component.Visibility.VISIBLE;
public void setX(float value) {
mX = value;
@@ -60,16 +60,16 @@ public class ComponentMeasure {
return mH;
}
- public Component.Visibility getVisibility() {
+ public @NonNull Component.Visibility getVisibility() {
return mVisibility;
}
- public void setVisibility(Component.Visibility visibility) {
+ public void setVisibility(@NonNull Component.Visibility visibility) {
mVisibility = visibility;
}
public ComponentMeasure(
- int id, float x, float y, float w, float h, Component.Visibility visibility) {
+ int id, float x, float y, float w, float h, @NonNull Component.Visibility visibility) {
this.mId = id;
this.mX = x;
this.mY = y;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java
index b48c2d5ae88b..fbf2784be843 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout.measure;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -26,15 +28,15 @@ public interface Measurable {
* does not apply the measure to the component.
*/
void measure(
- PaintContext context,
+ @NonNull PaintContext context,
float minWidth,
float maxWidth,
float minHeight,
float maxHeight,
- MeasurePass measure);
+ @NonNull MeasurePass measure);
/** Apply a given measure to the component */
- void layout(RemoteContext context, MeasurePass measure);
+ void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure);
/**
* Return true if the component needs to be remeasured
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java
index 112ab1b93474..5cfb1b43cf15 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java
@@ -43,7 +43,7 @@ public class MeasurePass {
return mList.containsKey(id);
}
- public ComponentMeasure get(@NonNull Component c) {
+ public @NonNull ComponentMeasure get(@NonNull Component c) {
if (!mList.containsKey(c.getComponentId())) {
ComponentMeasure measure =
new ComponentMeasure(
@@ -54,7 +54,7 @@ public class MeasurePass {
return mList.get(c.getComponentId());
}
- public ComponentMeasure get(int id) {
+ public @NonNull ComponentMeasure get(int id) {
if (!mList.containsKey(id)) {
ComponentMeasure measure =
new ComponentMeasure(id, 0f, 0f, 0f, 0f, Component.Visibility.GONE);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
index 76a97ca0eb51..71d2ba6edf21 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
@@ -98,7 +98,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation {
}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(@NonNull RemoteContext context, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
index d48a9c732cd5..0707cd627678 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
@@ -124,7 +124,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation {
}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(@NonNull RemoteContext context, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
index 78b51c3f83aa..e05b02781e10 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
@@ -40,7 +40,7 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation {
}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(@NonNull RemoteContext context, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
@@ -68,7 +68,7 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation {
buffer.start(OP_CODE);
}
- public static void read(WireBuffer buffer, @NonNull List<Operation> operations) {
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
operations.add(new ClipRectModifierOperation());
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
index 011d7edd18c8..d11f26f83ebd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
@@ -62,7 +62,7 @@ public class ComponentModifiers extends PaintOperation
}
@Override
- public void write(WireBuffer buffer) {
+ public void write(@NonNull WireBuffer buffer) {
// nothing
}
@@ -73,7 +73,7 @@ public class ComponentModifiers extends PaintOperation
}
}
- public void add(ModifierOperation operation) {
+ public void add(@NonNull ModifierOperation operation) {
mList.add(operation);
}
@@ -109,7 +109,7 @@ public class ComponentModifiers extends PaintOperation
}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(@NonNull RemoteContext context, float width, float height) {
float w = width;
float h = height;
for (ModifierOperation op : mList) {
@@ -126,13 +126,17 @@ public class ComponentModifiers extends PaintOperation
}
}
- public void addAll(ArrayList<ModifierOperation> operations) {
+ public void addAll(@NonNull ArrayList<ModifierOperation> operations) {
mList.addAll(operations);
}
@Override
public void onClick(
- RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ @NonNull RemoteContext context,
+ @NonNull CoreDocument document,
+ @NonNull Component component,
+ float x,
+ float y) {
for (ModifierOperation op : mList) {
if (op instanceof ClickHandler) {
((ClickHandler) op).onClick(context, document, component, x, y);
@@ -169,4 +173,110 @@ public class ComponentModifiers extends PaintOperation
}
}
}
+
+ @Override
+ public void onTouchDrag(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ for (ModifierOperation op : mList) {
+ if (op instanceof TouchHandler) {
+ ((TouchHandler) op).onTouchDrag(context, document, component, x, y);
+ }
+ }
+ }
+
+ public boolean hasHorizontalScroll() {
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isHorizontalScroll()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean hasVerticalScroll() {
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isVerticalScroll()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public float getScrollX() {
+ float scroll = 0;
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isHorizontalScroll()) {
+ scroll = Math.min(scroll, scrollModifier.getScrollX());
+ }
+ }
+ }
+ return scroll;
+ }
+
+ public float getScrollY() {
+ float scroll = 0;
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isVerticalScroll()) {
+ scroll = Math.min(scroll, scrollModifier.getScrollY());
+ }
+ }
+ }
+ return scroll;
+ }
+
+ public void setHorizontalScrollDimension(float hostDimension, float contentDimension) {
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isHorizontalScroll()) {
+ scrollModifier.setHorizontalScrollDimension(hostDimension, contentDimension);
+ }
+ }
+ }
+ }
+
+ public void setVerticalScrollDimension(float hostDimension, float contentDimension) {
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isVerticalScroll()) {
+ scrollModifier.setVerticalScrollDimension(hostDimension, contentDimension);
+ }
+ }
+ }
+ }
+
+ public float getHorizontalScrollDimension() {
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isHorizontalScroll()) {
+ return scrollModifier.getContentDimension();
+ }
+ }
+ }
+ return 0f;
+ }
+
+ public float getVerticalScrollDimension() {
+ for (ModifierOperation op : mList) {
+ if (op instanceof ScrollModifierOperation) {
+ ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
+ if (scrollModifier.isVerticalScroll()) {
+ return scrollModifier.getContentDimension();
+ }
+ }
+ }
+ return 0f;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
index 26e737b32027..471db0bedb11 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
@@ -63,16 +63,16 @@ public class ComponentVisibilityOperation
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@Override
- public void write(WireBuffer buffer) {}
+ public void write(@NonNull WireBuffer buffer) {}
public static void apply(@NonNull WireBuffer buffer, int valueId) {
buffer.start(OP_CODE);
@@ -114,10 +114,10 @@ public class ComponentVisibilityOperation
}
}
- public void setParent(LayoutComponent parent) {
+ public void setParent(@Nullable LayoutComponent parent) {
mParent = parent;
}
@Override
- public void layout(RemoteContext context, float width, float height) {}
+ public void layout(@NonNull RemoteContext context, float width, float height) {}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java
index 3c2d85cfee5b..b9324f0320d3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java
@@ -16,7 +16,6 @@
package com.android.internal.widget.remotecompose.core.operations.layout.modifiers;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.VariableSupport;
@@ -57,16 +56,16 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V
}
}
- Type mType = Type.EXACT;
+ @NonNull Type mType = Type.EXACT;
float mValue = Float.NaN;
float mOutValue = Float.NaN;
- public DimensionModifierOperation(Type type, float value) {
+ public DimensionModifierOperation(@NonNull Type type, float value) {
mType = type;
mOutValue = mValue = value;
}
- public DimensionModifierOperation(Type type) {
+ public DimensionModifierOperation(@NonNull Type type) {
this(type, Float.NaN);
}
@@ -115,7 +114,15 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V
return mType == Type.FILL;
}
- public Type getType() {
+ public boolean isIntrinsicMin() {
+ return mType == Type.INTRINSIC_MIN;
+ }
+
+ public boolean isIntrinsicMax() {
+ return mType == Type.INTRINSIC_MAX;
+ }
+
+ public @NonNull Type getType() {
return mType;
}
@@ -143,11 +150,11 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
index 2b3038281d57..571e554b9c71 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
@@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
@@ -175,8 +177,9 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation {
serializer.append(indent, "GRAPHICS_LAYER = [" + mScaleX + ", " + mScaleY + "]");
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
index 97c76c0aedf7..7bb4a756afa5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
@@ -59,11 +59,11 @@ public class HeightModifierOperation extends DimensionModifierOperation {
apply(buffer, mType.ordinal(), mValue);
}
- public HeightModifierOperation(Type type, float value) {
+ public HeightModifierOperation(@NonNull Type type, float value) {
super(type, value);
}
- public HeightModifierOperation(Type type) {
+ public HeightModifierOperation(@NonNull Type type) {
super(type);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
index 836321fff8e6..d239bc857446 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -63,22 +62,22 @@ public class HostActionOperation implements ActionOperation {
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@Override
- public void write(WireBuffer buffer) {}
+ public void write(@NonNull WireBuffer buffer) {}
@Override
public void runAction(
@NonNull RemoteContext context,
- CoreDocument document,
- Component component,
+ @NonNull CoreDocument document,
+ @NonNull Component component,
float x,
float y) {
context.runAction(mActionId, "");
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
index e97e89784a23..3268e5efd449 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -39,6 +38,7 @@ public class HostNamedActionOperation implements ActionOperation {
public static final int FLOAT_TYPE = 0;
public static final int INT_TYPE = 1;
public static final int STRING_TYPE = 2;
+ public static final int FLOAT_ARRAY_TYPE = 3;
public static final int NONE_TYPE = -1;
int mTextId = -1;
@@ -72,22 +72,22 @@ public class HostNamedActionOperation implements ActionOperation {
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@Override
- public void write(WireBuffer buffer) {}
+ public void write(@NonNull WireBuffer buffer) {}
@Override
public void runAction(
@NonNull RemoteContext context,
- CoreDocument document,
- Component component,
+ @NonNull CoreDocument document,
+ @NonNull Component component,
float x,
float y) {
Object value = null;
@@ -98,6 +98,8 @@ public class HostNamedActionOperation implements ActionOperation {
value = context.mRemoteComposeState.getFromId(mValueId);
} else if (mType == FLOAT_TYPE) {
value = context.mRemoteComposeState.getFloat(mValueId);
+ } else if (mType == FLOAT_ARRAY_TYPE) {
+ value = context.mRemoteComposeState.getFloats(mValueId);
}
}
context.runNamedAction(mTextId, value);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java
index 50f098e25f6a..8f08f1417add 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java
@@ -15,10 +15,12 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout.modifiers;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
/** Represents a modifier */
public interface ModifierOperation extends Operation {
- void serializeToString(int indent, StringSerializer serializer);
+ void serializeToString(int indent, @NonNull StringSerializer serializer);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
index 65fe345ac920..8c07059369ab 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
@@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
@@ -67,8 +69,9 @@ public class OffsetModifierOperation extends DecoratorModifierOperation {
serializer.append(indent, "OFFSET = [" + mX + ", " + mY + "]");
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
index ed5522ea865f..2b6621e4fd58 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -92,11 +91,11 @@ public class PaddingModifierOperation implements ModifierOperation {
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
index 6218dd5f3311..3fefc5817270 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
@@ -96,7 +96,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4
}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(@NonNull RemoteContext context, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
new file mode 100644
index 000000000000..8dcfed999c5c
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.layout.modifiers;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+
+import android.annotation.NonNull;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent;
+import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+
+import java.util.List;
+
+/** Represents a scroll modifier. */
+public class ScrollModifierOperation extends DecoratorModifierOperation implements TouchHandler {
+ private static final int OP_CODE = Operations.MODIFIER_SCROLL;
+ public static final String CLASS_NAME = "ScrollModifierOperation";
+
+ private final float mPositionExpression;
+ private final float mMax;
+ private final float mNotchMax;
+
+ float mWidth = 0;
+ float mHeight = 0;
+
+ int mDirection;
+
+ float mTouchDownX;
+ float mTouchDownY;
+
+ float mInitialScrollX;
+ float mInitialScrollY;
+
+ float mScrollX;
+ float mScrollY;
+
+ float mMaxScrollX;
+ float mMaxScrollY;
+
+ float mHostDimension;
+ float mContentDimension;
+
+ public ScrollModifierOperation(int direction, float position, float max, float notchMax) {
+ this.mDirection = direction;
+ this.mPositionExpression = position;
+ this.mMax = max;
+ this.mNotchMax = notchMax;
+ }
+
+ public boolean isVerticalScroll() {
+ return mDirection == 0;
+ }
+
+ public boolean isHorizontalScroll() {
+ return mDirection != 0;
+ }
+
+ public float getScrollX() {
+ return mScrollX;
+ }
+
+ public float getScrollY() {
+ return mScrollY;
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ RootLayoutComponent root = context.getDocument().getRootLayoutComponent();
+ if (root != null) {
+ root.setHasTouchListeners(true);
+ }
+ super.apply(context);
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ apply(buffer, mDirection, mPositionExpression, mMax, mNotchMax);
+ }
+
+ // @Override
+ public void serializeToString(int indent, StringSerializer serializer) {
+ serializer.append(indent, "SCROLL = [" + mDirection + "]");
+ }
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return (indent != null ? indent : "") + toString();
+ }
+
+ @Override
+ public void paint(PaintContext context) {
+ float position =
+ context.getContext()
+ .mRemoteComposeState
+ .getFloat(Utils.idFromNan(mPositionExpression));
+
+ if (mDirection == 0) {
+ mScrollY = -position;
+ } else {
+ mScrollX = -position;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ScrollModifierOperation(" + mDirection + ")";
+ }
+
+ public static String name() {
+ return CLASS_NAME;
+ }
+
+ public static int id() {
+ return OP_CODE;
+ }
+
+ public static void apply(
+ WireBuffer buffer, int direction, float position, float max, float notchMax) {
+ buffer.start(OP_CODE);
+ buffer.writeInt(direction);
+ buffer.writeFloat(position);
+ buffer.writeFloat(max);
+ buffer.writeFloat(notchMax);
+ }
+
+ public static void read(WireBuffer buffer, List<Operation> operations) {
+ int direction = buffer.readInt();
+ float position = buffer.readFloat();
+ float max = buffer.readFloat();
+ float notchMax = buffer.readFloat();
+ operations.add(new ScrollModifierOperation(direction, position, max, notchMax));
+ }
+
+ public static void documentation(DocumentationBuilder doc) {
+ doc.operation("Modifier Operations", OP_CODE, CLASS_NAME)
+ .description("define a Scroll Modifier")
+ .field(INT, "direction", "");
+ }
+
+ @Override
+ public void layout(RemoteContext context, float width, float height) {
+ mWidth = width;
+ mHeight = height;
+ if (mDirection == 0) { // VERTICAL
+ context.loadFloat(Utils.idFromNan(mMax), mMaxScrollY);
+ context.loadFloat(Utils.idFromNan(mNotchMax), mContentDimension);
+ } else {
+ context.loadFloat(Utils.idFromNan(mMax), mMaxScrollX);
+ context.loadFloat(Utils.idFromNan(mNotchMax), mContentDimension);
+ }
+ }
+
+ @Override
+ public void onTouchDown(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ mTouchDownX = x;
+ mTouchDownY = y;
+ mInitialScrollX = mScrollX;
+ mInitialScrollY = mScrollY;
+ document.appliedTouchOperation(component);
+ }
+
+ @Override
+ public void onTouchUp(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ // If not using touch expression, should add velocity decay here
+ }
+
+ @Override
+ public void onTouchDrag(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ float dx = x - mTouchDownX;
+ float dy = y - mTouchDownY;
+
+ if (!Utils.isVariable(mPositionExpression)) {
+ if (mDirection == 0) {
+ mScrollY = Math.max(-mMaxScrollY, Math.min(0, mInitialScrollY + dy));
+ } else {
+ mScrollX = Math.max(-mMaxScrollX, Math.min(0, mInitialScrollX + dx));
+ }
+ }
+ }
+
+ @Override
+ public void onTouchCancel(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {}
+
+ public void setHorizontalScrollDimension(float hostDimension, float contentDimension) {
+ mHostDimension = hostDimension;
+ mContentDimension = contentDimension;
+ mMaxScrollX = contentDimension - hostDimension;
+ }
+
+ public void setVerticalScrollDimension(float hostDimension, float contentDimension) {
+ mHostDimension = hostDimension;
+ mContentDimension = contentDimension;
+ mMaxScrollY = contentDimension - hostDimension;
+ }
+
+ public float getContentDimension() {
+ return mContentDimension;
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
index 29ec82810a7c..a97fcffdf75c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
@@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -59,8 +61,9 @@ public class ValueFloatChangeActionOperation implements ActionOperation {
@Override
public void apply(RemoteContext context) {}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
new file mode 100644
index 000000000000..41586b4939a6
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.layout.modifiers;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+
+import android.annotation.NonNull;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.ActionOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+
+import java.util.List;
+
+/** Apply a value change on an integer variable. */
+public class ValueFloatExpressionChangeActionOperation implements ActionOperation {
+ private static final int OP_CODE = Operations.VALUE_FLOAT_EXPRESSION_CHANGE_ACTION;
+
+ int mTargetValueId = -1;
+ int mValueExpressionId = -1;
+
+ public ValueFloatExpressionChangeActionOperation(int id, int valueId) {
+ mTargetValueId = id;
+ mValueExpressionId = valueId;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "ValueFloatExpressionChangeActionOperation(" + mTargetValueId + ")";
+ }
+
+ @NonNull
+ public String serializedName() {
+ return "VALUE_FLOAT_EXPRESSION_CHANGE";
+ }
+
+ @Override
+ public void serializeToString(int indent, @NonNull StringSerializer serializer) {
+ serializer.append(
+ indent, serializedName() + " = " + mTargetValueId + " -> " + mValueExpressionId);
+ }
+
+ @Override
+ public void apply(RemoteContext context) {}
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return (indent != null ? indent : "") + toString();
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {}
+
+ @Override
+ public void runAction(
+ @NonNull RemoteContext context,
+ @NonNull CoreDocument document,
+ Component component,
+ float x,
+ float y) {
+ document.evaluateFloatExpression(mValueExpressionId, mTargetValueId, context);
+ }
+
+ public static void apply(@NonNull WireBuffer buffer, int valueId, int value) {
+ buffer.start(OP_CODE);
+ buffer.writeInt(valueId);
+ buffer.writeInt(value);
+ }
+
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ int valueId = buffer.readInt();
+ int value = buffer.readInt();
+ operations.add(new ValueFloatExpressionChangeActionOperation(valueId, value));
+ }
+
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation")
+ .description(
+ "ValueIntegerExpressionChange action. "
+ + " This operation represents a value change for the given id")
+ .field(INT, "TARGET_VALUE_ID", "Value ID")
+ .field(INT, "VALUE_ID", "id of the value to be assigned to the target");
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
index d7ce8acc72bf..c2cd2ab32bb7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -61,22 +60,22 @@ public class ValueIntegerChangeActionOperation implements ActionOperation {
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@Override
- public void write(WireBuffer buffer) {}
+ public void write(@NonNull WireBuffer buffer) {}
@Override
public void runAction(
@NonNull RemoteContext context,
- CoreDocument document,
- Component component,
+ @NonNull CoreDocument document,
+ @NonNull Component component,
float x,
float y) {
context.overrideInteger(mTargetValueId, mValue);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
index 75d13e785d4c..43fbb8546b9d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -62,22 +61,22 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@Override
- public void write(WireBuffer buffer) {}
+ public void write(@NonNull WireBuffer buffer) {}
@Override
public void runAction(
@NonNull RemoteContext context,
@NonNull CoreDocument document,
- Component component,
+ @NonNull Component component,
float x,
float y) {
document.evaluateIntExpression(mValueExpressionId, (int) mTargetValueId, context);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
index 26d7244eee8c..1107889faaab 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
@@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -65,22 +64,22 @@ public class ValueStringChangeActionOperation implements ActionOperation {
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(@Nullable String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
@Override
- public void write(WireBuffer buffer) {}
+ public void write(@NonNull WireBuffer buffer) {}
@Override
public void runAction(
@NonNull RemoteContext context,
- CoreDocument document,
- Component component,
+ @NonNull CoreDocument document,
+ @NonNull Component component,
float x,
float y) {
context.overrideText(mTargetValueId, mValueId);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
index e2f899ce2b46..3c757a893a57 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
@@ -54,7 +54,7 @@ public class WidthModifierOperation extends DimensionModifierOperation {
operations.add(op);
}
- public WidthModifierOperation(Type type, float value) {
+ public WidthModifierOperation(@NonNull Type type, float value) {
super(type, value);
}
@@ -63,7 +63,7 @@ public class WidthModifierOperation extends DimensionModifierOperation {
apply(buffer, mType.ordinal(), mValue);
}
- public WidthModifierOperation(Type type) {
+ public WidthModifierOperation(@NonNull Type type) {
super(type);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
index aa20e0388d31..82c8f343565e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
@@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
@@ -57,8 +59,9 @@ public class ZIndexModifierOperation extends DecoratorModifierOperation {
serializer.append(indent, "ZINDEX = [" + mValue + "]");
}
+ @NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return (indent != null ? indent : "") + toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java
index d8e49b0a9ccd..842c9c161aee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java
@@ -27,11 +27,11 @@ public class DebugLog {
public static class Node {
@Nullable public Node parent;
- public String name;
- public String endString;
+ @NonNull public String name;
+ @NonNull public String endString;
@NonNull public ArrayList<Node> list = new ArrayList<>();
- public Node(@Nullable Node parent, String name) {
+ public Node(@Nullable Node parent, @NonNull String name) {
this.parent = parent;
this.name = name;
this.endString = name + " DONE";
@@ -40,13 +40,13 @@ public class DebugLog {
}
}
- public void add(Node node) {
+ public void add(@NonNull Node node) {
list.add(node);
}
}
public static class LogNode extends Node {
- public LogNode(Node parent, String name) {
+ public LogNode(@Nullable Node parent, @NonNull String name) {
super(parent, name);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java
index 701167abb8f0..5ec149390b84 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout.utils;
+import android.annotation.NonNull;
+
/** Basic interface for a lambda (used for logging) */
public interface StringValueSupplier {
/**
@@ -22,5 +24,6 @@ public interface StringValueSupplier {
*
* @return a string
*/
+ @NonNull
String getString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index e714947c6a5c..07cf7627e24d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.VariableSupport;
@@ -25,8 +28,8 @@ import java.util.Arrays;
/** Paint Bundle represents a delta of changes to a paint object */
public class PaintBundle {
- int[] mArray = new int[200];
- int[] mOutArray = null;
+ @NonNull int[] mArray = new int[200];
+ @Nullable int[] mOutArray = null;
int mPos = 0;
/**
@@ -35,7 +38,7 @@ public class PaintBundle {
* @param paintContext
* @param p
*/
- public void applyPaintChange(PaintContext paintContext, PaintChanges p) {
+ public void applyPaintChange(@NonNull PaintContext paintContext, @NonNull PaintChanges p) {
int i = 0;
int mask = 0;
if (mOutArray == null) {
@@ -138,12 +141,14 @@ public class PaintBundle {
// return "????" + id + "????";
// }
+ @NonNull
private static String colorInt(int color) {
String str = "000000000000" + Integer.toHexString(color);
return "0x" + str.substring(str.length() - 8);
}
- private static String colorInt(int[] color) {
+ @NonNull
+ private static String colorInt(@NonNull int[] color) {
String str = "[";
for (int i = 0; i < color.length; i++) {
if (i > 0) {
@@ -162,6 +167,7 @@ public class PaintBundle {
return Float.toString(fValue);
}
+ @NonNull
@Override
public String toString() {
StringBuilder ret = new StringBuilder("\n");
@@ -244,7 +250,8 @@ public class PaintBundle {
return ret.toString();
}
- private void registerFloat(int iv, RemoteContext context, VariableSupport support) {
+ private void registerFloat(
+ int iv, @NonNull RemoteContext context, @NonNull VariableSupport support) {
float v = Float.intBitsToFloat(iv);
if (Float.isNaN(v)) {
context.listensTo(Utils.idFromNan(v), support);
@@ -252,7 +259,11 @@ public class PaintBundle {
}
int callRegisterGradient(
- int cmd, int[] array, int i, RemoteContext context, VariableSupport support) {
+ int cmd,
+ int[] array,
+ int i,
+ @NonNull RemoteContext context,
+ @NonNull VariableSupport support) {
int ret = i;
int type = (cmd >> 16);
int control = array[ret++];
@@ -343,7 +354,7 @@ public class PaintBundle {
return ret;
}
- int callPrintGradient(int cmd, int[] array, int i, StringBuilder p) {
+ int callPrintGradient(int cmd, int[] array, int i, @NonNull StringBuilder p) {
int ret = i;
int type = (cmd >> 16);
int tileMode = 0;
@@ -432,7 +443,7 @@ public class PaintBundle {
return ret;
}
- int callSetGradient(int cmd, int[] array, int i, PaintChanges p) {
+ int callSetGradient(int cmd, @NonNull int[] array, int i, @NonNull PaintChanges p) {
int ret = i;
int gradientType = (cmd >> 16);
@@ -487,14 +498,14 @@ public class PaintBundle {
return ret;
}
- public void writeBundle(WireBuffer buffer) {
+ public void writeBundle(@NonNull WireBuffer buffer) {
buffer.writeInt(mPos);
for (int index = 0; index < mPos; index++) {
buffer.writeInt(mArray[index]);
}
}
- public void readBundle(WireBuffer buffer) {
+ public void readBundle(@NonNull WireBuffer buffer) {
int len = buffer.readInt();
if (len <= 0 || len > 1024) {
throw new RuntimeException("buffer corrupt paint len = " + len);
@@ -589,9 +600,9 @@ public class PaintBundle {
* @param tileMode The Shader tiling mode
*/
public void setLinearGradient(
- int[] colors,
+ @NonNull int[] colors,
int idMask,
- float[] stops,
+ @Nullable float[] stops,
float startX,
float startY,
float endX,
@@ -600,7 +611,7 @@ public class PaintBundle {
// int startPos = mPos;
int len;
mArray[mPos++] = GRADIENT | (LINEAR_GRADIENT << 16);
- mArray[mPos++] = (idMask << 16) | (len = (colors == null) ? 0 : colors.length);
+ mArray[mPos++] = (idMask << 16) | (len = colors.length);
for (int i = 0; i < len; i++) {
mArray[mPos++] = colors[i];
}
@@ -629,7 +640,12 @@ public class PaintBundle {
* spaced evenly.
*/
public void setSweepGradient(
- int[] colors, int idMask, float[] stops, float centerX, float centerY) {
+ @NonNull int[] colors,
+ int idMask,
+ @Nullable float[] stops, // TODO: rename positions to stops or stops to positions, but
+ // don't have both in the same file
+ float centerX,
+ float centerY) {
int len;
mArray[mPos++] = GRADIENT | (SWEEP_GRADIENT << 16);
mArray[mPos++] = (idMask << 16) | (len = (colors == null) ? 0 : colors.length);
@@ -659,9 +675,9 @@ public class PaintBundle {
* @param tileMode The Shader tiling mode
*/
public void setRadialGradient(
- int[] colors,
+ @NonNull int[] colors,
int idMask,
- float[] stops,
+ @Nullable float[] stops,
float centerX,
float centerY,
float radius,
@@ -900,7 +916,7 @@ public class PaintBundle {
mPos = 0;
}
- public static String blendModeString(int mode) {
+ public static @NonNull String blendModeString(int mode) {
switch (mode) {
case PaintBundle.BLEND_MODE_CLEAR:
return "CLEAR";
@@ -974,7 +990,7 @@ public class PaintBundle {
* @param context
* @param support
*/
- public void registerVars(RemoteContext context, VariableSupport support) {
+ public void registerVars(@NonNull RemoteContext context, @NonNull VariableSupport support) {
int i = 0;
while (i < mPos) {
int cmd = mArray[i++];
@@ -1020,7 +1036,7 @@ public class PaintBundle {
*
* @param context
*/
- public void updateVariables(RemoteContext context) {
+ public void updateVariables(@NonNull RemoteContext context) {
if (mOutArray == null) {
mOutArray = Arrays.copyOf(mArray, mArray.length);
} else {
@@ -1066,7 +1082,7 @@ public class PaintBundle {
}
}
- private int fixFloatVar(int val, RemoteContext context) {
+ private int fixFloatVar(int val, @NonNull RemoteContext context) {
float v = Float.intBitsToFloat(val);
if (Float.isNaN(v)) {
int id = Utils.idFromNan(v);
@@ -1075,12 +1091,13 @@ public class PaintBundle {
return val;
}
- private int fixColor(int colorId, RemoteContext context) {
+ private int fixColor(int colorId, @NonNull RemoteContext context) {
int n = context.getColor(colorId);
return n;
}
- int updateFloatsInGradient(int cmd, int[] out, int[] array, int i, RemoteContext context) {
+ int updateFloatsInGradient(
+ int cmd, int[] out, int[] array, int i, @NonNull RemoteContext context) {
int ret = i;
int type = (cmd >> 16);
int control = array[ret++];
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
index e2402be4e4d4..87a663266e0e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
public class PaintChangeAdapter implements PaintChanges {
@Override
@@ -64,8 +67,8 @@ public class PaintChangeAdapter implements PaintChanges {
@Override
public void setLinearGradient(
- int[] colorsArray,
- float[] stopsArray,
+ @NonNull int[] colorsArray,
+ @Nullable float[] stopsArray,
float startX,
float startY,
float endX,
@@ -74,8 +77,8 @@ public class PaintChangeAdapter implements PaintChanges {
@Override
public void setRadialGradient(
- int[] colorsArray,
- float[] stopsArray,
+ @NonNull int[] colorsArray,
+ @Nullable float[] stopsArray,
float centerX,
float centerY,
float radius,
@@ -83,7 +86,10 @@ public class PaintChangeAdapter implements PaintChanges {
@Override
public void setSweepGradient(
- int[] colorsArray, float[] stopsArray, float centerX, float centerY) {}
+ @NonNull int[] colorsArray,
+ @Nullable float[] stopsArray,
+ float centerX,
+ float centerY) {}
@Override
public void setColorFilter(int color, int mode) {}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
index 486d763cb6d5..e68164716a44 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/** Interface to a paint object For more details see Android Paint */
public interface PaintChanges {
@@ -135,7 +138,7 @@ public interface PaintChanges {
* Set a linear gradient fill
*
* @param colorsArray
- * @param stopsArray
+ * @param stopsArray // todo: standardize naming
* @param startX
* @param startY
* @param endX
@@ -143,8 +146,8 @@ public interface PaintChanges {
* @param tileMode
*/
void setLinearGradient(
- int[] colorsArray,
- float[] stopsArray,
+ @NonNull int[] colorsArray,
+ @Nullable float[] stopsArray,
float startX,
float startY,
float endX,
@@ -155,15 +158,15 @@ public interface PaintChanges {
* Set a radial gradient fill
*
* @param colorsArray
- * @param stopsArray
+ * @param stopsArray // todo: standardize naming
* @param centerX
* @param centerY
* @param radius
* @param tileMode
*/
void setRadialGradient(
- int[] colorsArray,
- float[] stopsArray,
+ @NonNull int[] colorsArray,
+ @Nullable float[] stopsArray,
float centerX,
float centerY,
float radius,
@@ -173,11 +176,12 @@ public interface PaintChanges {
* Set a sweep gradient fill
*
* @param colorsArray
- * @param stopsArray
+ * @param stopsArray // todo: standardize naming to either "positions" or "stops"
* @param centerX
* @param centerY
*/
- void setSweepGradient(int[] colorsArray, float[] stopsArray, float centerX, float centerY);
+ void setSweepGradient(
+ @NonNull int[] colorsArray, @Nullable float[] stopsArray, float centerX, float centerY);
/**
* Set Color filter mod
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java
index a808cf0e17b3..e5f6f2838d34 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java
@@ -16,6 +16,7 @@
package com.android.internal.widget.remotecompose.core.operations.paint;
import android.annotation.NonNull;
+import android.annotation.Nullable;
/** Provides a Builder pattern for a PaintBundle */
class Painter {
@@ -173,8 +174,8 @@ class Painter {
float centerX,
float centerY,
float radius,
- int[] colors,
- float[] positions,
+ @NonNull int[] colors,
+ @NonNull float[] positions,
int tileMode) {
mPaint.setRadialGradient(colors, 0, positions, centerX, centerY, radius, tileMode);
return this;
@@ -193,7 +194,8 @@ class Painter {
* spaced evenly.
*/
@NonNull
- public Painter setSweepGradient(float centerX, float centerY, int[] colors, float[] positions) {
+ public Painter setSweepGradient(
+ float centerX, float centerY, @NonNull int[] colors, @Nullable float[] positions) {
mPaint.setSweepGradient(colors, 0, positions, centerX, centerY);
return this;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java
index 1c0bec76bb62..ff6f45db5385 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+import android.annotation.NonNull;
+
+// TODO: this interface is unused. Delete it.
public interface TextPaint {
void setARGB(int a, int r, int g, int b);
@@ -28,7 +31,7 @@ public interface TextPaint {
void setFlags(int flags);
- void setFontFeatureSettings(String settings);
+ void setFontFeatureSettings(@NonNull String settings);
void setHinting(int mode);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
index b25f4cd3c530..e5633c70faee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
@@ -18,6 +18,9 @@ package com.android.internal.widget.remotecompose.core.operations.utilities;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.MonotonicSpline;
+
/** high performance floating point expression evaluator used in animation */
public class AnimatedFloatExpression {
@NonNull static IntMap<String> sNames = new IntMap<>();
@@ -64,20 +67,37 @@ public class AnimatedFloatExpression {
public static final float A_SUM = asNan(OFFSET + 35);
public static final float A_AVG = asNan(OFFSET + 36);
public static final float A_LEN = asNan(OFFSET + 37);
- public static final int LAST_OP = OFFSET + 37;
+ public static final float A_SPLINE = asNan(OFFSET + 38);
+
+ public static final int LAST_OP = OFFSET + 38;
- public static final float VAR1 = asNan(OFFSET + 38);
- public static final float VAR2 = asNan(OFFSET + 39);
+ public static final float VAR1 = asNan(OFFSET + 39);
+ public static final float VAR2 = asNan(OFFSET + 40);
// TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR
// private static final float FP_PI = (float) Math.PI;
private static final float FP_TO_RAD = 57.29578f; // 180/PI
private static final float FP_TO_DEG = 0.017453292f; // 180/PI
- float[] mStack;
+ @NonNull float[] mStack = new float[0];
@NonNull float[] mLocalStack = new float[128];
- float[] mVar;
- CollectionsAccess mCollectionsAccess;
+ @NonNull float[] mVar = new float[0];
+ @Nullable CollectionsAccess mCollectionsAccess;
+ IntMap<MonotonicSpline> mSplineMap = new IntMap<>();
+
+ private float getSplineValue(int arrayId, float pos) {
+ MonotonicSpline fit = mSplineMap.get(arrayId);
+ float[] f = mCollectionsAccess.getFloats(arrayId);
+ if (fit != null) {
+ if (fit.getArray() == f) { // the array has not changed.
+ return fit.getPos(pos);
+ }
+ }
+
+ fit = new MonotonicSpline(null, f);
+ mSplineMap.put(arrayId, fit);
+ return fit.getPos(pos);
+ }
/**
* is float a math operator
@@ -114,7 +134,7 @@ public class AnimatedFloatExpression {
* @param var
* @return
*/
- public float eval(float[] exp, float... var) {
+ public float eval(@NonNull float[] exp, @NonNull float... var) {
mStack = exp;
mVar = var;
int sp = -1;
@@ -137,7 +157,8 @@ public class AnimatedFloatExpression {
* @param var
* @return
*/
- public float eval(CollectionsAccess ca, float[] exp, int len, float... var) {
+ public float eval(
+ @NonNull CollectionsAccess ca, @NonNull float[] exp, int len, @NonNull float... var) {
System.arraycopy(exp, 0, mLocalStack, 0, len);
mStack = mLocalStack;
mVar = var;
@@ -167,7 +188,7 @@ public class AnimatedFloatExpression {
* @param exp
* @return
*/
- public float eval(CollectionsAccess ca, float[] exp, int len) {
+ public float eval(@NonNull CollectionsAccess ca, @NonNull float[] exp, int len) {
System.arraycopy(exp, 0, mLocalStack, 0, len);
mStack = mLocalStack;
mCollectionsAccess = ca;
@@ -189,7 +210,7 @@ public class AnimatedFloatExpression {
return mStack[sp];
}
- private int dereference(CollectionsAccess ca, int id, int sp) {
+ private int dereference(@NonNull CollectionsAccess ca, int id, int sp) {
mStack[sp] = ca.getFloatValue(id, (int) (mStack[sp]));
return sp;
}
@@ -202,7 +223,7 @@ public class AnimatedFloatExpression {
* @param var
* @return
*/
- public float eval(@NonNull float[] exp, int len, float... var) {
+ public float eval(@NonNull float[] exp, int len, @NonNull float... var) {
System.arraycopy(exp, 0, mLocalStack, 0, len);
mStack = mLocalStack;
mVar = var;
@@ -225,13 +246,12 @@ public class AnimatedFloatExpression {
* @param var
* @return
*/
- public float evalDB(@NonNull float[] exp, float... var) {
+ public float evalDB(@NonNull float[] exp, @NonNull float... var) {
mStack = exp;
mVar = var;
int sp = -1;
for (float v : exp) {
if (Float.isNaN(v)) {
- System.out.print(" " + sNames.get((fromNaN(v) - OFFSET)));
sp = mOps[fromNaN(v) - OFFSET].eval(sp);
} else {
System.out.print(" " + v);
@@ -375,12 +395,12 @@ public class AnimatedFloatExpression {
return sp - 2;
};
Op mCLAMP =
- (sp) -> { // CLAMP
+ (sp) -> { // CLAMP (min, max, value)
mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]);
return sp - 2;
};
Op mCBRT =
- (sp) -> { // CBRT
+ (sp) -> { // CBRT is cube root
mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.);
return sp;
};
@@ -401,8 +421,10 @@ public class AnimatedFloatExpression {
};
Op mA_DEREF =
(sp) -> { // A_DEREF
- int id = fromNaN(mStack[sp]);
- mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp - 1]);
+ Utils.log(" \n >>> DREF " + Integer.toHexString(fromNaN(mStack[sp - 1])));
+ Utils.log(" >>> DREF " + mStack[sp] + " " + mStack[sp - 1]);
+ int id = fromNaN(mStack[sp - 1]);
+ mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp]);
return sp - 1;
};
Op mA_MAX =
@@ -420,11 +442,14 @@ public class AnimatedFloatExpression {
(sp) -> { // A_MIN
int id = fromNaN(mStack[sp]);
float[] array = mCollectionsAccess.getFloats(id);
- float max = array[0];
+ if (array.length == 0) {
+ return sp;
+ }
+ float min = array[0];
for (int i = 1; i < array.length; i++) {
- max = Math.max(max, array[i]);
+ min = Math.min(min, array[i]);
}
- mStack[sp] = max;
+ mStack[sp] = min;
return sp;
};
Op mA_SUM =
@@ -455,6 +480,12 @@ public class AnimatedFloatExpression {
mStack[sp] = mCollectionsAccess.getListLength(id);
return sp;
};
+ Op mA_SPLINE =
+ (sp) -> { // A_SPLINE
+ int id = fromNaN(mStack[sp - 1]);
+ mStack[sp - 1] = getSplineValue(id, mStack[sp]);
+ return sp - 1;
+ };
Op mFIRST_VAR =
(sp) -> { // FIRST_VAR
mStack[sp] = mVar[0];
@@ -510,6 +541,7 @@ public class AnimatedFloatExpression {
mA_SUM,
mA_AVG,
mA_LEN,
+ mA_SPLINE,
mFIRST_VAR,
mSECOND_VAR,
mTHIRD_VAR,
@@ -558,6 +590,7 @@ public class AnimatedFloatExpression {
sNames.put(k++, "A_SUM");
sNames.put(k++, "A_AVG");
sNames.put(k++, "A_LEN");
+ sNames.put(k++, "A_SPLINE");
sNames.put(k++, "a[0]");
sNames.put(k++, "a[1]");
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java
index eb5e4828f2a0..182d36a5eb06 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.utilities;
+import android.annotation.Nullable;
+
/**
* Support a standardized interface to commands that contain arrays All commands that implement
* array access will be collected in a map in the state TODO refactor to DataAccess,
@@ -27,6 +29,7 @@ public interface ArrayAccess {
return 0;
}
+ @Nullable
float[] getFloats();
int getLength();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java
index 0128253e1f90..4f1287265d75 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.utilities;
+import android.annotation.Nullable;
+
/**
* interface to allow expressions to access collections Todo define a convention for when access is
* unavailable
@@ -22,6 +24,7 @@ package com.android.internal.widget.remotecompose.core.operations.utilities;
public interface CollectionsAccess {
float getFloatValue(int id, int index);
+ @Nullable
float[] getFloats(int id);
int getListLength(int id);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java
index 24f17d7b00c7..07a3d8482db2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java
@@ -15,18 +15,20 @@
*/
package com.android.internal.widget.remotecompose.core.operations.utilities;
+import android.annotation.NonNull;
+
public class DataMap {
- public String[] mNames;
- public int[] mIds;
- public byte[] mTypes;
+ @NonNull public final String[] mNames;
+ @NonNull public final int[] mIds;
+ @NonNull public final byte[] mTypes;
- public DataMap(String[] names, byte[] types, int[] ids) {
+ public DataMap(@NonNull String[] names, @NonNull byte[] types, @NonNull int[] ids) {
mNames = names;
mTypes = types;
mIds = ids;
}
- public int getPos(String str) {
+ public int getPos(@NonNull String str) {
for (int i = 0; i < mNames.length; i++) {
String name = mNames[i];
if (str.equals(name)) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java
index e74b3350f427..98ee91b370e0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java
@@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.utilities;
import android.annotation.NonNull;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
+
/** Implement the scaling logic for Compose Image or ImageView */
public class ImageScaling {
@@ -109,7 +111,7 @@ public class ImageScaling {
String s = str;
s += str(left) + ", " + str(top) + ", " + str(right) + ", " + str(bottom) + ", ";
s += " [" + str(right - left) + " x " + str(bottom - top) + "]";
- System.out.println(s);
+ Utils.log(s);
}
/** This adjust destnation on the DrawBitMapInt to support all contentScale types */
@@ -128,7 +130,7 @@ public class ImageScaling {
print("test rc ", mSrcLeft, mSrcTop, mSrcRight, mSrcBottom);
print("test dst ", mDstLeft, mDstTop, mDstRight, mDstBottom);
}
-
+ if (sh == 0 || sw == 0) return;
switch (mScaleType) {
case SCALE_NONE:
dh = sh;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
index 749c0fe0dcc3..b9aa88146f2a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.widget.remotecompose.core.operations.utilities;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import java.util.ArrayList;
@@ -45,7 +46,7 @@ public class IntMap<T> {
}
@Nullable
- public T put(int key, T value) {
+ public T put(int key, @NonNull T value) {
if (key == NOT_PRESENT) throw new IllegalArgumentException("Key cannot be NOT_PRESENT");
if (mSize > mKeys.length * LOAD_FACTOR) {
resize();
@@ -66,7 +67,7 @@ public class IntMap<T> {
}
@Nullable
- private T insert(int key, T value) {
+ private T insert(int key, @NonNull T value) {
int index = hash(key) % mKeys.length;
while (mKeys[index] != NOT_PRESENT && mKeys[index] != key) {
index = (index + 1) % mKeys.length;
@@ -116,6 +117,7 @@ public class IntMap<T> {
}
}
+ @Nullable
public T remove(int key) {
int index = hash(key) % mKeys.length;
int initialIndex = index;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java
index 8905431d14d7..f73ab39e496e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java
@@ -59,9 +59,9 @@ public class IntegerExpressionEvaluator {
public static final int I_VAR1 = OFFSET + 24;
public static final int I_VAR2 = OFFSET + 25;
- int[] mStack;
+ @NonNull int[] mStack = new int[0];
@NonNull int[] mLocalStack = new int[128];
- int[] mVar;
+ @NonNull int[] mVar = new int[0];
interface Op {
int eval(int sp);
@@ -75,7 +75,7 @@ public class IntegerExpressionEvaluator {
* @param var variables if the expression is a function
* @return return the results of evaluating the expression
*/
- public int eval(int mask, int[] exp, int... var) {
+ public int eval(int mask, @NonNull int[] exp, @NonNull int... var) {
mStack = exp;
mVar = var;
int sp = -1;
@@ -99,7 +99,7 @@ public class IntegerExpressionEvaluator {
* @param var variables if the expression is a function
* @return return the results of evaluating the expression
*/
- public int eval(int mask, @NonNull int[] exp, int len, int... var) {
+ public int eval(int mask, @NonNull int[] exp, int len, @NonNull int... var) {
System.arraycopy(exp, 0, mLocalStack, 0, len);
mStack = mLocalStack;
mVar = var;
@@ -123,17 +123,15 @@ public class IntegerExpressionEvaluator {
* @param var variables if the expression is a function
* @return return the results of evaluating the expression
*/
- public int evalDB(int opMask, @NonNull int[] exp, int... var) {
+ public int evalDB(int opMask, @NonNull int[] exp, @NonNull int... var) {
mStack = exp;
mVar = var;
int sp = -1;
for (int i = 0; i < exp.length; i++) {
int v = mStack[i];
if (((1 << i) & opMask) != 0) {
- System.out.print(" " + sNames.get((v - OFFSET)));
sp = mOps[v - OFFSET].eval(sp);
} else {
- System.out.print(" " + v);
mStack[++sp] = v;
}
}
@@ -199,7 +197,7 @@ public class IntegerExpressionEvaluator {
return sp - 1;
};
Op mCOPY_SIGN =
- (sp) -> { // COPY_SIGN
+ (sp) -> { // COPY_SIGN copy the sign via bit manipulation
mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31);
return sp - 1;
};
@@ -239,12 +237,12 @@ public class IntegerExpressionEvaluator {
return sp;
};
Op mSIGN =
- (sp) -> { // SIGN
+ (sp) -> { // SIGN x<0 = -1,x==0 = 0 , x>0 = 1
mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31);
return sp;
};
Op mCLAMP =
- (sp) -> { // CLAMP
+ (sp) -> { // CLAMP(min,max, val)
mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]);
return sp - 2;
};
@@ -360,7 +358,7 @@ public class IntegerExpressionEvaluator {
* @return
*/
@NonNull
- public static String toString(int opMask, @NonNull int[] exp, String[] labels) {
+ public static String toString(int opMask, @NonNull int[] exp, @NonNull String[] labels) {
StringBuilder s = new StringBuilder();
for (int i = 0; i < exp.length; i++) {
int v = exp[i];
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
index ebb22b6e98c5..465c95d06726 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
@@ -57,13 +57,17 @@ public class FloatAnimation extends Easing {
mEasingCurve = new CubicEasing(mType);
}
- public FloatAnimation(float... description) {
+ public FloatAnimation(@NonNull float... description) {
mType = CUBIC_STANDARD;
setAnimationDescription(description);
}
public FloatAnimation(
- int type, float duration, float[] description, float initialValue, float wrap) {
+ int type,
+ float duration,
+ @Nullable float[] description,
+ float initialValue,
+ float wrap) {
mType = CUBIC_STANDARD;
setAnimationDescription(packToFloatArray(duration, type, description, initialValue, wrap));
}
@@ -77,7 +81,7 @@ public class FloatAnimation extends Easing {
* @param initialValue
* @return
*/
- public static float[] packToFloatArray(
+ public static @NonNull float[] packToFloatArray(
float duration, int type, @Nullable float[] spec, float initialValue, float wrap) {
int count = 0;
@@ -221,7 +225,7 @@ public class FloatAnimation extends Easing {
*
* @param description
*/
- public void setAnimationDescription(float[] description) {
+ public void setAnimationDescription(@NonNull float[] description) {
mSpec = description;
mDuration = (mSpec.length == 0) ? 1 : mSpec[0];
int len = 0;
@@ -242,7 +246,7 @@ public class FloatAnimation extends Easing {
create(mType, description, 2, len);
}
- private void create(int type, float[] params, int offset, int len) {
+ private void create(int type, @Nullable float[] params, int offset, int len) {
switch (type) {
case CUBIC_STANDARD:
case CUBIC_ACCELERATE:
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
index 90b65bf2353a..06969ccd1b10 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
@@ -19,7 +19,7 @@ import android.annotation.NonNull;
/** Provides and interface to create easing functions */
public class GeneralEasing extends Easing {
- float[] mEasingData = new float[0];
+ @NonNull float[] mEasingData = new float[0];
@NonNull Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD);
/**
@@ -27,12 +27,12 @@ public class GeneralEasing extends Easing {
*
* @param data
*/
- public void setCurveSpecification(float[] data) {
+ public void setCurveSpecification(@NonNull float[] data) {
mEasingData = data;
createEngine();
}
- public float[] getCurveSpecification() {
+ public @NonNull float[] getCurveSpecification() {
return mEasingData;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
index f540e7008471..f4579a24fd44 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
@@ -22,11 +22,11 @@ import java.util.Arrays;
/** This performs a spline interpolation in multiple dimensions */
public class MonotonicCurveFit {
private static final String TAG = "MonotonicCurveFit";
- private double[] mT;
- private double[][] mY;
- private double[][] mTangent;
+ @NonNull private final double[] mT;
+ @NonNull private final double[][] mY;
+ @NonNull private final double[][] mTangent;
private boolean mExtrapolate = true;
- double[] mSlopeTemp;
+ @NonNull final double[] mSlopeTemp;
/**
* create a collection of curves
@@ -81,7 +81,7 @@ public class MonotonicCurveFit {
* @param t
* @param v
*/
- public void getPos(double t, double[] v) {
+ public void getPos(double t, @NonNull double[] v) {
final int n = mT.length;
final int dim = mY[0].length;
if (mExtrapolate) {
@@ -141,7 +141,7 @@ public class MonotonicCurveFit {
* @param t
* @param v
*/
- public void getPos(double t, float[] v) {
+ public void getPos(double t, @NonNull float[] v) {
final int n = mT.length;
final int dim = mY[0].length;
if (mExtrapolate) {
@@ -243,7 +243,7 @@ public class MonotonicCurveFit {
* @param t
* @param v
*/
- public void getSlope(double t, double[] v) {
+ public void getSlope(double t, @NonNull double[] v) {
final int n = mT.length;
int dim = mY[0].length;
if (t <= mT[0]) {
@@ -297,7 +297,7 @@ public class MonotonicCurveFit {
return 0; // should never reach here
}
- public double[] getTimePoints() {
+ public @NonNull double[] getTimePoints() {
return mT;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicSpline.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicSpline.java
new file mode 100644
index 000000000000..23a664336c5f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicSpline.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/** This performs a spline interpolation in multiple dimensions */
+public class MonotonicSpline {
+ private static final String TAG = "MonotonicCurveFit";
+ private float[] mT;
+ private float[] mY;
+ private float[] mTangent;
+ private boolean mExtrapolate = true;
+ float[] mSlopeTemp;
+
+ /**
+ * create a collection of curves
+ *
+ * @param time the point along the curve
+ * @param y the parameter at those points
+ */
+ public MonotonicSpline(@Nullable float[] time, @NonNull float[] y) {
+ if (time == null) { // if time is null assume even 0 to 1;
+ time = new float[y.length];
+ for (int i = 0; i < time.length; i++) {
+ time[i] = i / (float) (time.length - 1);
+ }
+ }
+ mT = time;
+ mY = y;
+ final int n = time.length;
+ final int dim = 1;
+ mSlopeTemp = new float[dim];
+ float[] slope = new float[n - 1]; // could optimize this out
+ float[] tangent = new float[n];
+ for (int i = 0; i < n - 1; i++) {
+ float dt = time[i + 1] - time[i];
+ slope[i] = (y[i + 1] - y[i]) / dt;
+ if (i == 0) {
+ tangent[i] = slope[i];
+ } else {
+ tangent[i] = (slope[i - 1] + slope[i]) * 0.5f;
+ }
+ }
+ tangent[n - 1] = slope[n - 2];
+
+ for (int i = 0; i < n - 1; i++) {
+ if (slope[i] == 0.) {
+ tangent[i] = 0f;
+ tangent[i + 1] = 0f;
+ } else {
+ float a = tangent[i] / slope[i];
+ float b = tangent[i + 1] / slope[i];
+ float h = (float) Math.hypot(a, b);
+ if (h > 9.0) {
+ float t = 3f / h;
+ tangent[i] = t * a * slope[i];
+ tangent[i + 1] = t * b * slope[i];
+ }
+ }
+ }
+ mTangent = tangent;
+ }
+
+ public float[] getArray() {
+ return mY;
+ }
+
+ /**
+ * Get the position of all curves at time t
+ *
+ * @param t
+ * @return position at t
+ */
+ public float getPos(float t) {
+ final int n = mT.length;
+ float v;
+ if (mExtrapolate) {
+ if (t <= mT[0]) {
+ float slopeTemp = getSlope(mT[0]);
+ v = mY[0] + (t - mT[0]) * slopeTemp;
+
+ return v;
+ }
+ if (t >= mT[n - 1]) {
+ float slopeTemp = getSlope(mT[n - 1]);
+ v = mY[n - 1] + (t - mT[n - 1]) * slopeTemp;
+
+ return v;
+ }
+ } else {
+ if (t <= mT[0]) {
+ v = mY[0];
+
+ return v;
+ }
+ if (t >= mT[n - 1]) {
+ v = mY[n - 1];
+
+ return v;
+ }
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t == mT[i]) {
+
+ v = mY[i];
+ }
+ if (t < mT[i + 1]) {
+ float h = mT[i + 1] - mT[i];
+ float x = (t - mT[i]) / h;
+
+ float y1 = mY[i];
+ float y2 = mY[i + 1];
+ float t1 = mTangent[i];
+ float t2 = mTangent[i + 1];
+ v = interpolate(h, x, y1, y2, t1, t2);
+
+ return v;
+ }
+ }
+ return 0f;
+ }
+
+ /**
+ * Get the slope of the curve at position t
+ *
+ * @param t
+ * @return slope at t
+ */
+ public float getSlope(float t) {
+ final int n = mT.length;
+ float v = 0;
+
+ if (t <= mT[0]) {
+ t = mT[0];
+ } else if (t >= mT[n - 1]) {
+ t = mT[n - 1];
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t <= mT[i + 1]) {
+ float h = mT[i + 1] - mT[i];
+ float x = (t - mT[i]) / h;
+ float y1 = mY[i];
+ float y2 = mY[i + 1];
+ float t1 = mTangent[i];
+ float t2 = mTangent[i + 1];
+ v = diff(h, x, y1, y2, t1, t2) / h;
+ }
+ break;
+ }
+ return v;
+ }
+
+ public float[] getTimePoints() {
+ return mT;
+ }
+
+ /** Cubic Hermite spline */
+ private static float interpolate(float h, float x, float y1, float y2, float t1, float t2) {
+ float x2 = x * x;
+ float x3 = x2 * x;
+ return -2 * x3 * y2
+ + 3 * x2 * y2
+ + 2 * x3 * y1
+ - 3 * x2 * y1
+ + y1
+ + h * t2 * x3
+ + h * t1 * x3
+ - h * t2 * x2
+ - 2 * h * t1 * x2
+ + h * t1 * x;
+ }
+
+ /** Cubic Hermite spline slope differentiated */
+ private static float diff(float h, float x, float y1, float y2, float t1, float t2) {
+ float x2 = x * x;
+ return -6 * x2 * y2
+ + 6 * x * y2
+ + 6 * x2 * y1
+ - 6 * x * y1
+ + 3 * h * t2 * x2
+ + 3 * h * t1 * x2
+ - 2 * h * t2 * x
+ - 4 * h * t1 * x
+ + h * t1;
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/SpringStopEngine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/SpringStopEngine.java
new file mode 100644
index 000000000000..03e45031e515
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/SpringStopEngine.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * This contains the class to provide the logic for an animation to come to a stop using a spring
+ * model. String debug(String desc, float time); float getVelocity(float time); float
+ * getInterpolation(float time); float getVelocity(); boolean isStopped();
+ */
+public class SpringStopEngine {
+ double mDamping = 0.5f;
+
+ @SuppressWarnings("unused")
+ private static final double UNSET = Double.MAX_VALUE;
+
+ @SuppressWarnings("unused")
+ private boolean mInitialized = false;
+
+ private double mStiffness;
+ private double mTargetPos;
+
+ @SuppressWarnings("unused")
+ private double mLastVelocity;
+
+ private float mLastTime;
+ private float mPos;
+ private float mV;
+ private float mMass;
+ private float mStopThreshold;
+ private int mBoundaryMode = 0;
+
+ public String debug(String desc, float time) {
+ return null;
+ }
+
+ void log(String str) {
+ StackTraceElement s = new Throwable().getStackTrace()[1];
+ String line =
+ ".(" + s.getFileName() + ":" + s.getLineNumber() + ") " + s.getMethodName() + "() ";
+ System.out.println(line + str);
+ }
+
+ public SpringStopEngine() {}
+
+ public float getTargetValue() {
+ return (float) mTargetPos;
+ }
+
+ public void setInitialValue(float v) {
+ mPos = v;
+ }
+
+ public void setTargetValue(float v) {
+ mTargetPos = v;
+ }
+
+ public SpringStopEngine(float[] parameters) {
+ if (parameters[0] != 0) {
+ throw new RuntimeException(" parameter[0] should be 0");
+ }
+
+ springParameters(
+ 1,
+ parameters[1],
+ parameters[2],
+ parameters[3],
+ Float.floatToRawIntBits(parameters[4]));
+ }
+
+ /**
+ * Config the spring starting conditions
+ *
+ * @param currentPos
+ * @param target
+ * @param currentVelocity
+ */
+ public void springStart(float currentPos, float target, float currentVelocity) {
+ mTargetPos = target;
+ mInitialized = false;
+ mPos = currentPos;
+ mLastVelocity = currentVelocity;
+ mLastTime = 0;
+ }
+
+ /**
+ * Config the spring parameters
+ *
+ * @param mass The mass of the spring
+ * @param stiffness The stiffness of the spring
+ * @param damping The dampening factor
+ * @param stopThreshold how low energy must you be to stop
+ * @param boundaryMode The boundary behaviour
+ */
+ public void springParameters(
+ float mass, float stiffness, float damping, float stopThreshold, int boundaryMode) {
+ mDamping = damping;
+ mInitialized = false;
+ mStiffness = stiffness;
+ mMass = mass;
+ mStopThreshold = stopThreshold;
+ mBoundaryMode = boundaryMode;
+ mLastTime = 0;
+ }
+
+ public float getVelocity(float time) {
+ return (float) mV;
+ }
+
+ public float get(float time) {
+ compute(time - mLastTime);
+ mLastTime = time;
+ if (isStopped()) {
+ mPos = (float) mTargetPos;
+ }
+ return (float) mPos;
+ }
+
+ public float getAcceleration() {
+ double k = mStiffness;
+ double c = mDamping;
+ double x = (mPos - mTargetPos);
+ return (float) (-k * x - c * mV) / mMass;
+ }
+
+ public float getVelocity() {
+ return 0;
+ }
+
+ public boolean isStopped() {
+ double x = (mPos - mTargetPos);
+ double k = mStiffness;
+ double v = mV;
+ double m = mMass;
+ double energy = v * v * m + k * x * x;
+ double max_def = Math.sqrt(energy / k);
+ return max_def <= mStopThreshold;
+ }
+
+ private void compute(double dt) {
+ if (dt <= 0) {
+ // Nothing to compute if there's no time difference
+ return;
+ }
+
+ double k = mStiffness;
+ double c = mDamping;
+ // Estimate how many time we should over sample based on the frequency and current sampling
+ int overSample = (int) (1 + 9 / (Math.sqrt(mStiffness / mMass) * dt * 4));
+ dt /= overSample;
+
+ for (int i = 0; i < overSample; i++) {
+ double x = (mPos - mTargetPos);
+ double a = (-k * x - c * mV) / mMass;
+ // This refinement of a simple coding of the acceleration increases accuracy
+ double avgV = mV + a * dt / 2; // pass 1 calculate the average velocity
+ double avgX = mPos + dt * avgV / 2 - mTargetPos; // pass 1 calculate the average pos
+ a = (-avgX * k - avgV * c) / mMass; // calculate acceleration over that average pos
+
+ double dv = a * dt; // calculate change in velocity
+ avgV = mV + dv / 2; // average velocity is current + half change
+ mV += (float) dv;
+ mPos += (float) (avgV * dt);
+ if (mBoundaryMode > 0) {
+ if (mPos < 0 && ((mBoundaryMode & 1) == 1)) {
+ mPos = -mPos;
+ mV = -mV;
+ }
+ if (mPos > 1 && ((mBoundaryMode & 2) == 2)) {
+ mPos = 2 - mPos;
+ mV = -mV;
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
index c7be3cab4c0b..b1eb8041b0b3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
@@ -24,14 +24,14 @@ import android.annotation.NonNull;
*/
public class StepCurve extends Easing {
// private static final boolean DEBUG = false;
- MonotonicCurveFit mCurveFit;
+ @NonNull private final MonotonicCurveFit mCurveFit;
- public StepCurve(float[] params, int offset, int len) {
+ public StepCurve(@NonNull float[] params, int offset, int len) {
mCurveFit = genSpline(params, offset, len);
}
@NonNull
- private static MonotonicCurveFit genSpline(float[] values, int off, int arrayLen) {
+ private static MonotonicCurveFit genSpline(@NonNull float[] values, int off, int arrayLen) {
int length = arrayLen * 3 - 2;
int len = arrayLen - 1;
double gap = 1.0 / len;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java
index 3e24372f9b8c..7e02bc9416a9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java
@@ -212,7 +212,6 @@ public class VelocityEasing {
mStage[1].setUp(peak_v, d1, t1, 0f, destination, t2 + t1);
mDuration = t2 + t1;
if (mDuration > maxTime) {
- System.out.println(" fail ");
return false;
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
index 3fba8acf8bca..4af79f3ce4f4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
@@ -54,11 +54,11 @@ public class BooleanConstant implements Operation {
}
@Override
- public void apply(RemoteContext context) {}
+ public void apply(@NonNull RemoteContext context) {}
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
index 79f2a8d8dec5..613e7328e24a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
@@ -50,7 +50,7 @@ public class IntegerConstant implements Operation {
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
index 01672b469728..745caa384e4c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
@@ -54,13 +54,13 @@ public class LongConstant implements Operation {
}
@Override
- public void apply(RemoteContext context) {
+ public void apply(@NonNull RemoteContext context) {
context.putObject(mId, this);
}
@NonNull
@Override
- public String deepToString(String indent) {
+ public String deepToString(@NonNull String indent) {
return toString();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
index aaee9c565fbb..2a3f3be714b9 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
@@ -141,4 +141,9 @@ public class RemoteComposeDocument {
}
return mDocument.getStats();
}
+
+ public int hasSensorListeners(int[] ids) {
+
+ return 0;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index cc74b119866d..648f7bf06dd4 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -15,9 +15,14 @@
*/
package com.android.internal.widget.remotecompose.player;
+import android.app.Application;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -28,6 +33,7 @@ import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.operations.NamedVariable;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.player.platform.RemoteComposeCanvas;
@@ -81,6 +87,7 @@ public class RemoteComposePlayer extends FrameLayout {
mInner.setDocument(null);
}
mapColors();
+ setupSensors();
mInner.setHapticEngine(
new CoreDocument.HapticEngine() {
@@ -543,4 +550,113 @@ public class RemoteComposePlayer extends FrameLayout {
private void provideHapticFeedback(int type) {
performHapticFeedback(sHapticTable[type % sHapticTable.length]);
}
+
+ SensorManager mSensorManager;
+ Sensor mAcc = null, mGyro = null, mMag = null, mLight = null;
+ SensorEventListener mListener;
+
+ private void setupSensors() {
+
+ int minId = RemoteContext.ID_ACCELERATION_X;
+ int maxId = RemoteContext.ID_LIGHT;
+ int[] ids = new int[1 + maxId - minId];
+
+ int count = mInner.hasSensorListeners(ids);
+ mAcc = null;
+ mGyro = null;
+ mMag = null;
+ mLight = null;
+ if (count > 0) {
+ Application app = (Application) getContext().getApplicationContext();
+
+ mSensorManager = (SensorManager) app.getSystemService(Context.SENSOR_SERVICE);
+ for (int i = 0; i < count; i++) {
+ switch (ids[i]) {
+ case RemoteContext.ID_ACCELERATION_X:
+ case RemoteContext.ID_ACCELERATION_Y:
+ case RemoteContext.ID_ACCELERATION_Z:
+ if (mAcc == null) {
+ mAcc = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ }
+ break;
+ case RemoteContext.ID_GYRO_ROT_X:
+ case RemoteContext.ID_GYRO_ROT_Y:
+ case RemoteContext.ID_GYRO_ROT_Z:
+ if (mGyro == null) {
+ mGyro = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
+ }
+ break;
+ case RemoteContext.ID_MAGNETIC_X:
+ case RemoteContext.ID_MAGNETIC_Y:
+ case RemoteContext.ID_MAGNETIC_Z:
+ if (mMag == null) {
+ mMag = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
+ }
+ break;
+ case RemoteContext.ID_LIGHT:
+ if (mLight == null) {
+ mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ }
+ }
+ }
+ }
+ registerListener();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ unregisterListener();
+ }
+
+ public void registerListener() {
+ Sensor[] s = {mAcc, mGyro, mMag, mLight};
+ if (mListener != null) {
+ unregisterListener();
+ }
+ SensorEventListener listener =
+ new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (event.sensor == mAcc) {
+ mInner.setExternalFloat(
+ RemoteContext.ID_ACCELERATION_X, event.values[0]);
+ mInner.setExternalFloat(
+ RemoteContext.ID_ACCELERATION_Y, event.values[1]);
+ mInner.setExternalFloat(
+ RemoteContext.ID_ACCELERATION_Z, event.values[2]);
+ } else if (event.sensor == mGyro) {
+ mInner.setExternalFloat(RemoteContext.ID_GYRO_ROT_X, event.values[0]);
+ mInner.setExternalFloat(RemoteContext.ID_GYRO_ROT_Y, event.values[1]);
+ mInner.setExternalFloat(RemoteContext.ID_GYRO_ROT_Z, event.values[2]);
+ } else if (event.sensor == mMag) {
+ mInner.setExternalFloat(RemoteContext.ID_MAGNETIC_X, event.values[0]);
+ mInner.setExternalFloat(RemoteContext.ID_MAGNETIC_Y, event.values[1]);
+ mInner.setExternalFloat(RemoteContext.ID_MAGNETIC_Z, event.values[2]);
+ } else if (event.sensor == mLight) {
+ mInner.setExternalFloat(RemoteContext.ID_LIGHT, event.values[0]);
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+ };
+
+ Sensor[] sensors = {mAcc, mGyro, mMag, mLight};
+ for (int i = 0; i < sensors.length; i++) {
+ Sensor sensor = sensors[i];
+ if (sensor != null) {
+ mListener = listener;
+ mSensorManager.registerListener(
+ mListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+ }
+ }
+
+ public void unregisterListener() {
+ if (mListener != null && mSensorManager != null) {
+ mSensorManager.unregisterListener(mListener);
+ }
+ mListener = null;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index 0b650a93c9db..3c91cffcec3f 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.widget.remotecompose.player.platform;
+import android.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Canvas;
@@ -247,7 +248,7 @@ public class AndroidPaintContext extends PaintContext {
}
@Override
- public void getTextBounds(int textId, int start, int end, int flags, float[] bounds) {
+ public void getTextBounds(int textId, int start, int end, int flags, @NonNull float[] bounds) {
String str = getText(textId);
if (end == -1) {
end = str.length();
@@ -420,7 +421,7 @@ public class AndroidPaintContext extends PaintContext {
* @param paintData the list change to the paint
*/
@Override
- public void applyPaint(PaintBundle paintData) {
+ public void applyPaint(@NonNull PaintBundle paintData) {
paintData.applyPaintChange(
(PaintContext) this,
new PaintChanges() {
@@ -576,8 +577,8 @@ public class AndroidPaintContext extends PaintContext {
@Override
public void setLinearGradient(
- int[] colors,
- float[] stops,
+ @NonNull int[] colors,
+ @NonNull float[] stops,
float startX,
float startY,
float endX,
@@ -596,8 +597,8 @@ public class AndroidPaintContext extends PaintContext {
@Override
public void setRadialGradient(
- int[] colors,
- float[] stops,
+ @NonNull int[] colors,
+ @NonNull float[] stops,
float centerX,
float centerY,
float radius,
@@ -614,7 +615,10 @@ public class AndroidPaintContext extends PaintContext {
@Override
public void setSweepGradient(
- int[] colors, float[] stops, float centerX, float centerY) {
+ @NonNull int[] colors,
+ @NonNull float[] stops,
+ float centerX,
+ float centerY) {
mPaint.setShader(new SweepGradient(centerX, centerY, colors, stops));
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java
index f28e85a44c1b..ba8d83bff51f 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.player.platform;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.graphics.Path;
import android.graphics.PathIterator;
@@ -31,7 +33,7 @@ public class AndroidPlatformServices implements Platform {
private static final String LOG_TAG = "RemoteCompose";
@Override
- public byte[] imageToByteArray(Object image) {
+ public byte[] imageToByteArray(@NonNull Object image) {
if (image instanceof Bitmap) {
// let's create a bitmap
ByteArrayOutputStream byteArrayBitmapStream = new ByteArrayOutputStream();
@@ -42,7 +44,7 @@ public class AndroidPlatformServices implements Platform {
}
@Override
- public int getImageWidth(Object image) {
+ public int getImageWidth(@NonNull Object image) {
if (image instanceof Bitmap) {
return ((Bitmap) image).getWidth();
}
@@ -50,7 +52,7 @@ public class AndroidPlatformServices implements Platform {
}
@Override
- public int getImageHeight(Object image) {
+ public int getImageHeight(@NonNull Object image) {
if (image instanceof Bitmap) {
return ((Bitmap) image).getHeight();
}
@@ -58,7 +60,8 @@ public class AndroidPlatformServices implements Platform {
}
@Override
- public float[] pathToFloatArray(Object path) {
+ @Nullable
+ public float[] pathToFloatArray(@NonNull Object path) {
// if (path is RemotePath) {
// return path.createFloatArray()
// }
@@ -88,7 +91,7 @@ public class AndroidPlatformServices implements Platform {
}
}
- private float[] androidPathToFloatArray(Path path) {
+ private @NonNull float[] androidPathToFloatArray(@NonNull Path path) {
PathIterator i = path.getPathIterator();
int estimatedSize = 0;
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
index 7a7edba160c8..77c25147b1fd 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.player.platform;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -22,11 +24,15 @@ import android.graphics.Canvas;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.TouchListener;
import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.operations.BitmapData;
import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess;
import com.android.internal.widget.remotecompose.core.operations.utilities.DataMap;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.HashMap;
/**
@@ -53,7 +59,7 @@ class AndroidRemoteContext extends RemoteContext {
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public void loadPathData(int instanceId, float[] floatPath) {
+ public void loadPathData(int instanceId, @NonNull float[] floatPath) {
if (!mRemoteComposeState.containsId(instanceId)) {
mRemoteComposeState.cacheData(instanceId, floatPath);
}
@@ -74,12 +80,12 @@ class AndroidRemoteContext extends RemoteContext {
HashMap<String, VarName> mVarNameHashMap = new HashMap<>();
@Override
- public void loadVariableName(String varName, int varId, int varType) {
+ public void loadVariableName(@NonNull String varName, int varId, int varType) {
mVarNameHashMap.put(varName, new VarName(varName, varId, varType));
}
@Override
- public void setNamedStringOverride(String stringName, String value) {
+ public void setNamedStringOverride(@NonNull String stringName, @NonNull String value) {
if (mVarNameHashMap.get(stringName) != null) {
int id = mVarNameHashMap.get(stringName).mId;
overrideText(id, value);
@@ -87,7 +93,7 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
- public void clearNamedStringOverride(String stringName) {
+ public void clearNamedStringOverride(@NonNull String stringName) {
if (mVarNameHashMap.get(stringName) != null) {
int id = mVarNameHashMap.get(stringName).mId;
clearDataOverride(id);
@@ -96,7 +102,7 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
- public void setNamedIntegerOverride(String stringName, int value) {
+ public void setNamedIntegerOverride(@NonNull String stringName, int value) {
if (mVarNameHashMap.get(stringName) != null) {
int id = mVarNameHashMap.get(stringName).mId;
overrideInt(id, value);
@@ -104,7 +110,7 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
- public void clearNamedIntegerOverride(String integerName) {
+ public void clearNamedIntegerOverride(@NonNull String integerName) {
if (mVarNameHashMap.get(integerName) != null) {
int id = mVarNameHashMap.get(integerName).mId;
clearIntegerOverride(id);
@@ -118,18 +124,18 @@ class AndroidRemoteContext extends RemoteContext {
* @param colorName name of color
* @param color
*/
- public void setNamedColorOverride(String colorName, int color) {
+ public void setNamedColorOverride(@NonNull String colorName, int color) {
int id = mVarNameHashMap.get(colorName).mId;
mRemoteComposeState.overrideColor(id, color);
}
@Override
- public void addCollection(int id, ArrayAccess collection) {
+ public void addCollection(int id, @NonNull ArrayAccess collection) {
mRemoteComposeState.addCollection(id, collection);
}
@Override
- public void putDataMap(int id, DataMap map) {
+ public void putDataMap(int id, @NonNull DataMap map) {
mRemoteComposeState.putDataMap(id, map);
}
@@ -139,7 +145,7 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
- public void runAction(int id, String metadata) {
+ public void runAction(int id, @NonNull String metadata) {
mDocument.performClick(id);
}
@@ -152,21 +158,66 @@ class AndroidRemoteContext extends RemoteContext {
/**
* Decode a byte array into an image and cache it using the given imageId
*
- * @param width with of image to be loaded
+ * @param encoding how the data is encoded 0 = png, 1 = raw, 2 = url
+ * @param type the type of the data 0 = RGBA 8888, 1 = 888, 2 = 8 gray
+ * @param width with of image to be loaded largest dimension is 32767
* @param height height of image to be loaded
* @param bitmap a byte array containing the image information
* @oaram imageId the id of the image
*/
@Override
- public void loadBitmap(int imageId, int width, int height, byte[] bitmap) {
+ public void loadBitmap(
+ int imageId, short encoding, short type, int width, int height, @NonNull byte[] data) {
if (!mRemoteComposeState.containsId(imageId)) {
- Bitmap image = BitmapFactory.decodeByteArray(bitmap, 0, bitmap.length);
+ Bitmap image = null;
+ switch (encoding) {
+ case BitmapData.ENCODING_INLINE:
+ switch (type) {
+ case BitmapData.TYPE_PNG_8888:
+ image = BitmapFactory.decodeByteArray(data, 0, data.length);
+ break;
+ case BitmapData.TYPE_RAW8888:
+ image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ int[] idata = new int[data.length / 4];
+ for (int i = 0; i < idata.length; i++) {
+ int p = i * 4;
+ idata[i] =
+ (data[p] << 24)
+ | (data[p + 1] << 16)
+ | (data[p + 2] << 8)
+ | data[p + 3];
+ }
+ image.setPixels(idata, 0, width, 0, 0, width, height);
+ break;
+ case BitmapData.TYPE_RAW8:
+ image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ int[] bdata = new int[data.length / 4];
+ for (int i = 0; i < bdata.length; i++) {
+
+ bdata[i] = 0x1010101 * data[i];
+ }
+ image.setPixels(bdata, 0, width, 0, 0, width, height);
+ break;
+ }
+ break;
+ case BitmapData.ENCODING_FILE:
+ image = BitmapFactory.decodeFile(new String(data));
+ break;
+ case BitmapData.ENCODING_URL:
+ try {
+ image = BitmapFactory.decodeStream(new URL(new String(data)).openStream());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
mRemoteComposeState.cacheData(imageId, image);
}
}
@Override
- public void loadText(int id, String text) {
+ public void loadText(int id, @NonNull String text) {
if (!mRemoteComposeState.containsId(id)) {
mRemoteComposeState.cacheData(id, text);
} else {
@@ -225,12 +276,12 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
- public void loadAnimatedFloat(int id, FloatExpression animatedFloat) {
+ public void loadAnimatedFloat(int id, @NonNull FloatExpression animatedFloat) {
mRemoteComposeState.cacheData(id, animatedFloat);
}
@Override
- public void loadShader(int id, ShaderData value) {
+ public void loadShader(int id, @NonNull ShaderData value) {
mRemoteComposeState.cacheData(id, value);
}
@@ -240,7 +291,7 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
- public void putObject(int id, Object value) {
+ public void putObject(int id, @NonNull Object value) {
mRemoteComposeState.updateObject(id, value);
}
@@ -260,7 +311,7 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
- public void listensTo(int id, VariableSupport variableSupport) {
+ public void listensTo(int id, @NonNull VariableSupport variableSupport) {
mRemoteComposeState.listenToVar(id, variableSupport);
}
@@ -270,6 +321,7 @@ class AndroidRemoteContext extends RemoteContext {
}
@Override
+ @Nullable
public ShaderData getShader(int id) {
return (ShaderData) mRemoteComposeState.getFromId(id);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
index fdd9aad68d47..41ed017b3896 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.widget.remotecompose.player.platform;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -23,13 +24,17 @@ import android.view.View;
/** Implementation for the click handling */
class ClickAreaView extends View {
private int mId;
- private String mMetadata;
+ private final String mMetadata;
Paint mPaint = new Paint();
private boolean mDebug;
ClickAreaView(
- Context context, boolean debug, int id, String contentDescription, String metadata) {
+ Context context,
+ boolean debug,
+ int id,
+ @Nullable String contentDescription,
+ String metadata) {
super(context);
this.mId = id;
this.mMetadata = metadata;
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index b54ed8a77ec5..8f55f8abf713 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -26,6 +26,7 @@ import android.view.View;
import android.widget.FrameLayout;
import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.Theme;
import com.android.internal.widget.remotecompose.player.RemoteComposeDocument;
@@ -194,6 +195,20 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
}
}
+ public int hasSensorListeners(int[] ids) {
+ int count = 0;
+ for (int id = RemoteContext.ID_ACCELERATION_X; id <= RemoteContext.ID_LIGHT; id++) {
+ if (mARContext.mRemoteComposeState.hasListener(id)) {
+ ids[count++] = id;
+ }
+ }
+ return count;
+ }
+
+ public void setExternalFloat(int id, float value) {
+ mARContext.loadFloat(id, value);
+ }
+
public interface ClickCallbacks {
void click(int id, String metadata);
}
@@ -344,7 +359,9 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
mARContext.setAnimationEnabled(true);
mARContext.currentTime = System.currentTimeMillis();
mARContext.setDebug(mDebug);
+ float density = getContext().getResources().getDisplayMetrics().density;
mARContext.useCanvas(canvas);
+ mARContext.setDensity(density);
mARContext.mWidth = getWidth();
mARContext.mHeight = getHeight();
mDocument.paint(mARContext, mTheme);
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index 53500596f938..d05f5e3950b4 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -91,6 +91,28 @@ import java.util.UUID;
public interface AndroidPackage {
/**
+ * An array containing the drawable resources that used for the launcher
+ * activity icons.
+ *
+ * @see R.attr#alternateLauncherIcons
+ * @hide
+ */
+ @Immutable.Ignore
+ @Nullable
+ int[] getAlternateLauncherIconResIds();
+
+ /**
+ * An array containing the string resources that used for the launcher
+ * activity labels.
+ *
+ * @see R.attr#alternateLauncherLabels
+ * @hide
+ */
+ @Immutable.Ignore
+ @Nullable
+ int[] getAlternateLauncherLabelResIds();
+
+ /**
* @see ApplicationInfo#className
* @see R.styleable#AndroidManifestApplication_name
*/
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 25412581303c..5c03c5cca66d 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -77,6 +77,7 @@ cc_library_shared_for_libandroid_runtime {
"android_os_SystemClock.cpp",
"android_os_SystemProperties.cpp",
"android_text_AndroidCharacter.cpp",
+ "android_text_Hyphenator.cpp",
"android_util_AssetManager.cpp",
"android_util_EventLog.cpp",
"android_util_Log.cpp",
@@ -160,13 +161,13 @@ cc_library_shared_for_libandroid_runtime {
"android_view_MotionPredictor.cpp",
"android_view_PointerIcon.cpp",
"android_view_SurfaceControl.cpp",
+ "android_view_SurfaceControlActivePictureListener.cpp",
"android_view_SurfaceControlHdrLayerInfoListener.cpp",
"android_view_WindowManagerGlobal.cpp",
"android_graphics_BLASTBufferQueue.cpp",
"android_view_SurfaceSession.cpp",
"android_view_TextureView.cpp",
"android_view_TunnelModeEnabledListener.cpp",
- "android_text_Hyphenator.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
"android_os_HidlMemory.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 821861efd59b..00a62977de43 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -128,6 +128,7 @@ extern int register_android_view_InputApplicationHandle(JNIEnv* env);
extern int register_android_view_InputWindowHandle(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(JNIEnv* env);
+extern int register_android_view_SurfaceControlActivePictureListener(JNIEnv* env);
extern int register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
@@ -1563,6 +1564,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_DisplayEventReceiver),
REG_JNI(register_android_view_Surface),
REG_JNI(register_android_view_SurfaceControl),
+ REG_JNI(register_android_view_SurfaceControlActivePictureListener),
REG_JNI(register_android_view_SurfaceControlHdrLayerInfoListener),
REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_InputApplicationHandle),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index ded1a9949ef8..1e7bfe32ba79 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -36,6 +36,8 @@ using ::android::base::unique_fd;
namespace android {
+static constexpr bool kLogWeakReachableDeletedAssets = false;
+
static struct overlayableinfo_offsets_t {
jclass classObject;
jmethodID constructor;
@@ -97,7 +99,7 @@ static void DeleteGuardedApkAssets(Guarded<AssetManager2::ApkAssetsPtr>& apk_ass
if (useCount > 1) {
ALOGW("ApkAssets: Deleting an object '%s' with %d > 1 strong and %d weak references",
(*assets)->GetDebugName().c_str(), int(useCount), int(weakCount));
- } else if (weakCount > 0) {
+ } else if constexpr (kLogWeakReachableDeletedAssets) if (weakCount > 0) {
ALOGW("ApkAssets: Deleting an ApkAssets object '%s' with %d weak references",
(*assets)->GetDebugName().c_str(), int(weakCount));
}
diff --git a/core/jni/android_hardware_OverlayProperties.cpp b/core/jni/android_hardware_OverlayProperties.cpp
index bb4084e8f39e..f64dec8eb215 100644
--- a/core/jni/android_hardware_OverlayProperties.cpp
+++ b/core/jni/android_hardware_OverlayProperties.cpp
@@ -106,7 +106,7 @@ static jobjectArray android_hardware_OverlayProperties_getLutProperties(JNIEnv*
jlong nativeObject) {
gui::OverlayProperties* overlayProperties =
reinterpret_cast<gui::OverlayProperties*>(nativeObject);
- if (overlayProperties->lutProperties.has_value()) {
+ if (!overlayProperties || !overlayProperties->lutProperties) {
return NULL;
}
auto& lutProperties = overlayProperties->lutProperties.value();
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index f9d00edce3fa..5a183925e38e 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -584,14 +584,23 @@ static jboolean android_media_AudioRecord_setInputDevice(
return lpRecorder->setInputDevice(device_id) == NO_ERROR;
}
-static jint android_media_AudioRecord_getRoutedDeviceId(
- JNIEnv *env, jobject thiz) {
-
+static jintArray android_media_AudioRecord_getRoutedDeviceIds(JNIEnv *env, jobject thiz) {
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
- if (lpRecorder == 0) {
- return 0;
+ if (lpRecorder == NULL) {
+ return NULL;
+ }
+ DeviceIdVector deviceIds = lpRecorder->getRoutedDeviceIds();
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
+ }
+ jint *values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
}
- return (jint)lpRecorder->getRoutedDeviceId();
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
// Enable and Disable Callback methods are synchronized on the Java side
@@ -821,8 +830,7 @@ static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{"native_start", "(II)I", (void *)android_media_AudioRecord_start},
{"native_stop", "()V", (void *)android_media_AudioRecord_stop},
- {"native_setup",
- "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I",
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I",
(void *)android_media_AudioRecord_setup},
{"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
{"native_release", "()V", (void *)android_media_AudioRecord_release},
@@ -846,7 +854,7 @@ static const JNINativeMethod gMethods[] = {
{"native_getMetrics", "()Landroid/os/PersistableBundle;",
(void *)android_media_AudioRecord_native_getMetrics},
{"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioRecord_getRoutedDeviceIds},
{"native_enableDeviceCallback", "()V",
(void *)android_media_AudioRecord_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8eaa7aa99a2d..3d9a19e129a8 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -109,6 +109,7 @@ static struct {
// Valid only if an AudioDevicePort
jfieldID mType;
jfieldID mAddress;
+ jfieldID mSpeakerLayoutChannelMask;
// other fields unused by JNI
} gAudioPortFields;
@@ -1084,6 +1085,8 @@ static jint convertAudioPortConfigToNativeWithDevicePort(JNIEnv *env,
strncpy(nAudioPortConfig->ext.device.address,
nDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN - 1);
env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
+ nAudioPortConfig->ext.device.speaker_layout_channel_mask = outChannelMaskToNative(
+ env->GetIntField(jAudioDevicePort, gAudioPortFields.mSpeakerLayoutChannelMask));
env->DeleteLocalRef(jDeviceAddress);
env->DeleteLocalRef(jAudioDevicePort);
return jStatus;
@@ -1541,10 +1544,12 @@ static jint convertAudioPortFromNative(JNIEnv *env, ScopedLocalRef<jobject> *jAu
.encapsulation_metadata_types));
ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(nAudioPort->ext.device.address));
+ int speakerLayoutChannelMask = outChannelMaskFromNative(
+ nAudioPort->active_config.ext.device.speaker_layout_channel_mask);
jAudioPort->reset(env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
jHandle.get(), jDeviceName.get(), jAudioProfiles.get(),
jGains.get(), nAudioPort->ext.device.type, jAddress.get(),
- jEncapsulationModes.get(),
+ speakerLayoutChannelMask, jEncapsulationModes.get(),
jEncapsulationMetadataTypes.get(),
jAudioDescriptors.get()));
} else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
@@ -3705,14 +3710,15 @@ int register_android_media_AudioSystem(JNIEnv *env)
gAudioDevicePortCstor =
GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
"(Landroid/media/AudioHandle;Ljava/lang/String;Ljava/util/List;"
- "[Landroid/media/AudioGain;ILjava/lang/String;[I[I"
+ "[Landroid/media/AudioGain;ILjava/lang/String;I[I[I"
"Ljava/util/List;)V");
// When access AudioPort as AudioDevicePort
gAudioPortFields.mType = GetFieldIDOrDie(env, audioDevicePortClass, "mType", "I");
gAudioPortFields.mAddress = GetFieldIDOrDie(env, audioDevicePortClass, "mAddress",
"Ljava/lang/String;");
-
+ gAudioPortFields.mSpeakerLayoutChannelMask =
+ GetFieldIDOrDie(env, audioDevicePortClass, "mSpeakerLayoutChannelMask", "I");
jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
gAudioMixPortCstor =
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1557f9ed47a5..5d4d1ce20e5d 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1190,15 +1190,23 @@ static jboolean android_media_AudioTrack_setOutputDevice(
}
return lpTrack->setOutputDevice(device_id) == NO_ERROR;
}
-
-static jint android_media_AudioTrack_getRoutedDeviceId(
- JNIEnv *env, jobject thiz) {
-
+static jintArray android_media_AudioTrack_getRoutedDeviceIds(JNIEnv *env, jobject thiz) {
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
if (lpTrack == NULL) {
- return 0;
+ return NULL;
+ }
+ DeviceIdVector deviceIds = lpTrack->getRoutedDeviceIds();
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
+ }
+ jint *values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
}
- return (jint)lpTrack->getRoutedDeviceId();
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
static void android_media_AudioTrack_enableDeviceCallback(
@@ -1503,7 +1511,7 @@ static const JNINativeMethod gMethods[] = {
(void *)android_media_AudioTrack_setAuxEffectSendLevel},
{"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
{"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioTrack_getRoutedDeviceIds},
{"native_enableDeviceCallback", "()V",
(void *)android_media_AudioTrack_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
diff --git a/core/jni/android_media_DeviceCallback.cpp b/core/jni/android_media_DeviceCallback.cpp
index a1a035110caf..ccdf633c842a 100644
--- a/core/jni/android_media_DeviceCallback.cpp
+++ b/core/jni/android_media_DeviceCallback.cpp
@@ -61,21 +61,20 @@ JNIDeviceCallback::~JNIDeviceCallback()
}
void JNIDeviceCallback::onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId)
-{
+ const DeviceIdVector& deviceIds) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
return;
}
- ALOGV("%s audioIo %d deviceId %d", __FUNCTION__, audioIo, deviceId);
- env->CallStaticVoidMethod(mClass,
- mPostEventFromNative,
- mObject,
- AUDIO_NATIVE_EVENT_ROUTING_CHANGE, deviceId, 0, NULL);
+ ALOGV("%s audioIo %d deviceIds %s", __FUNCTION__, audioIo, toString(deviceIds).c_str());
+ // Java should query the new device ids once it gets the event.
+ // TODO(b/378505346): Pass the deviceIds to Java to avoid race conditions.
+ env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject,
+ AUDIO_NATIVE_EVENT_ROUTING_CHANGE, 0 /*arg1*/, 0 /*arg2*/,
+ NULL /*obj*/);
if (env->ExceptionCheck()) {
ALOGW("An exception occurred while notifying an event.");
env->ExceptionClear();
}
}
-
diff --git a/core/jni/android_media_DeviceCallback.h b/core/jni/android_media_DeviceCallback.h
index 7ae788eaf058..0c9ccc89ba1a 100644
--- a/core/jni/android_media_DeviceCallback.h
+++ b/core/jni/android_media_DeviceCallback.h
@@ -31,8 +31,7 @@ public:
JNIDeviceCallback(JNIEnv* env, jobject thiz, jobject weak_thiz, jmethodID postEventFromNative);
~JNIDeviceCallback();
- virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId);
+ virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo, const DeviceIdVector& deviceIds);
private:
void sendEvent(int event);
diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp
index aebe7ea7ee61..0f78c9e93a00 100644
--- a/core/jni/android_os_PerformanceHintManager.cpp
+++ b/core/jni/android_os_PerformanceHintManager.cpp
@@ -88,9 +88,10 @@ void ensureAPerformanceHintBindingInitialized() {
"Failed to find required symbol "
"APerformanceHint_getPreferredUpdateRateNanos!");
- gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+ gAPH_createSessionFn =
+ (APH_createSession)dlsym(handle_, "APerformanceHint_createSessionFromJava");
LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
- "Failed to find required symbol APerformanceHint_createSession!");
+ "Failed to find required symbol APerformanceHint_createSessionFromJava!");
gAPH_updateTargetWorkDurationFn =
(APH_updateTargetWorkDuration)dlsym(handle_,
@@ -106,9 +107,9 @@ void ensureAPerformanceHintBindingInitialized() {
"Failed to find required symbol "
"APerformanceHint_reportActualWorkDuration!");
- gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
+ gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSessionFromJava");
LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
- "Failed to find required symbol APerformanceHint_closeSession!");
+ "Failed to find required symbol APerformanceHint_closeSessionFromJava!");
gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 933781c3e924..e45cbaf07876 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -18,10 +18,17 @@
#include <cutils/trace.h>
#include <fcntl.h>
#include <minikin/Hyphenator.h>
+#ifdef __ANDROID__
#include <sys/mman.h>
+#else
+#include <android-base/mapped_file.h>
+#include <android-base/properties.h>
+#endif
#include <sys/stat.h>
#include <sys/types.h>
+#ifdef __ANDROID__
#include <tracing_perfetto.h>
+#endif
#include <unicode/uloc.h>
#include <unistd.h>
@@ -30,7 +37,12 @@
namespace android {
static std::string buildFileName(const std::string& locale) {
+#ifdef __ANDROID__
constexpr char SYSTEM_HYPHENATOR_PREFIX[] = "/system/usr/hyphen-data/hyph-";
+#else
+ std::string hyphenPath = base::GetProperty("ro.hyphen.data.dir", "/system/usr/hyphen-data");
+ std::string SYSTEM_HYPHENATOR_PREFIX = hyphenPath + "/hyph-";
+#endif
constexpr char SYSTEM_HYPHENATOR_SUFFIX[] = ".hyb";
std::string lowerLocale;
lowerLocale.reserve(locale.size());
@@ -51,11 +63,22 @@ static std::pair<const uint8_t*, size_t> mmapPatternFile(const std::string& loca
return std::make_pair(nullptr, 0);
}
+#ifdef __ANDROID__
void* ptr = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0 /* offset */);
close(fd);
if (ptr == MAP_FAILED) {
return std::make_pair(nullptr, 0);
}
+#else
+ std::unique_ptr<base::MappedFile> patternFile =
+ base::MappedFile::FromFd(fd, 0, st.st_size, PROT_READ);
+ close(fd);
+ if (patternFile == nullptr) {
+ return std::make_pair(nullptr, 0);
+ }
+ auto* mappedPtr = new base::MappedFile(std::move(*patternFile));
+ char* ptr = mappedPtr->data();
+#endif
return std::make_pair(reinterpret_cast<const uint8_t*>(ptr), st.st_size);
}
@@ -210,9 +233,13 @@ static void init() {
addHyphenatorAlias("und-Taml", "ta"); // Tamil
addHyphenatorAlias("und-Telu", "te"); // Telugu
+#ifdef __ANDROID__
tracing_perfetto::traceBegin(ATRACE_TAG_VIEW, "CacheUnicodeExtensionSubtagsKeyMap");
+#endif
cacheUnicodeExtensionSubtagsKeyMap();
+#ifdef __ANDROID__
tracing_perfetto::traceEnd(ATRACE_TAG_VIEW); // CacheUnicodeExtensionSubtagsKeyMap
+#endif
}
static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 49191ee02ad6..7ef7829c6ba5 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -33,6 +33,7 @@
#include <algorithm>
#include <array>
+#include <cctype>
#include <cstring>
#include <limits>
#include <memory>
@@ -1008,6 +1009,8 @@ jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
}
}
if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
+ std::replace_if(buffer+start, buffer+end,
+ [](unsigned char c){ return !std::isprint(c); }, '?');
jstring str = env->NewStringUTF(buffer+start);
env->SetObjectArrayElement(outStrings, di, str);
}
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index f007cc5a23bd..a09c405de1cd 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -67,6 +67,7 @@ static struct {
jfieldID preferredFrameTimelineIndex;
jfieldID frameTimelinesLength;
jfieldID frameTimelines;
+ jfieldID numberQueuedBuffers;
} vsyncEventDataClassInfo;
} gDisplayEventReceiverClassInfo;
@@ -165,7 +166,8 @@ static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventDa
return env->NewObject(gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init,
frameTimelineObjs.get(), vsyncEventData.preferredFrameTimelineIndex,
- vsyncEventData.frameTimelinesLength, vsyncEventData.frameInterval);
+ vsyncEventData.frameTimelinesLength, vsyncEventData.frameInterval,
+ vsyncEventData.numberQueuedBuffers);
}
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -188,6 +190,9 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla
env->SetLongField(vsyncEventDataObj.get(),
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval,
vsyncEventData.frameInterval);
+ env->SetIntField(vsyncEventDataObj.get(),
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.numberQueuedBuffers,
+ vsyncEventData.numberQueuedBuffers);
ScopedLocalRef<jobjectArray>
frameTimelinesObj(env,
@@ -441,7 +446,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
"<init>",
"([Landroid/view/"
- "DisplayEventReceiver$VsyncEventData$FrameTimeline;IIJ)V");
+ "DisplayEventReceiver$VsyncEventData$FrameTimeline;IIJI)V");
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex =
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
@@ -456,6 +461,9 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
"frameTimelines",
"[Landroid/view/DisplayEventReceiver$VsyncEventData$FrameTimeline;");
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.numberQueuedBuffers =
+ GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+ "numberQueuedBuffers", "I");
return res;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d3bf36e60345..0c243d1dc185 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -55,6 +55,7 @@
#include <ui/FrameStats.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
+#include <ui/PictureProfileHandle.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/StaticDisplayInfo.h>
@@ -118,6 +119,7 @@ static struct {
jfieldID renderFrameRate;
jfieldID hasArrSupport;
jfieldID frameRateCategoryRate;
+ jfieldID supportedRefreshRates;
jfieldID supportedColorModes;
jfieldID activeColorMode;
jfieldID hdrCapabilities;
@@ -758,58 +760,83 @@ static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
- ScopedIntArrayRW joffsets(env, joffsetArray);
- if (joffsets.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray");
- return;
- }
- ScopedIntArrayRW jdimensions(env, jdimensionArray);
- if (jdimensions.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray");
- return;
- }
- ScopedIntArrayRW jsizes(env, jsizeArray);
- if (jsizes.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray");
- return;
- }
- ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray);
- if (jsamplingKeys.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray");
- return;
- }
+ std::vector<int32_t> offsets;
+ std::vector<int32_t> dimensions;
+ std::vector<int32_t> sizes;
+ std::vector<int32_t> samplingKeys;
+ int32_t fd = -1;
+
+ if (jdimensionArray) {
+ jsize numLuts = env->GetArrayLength(jdimensionArray);
+ ScopedIntArrayRW joffsets(env, joffsetArray);
+ if (joffsets.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray");
+ return;
+ }
+ ScopedIntArrayRW jdimensions(env, jdimensionArray);
+ if (jdimensions.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray");
+ return;
+ }
+ ScopedIntArrayRW jsizes(env, jsizeArray);
+ if (jsizes.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray");
+ return;
+ }
+ ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray);
+ if (jsamplingKeys.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray");
+ return;
+ }
- jsize numLuts = env->GetArrayLength(jdimensionArray);
- std::vector<int32_t> offsets(joffsets.get(), joffsets.get() + numLuts);
- std::vector<int32_t> dimensions(jdimensions.get(), jdimensions.get() + numLuts);
- std::vector<int32_t> sizes(jsizes.get(), jsizes.get() + numLuts);
- std::vector<int32_t> samplingKeys(jsamplingKeys.get(), jsamplingKeys.get() + numLuts);
+ if (numLuts > 0) {
+ offsets = std::vector<int32_t>(joffsets.get(), joffsets.get() + numLuts);
+ dimensions = std::vector<int32_t>(jdimensions.get(), jdimensions.get() + numLuts);
+ sizes = std::vector<int32_t>(jsizes.get(), jsizes.get() + numLuts);
+ samplingKeys = std::vector<int32_t>(jsamplingKeys.get(), jsamplingKeys.get() + numLuts);
- ScopedFloatArrayRW jbuffers(env, jbufferArray);
- if (jbuffers.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray");
- return;
- }
+ ScopedFloatArrayRW jbuffers(env, jbufferArray);
+ if (jbuffers.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray");
+ return;
+ }
- // create the shared memory and copy jbuffers
- size_t bufferSize = jbuffers.size() * sizeof(float);
- int32_t fd = ashmem_create_region("lut_shread_mem", bufferSize);
- if (fd < 0) {
- jniThrowRuntimeException(env, "ashmem_create_region() failed");
- return;
- }
- void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (ptr == MAP_FAILED) {
- jniThrowRuntimeException(env, "Failed to map the shared memory");
- return;
+ // create the shared memory and copy jbuffers
+ size_t bufferSize = jbuffers.size() * sizeof(float);
+ fd = ashmem_create_region("lut_shared_mem", bufferSize);
+ if (fd < 0) {
+ jniThrowRuntimeException(env, "ashmem_create_region() failed");
+ return;
+ }
+ void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ jniThrowRuntimeException(env, "Failed to map the shared memory");
+ return;
+ }
+ memcpy(ptr, jbuffers.get(), bufferSize);
+ // unmap
+ munmap(ptr, bufferSize);
+ }
}
- memcpy(ptr, jbuffers.get(), bufferSize);
- // unmap
- munmap(ptr, bufferSize);
transaction->setLuts(ctrl, base::unique_fd(fd), offsets, dimensions, sizes, samplingKeys);
}
+static void nativeSetPictureProfileId(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong surfaceControlObj, jlong pictureProfileId) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(surfaceControlObj);
+ PictureProfileHandle handle(pictureProfileId);
+ transaction->setPictureProfileHandle(surfaceControl, handle);
+}
+
+static void nativeSetContentPriority(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong surfaceControlObj, jint priority) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(surfaceControlObj);
+ transaction->setContentPriority(surfaceControl, priority);
+}
+
static void nativeSetCachingHint(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint cachingHint) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -1332,8 +1359,9 @@ static void nativeSetDisplaySize(JNIEnv* env, jclass clazz,
}
}
-static jobject convertDeviceProductInfoToJavaObject(
- JNIEnv* env, const std::optional<DeviceProductInfo>& info) {
+static jobject convertDeviceProductInfoToJavaObject(JNIEnv* env,
+ const std::optional<DeviceProductInfo>& info,
+ bool isInternal) {
using ModelYear = android::DeviceProductInfo::ModelYear;
using ManufactureYear = android::DeviceProductInfo::ManufactureYear;
using ManufactureWeekAndYear = android::DeviceProductInfo::ManufactureWeekAndYear;
@@ -1368,7 +1396,8 @@ static jobject convertDeviceProductInfoToJavaObject(
// Section 8.7 - Physical Address of HDMI Specification Version 1.3a
using android::hardware::display::IDeviceProductInfoConstants;
if (info->relativeAddress.size() != 4) {
- connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
+ connectionToSinkType = isInternal ? IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN
+ : IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
} else if (info->relativeAddress[0] == 0) {
connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN;
} else if (info->relativeAddress[1] == 0) {
@@ -1390,12 +1419,14 @@ static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jlong id) {
jobject object =
env->NewObject(gStaticDisplayInfoClassInfo.clazz, gStaticDisplayInfoClassInfo.ctor);
- env->SetBooleanField(object, gStaticDisplayInfoClassInfo.isInternal,
- info.connectionType == ui::DisplayConnectionType::Internal);
+
+ const bool isInternal = info.connectionType == ui::DisplayConnectionType::Internal;
+ env->SetBooleanField(object, gStaticDisplayInfoClassInfo.isInternal, isInternal);
env->SetFloatField(object, gStaticDisplayInfoClassInfo.density, info.density);
env->SetBooleanField(object, gStaticDisplayInfoClassInfo.secure, info.secure);
env->SetObjectField(object, gStaticDisplayInfoClassInfo.deviceProductInfo,
- convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo));
+ convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo,
+ isInternal));
env->SetIntField(object, gStaticDisplayInfoClassInfo.installOrientation,
static_cast<uint32_t>(info.installOrientation));
return object;
@@ -1478,6 +1509,21 @@ static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jlong disp
env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.hasArrSupport, info.hasArrSupport);
env->SetObjectField(object, gDynamicDisplayInfoClassInfo.frameRateCategoryRate,
convertFrameRateCategoryRateToJavaObject(env, info.frameRateCategoryRate));
+
+ jfloatArray supportedRefreshRatesArray = env->NewFloatArray(info.supportedRefreshRates.size());
+ if (supportedRefreshRatesArray == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return NULL;
+ }
+ jfloat* supportedRefreshRatesArrayValues =
+ env->GetFloatArrayElements(supportedRefreshRatesArray, 0);
+ for (size_t i = 0; i < info.supportedRefreshRates.size(); i++) {
+ supportedRefreshRatesArrayValues[i] = static_cast<jfloat>(info.supportedRefreshRates[i]);
+ }
+ env->ReleaseFloatArrayElements(supportedRefreshRatesArray, supportedRefreshRatesArrayValues, 0);
+ env->SetObjectField(object, gDynamicDisplayInfoClassInfo.supportedRefreshRates,
+ supportedRefreshRatesArray);
+
jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size());
if (colorModesArray == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
@@ -2163,7 +2209,7 @@ static void nativeClearTrustedPresentationCallback(JNIEnv* env, jclass clazz, jl
class JankDataListenerWrapper : public JankDataListener {
public:
- JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) {
+ JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) : mRemovedVsyncId(-1) {
mOnJankDataListenerWeak = env->NewWeakGlobalRef(onJankDataListenerObject);
env->GetJavaVM(&mVm);
}
@@ -2174,6 +2220,12 @@ public:
}
bool onJankDataAvailable(const std::vector<gui::JankData>& jankData) override {
+ // Don't invoke the listener if we've been force removed and got this
+ // out-of-order callback.
+ if (mRemovedVsyncId == 0) {
+ return false;
+ }
+
JNIEnv* env = getEnv();
jobject target = env->NewLocalRef(mOnJankDataListenerWeak);
@@ -2181,8 +2233,8 @@ public:
return false;
}
- jobjectArray jJankDataArray = env->NewObjectArray(jankData.size(),
- gJankDataClassInfo.clazz, nullptr);
+ jobjectArray jJankDataArray =
+ env->NewObjectArray(jankData.size(), gJankDataClassInfo.clazz, nullptr);
for (size_t i = 0; i < jankData.size(); i++) {
// The exposed constants in SurfaceControl are simplified, so we need to translate the
// jank type we get from SF to what is exposed in Java.
@@ -2225,6 +2277,11 @@ public:
return true;
}
+ void removeListener(int64_t afterVsyncId) {
+ mRemovedVsyncId = (afterVsyncId <= 0) ? 0 : afterVsyncId;
+ JankDataListener::removeListener(afterVsyncId);
+ }
+
private:
JNIEnv* getEnv() {
@@ -2235,6 +2292,7 @@ private:
JavaVM* mVm;
jobject mOnJankDataListenerWeak;
+ int64_t mRemovedVsyncId;
};
static jlong nativeCreateJankDataListenerWrapper(JNIEnv* env, jclass clazz,
@@ -2325,6 +2383,20 @@ static jboolean nativeBootFinished(JNIEnv* env, jclass clazz) {
return error == OK ? JNI_TRUE : JNI_FALSE;
}
+static jint nativeGetMaxPictureProfiles(JNIEnv* env, jclass clazz) {
+ const auto displayIds = SurfaceComposerClient::SurfaceComposerClient::getPhysicalDisplayIds();
+ int largestMaxProfiles = 0;
+ for (auto displayId : displayIds) {
+ sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(displayId);
+ int32_t maxProfiles = 0;
+ SurfaceComposerClient::getMaxLayerPictureProfiles(token, &maxProfiles);
+ if (maxProfiles > largestMaxProfiles) {
+ largestMaxProfiles = maxProfiles;
+ }
+ }
+ return largestMaxProfiles;
+}
+
jlong nativeCreateTpc(JNIEnv* env, jclass clazz, jobject trustedPresentationCallback) {
return reinterpret_cast<jlong>(
new TrustedPresentationCallbackWrapper(env, trustedPresentationCallback));
@@ -2646,6 +2718,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetDefaultApplyToken },
{"nativeBootFinished", "()Z",
(void*)nativeBootFinished },
+ {"nativeGetMaxPictureProfiles", "()I",
+ (void*)nativeGetMaxPictureProfiles },
{"nativeCreateTpc", "(Landroid/view/SurfaceControl$TrustedPresentationCallback;)J",
(void*)nativeCreateTpc},
{"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer },
@@ -2657,6 +2731,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeNotifyShutdown },
{"nativeSetLuts", "(JJ[F[I[I[I[I)V", (void*)nativeSetLuts },
{"nativeEnableDebugLogCallPoints", "(J)V", (void*)nativeEnableDebugLogCallPoints },
+ {"nativeSetPictureProfileId", "(JJJ)V", (void*)nativeSetPictureProfileId },
+ {"nativeSetContentPriority", "(JJI)V", (void*)nativeSetContentPriority },
// clang-format on
};
@@ -2706,6 +2782,8 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gFrameRateCategoryRateClassInfo.ctor =
GetMethodIDOrDie(env, frameRateCategoryRateClazz, "<init>", "(FF)V");
+ gDynamicDisplayInfoClassInfo.supportedRefreshRates =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "supportedRefreshRates", "[F");
gDynamicDisplayInfoClassInfo.supportedColorModes =
GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I");
gDynamicDisplayInfoClassInfo.activeColorMode =
diff --git a/core/jni/android_view_SurfaceControlActivePictureListener.cpp b/core/jni/android_view_SurfaceControlActivePictureListener.cpp
new file mode 100644
index 000000000000..91849c1514cc
--- /dev/null
+++ b/core/jni/android_view_SurfaceControlActivePictureListener.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceControlActivePictureListener"
+
+#include <android/gui/BnActivePictureListener.h>
+#include <android_runtime/Log.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/RefBase.h>
+
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+struct {
+ jclass clazz;
+ jmethodID onActivePicturesChanged;
+} gListenerClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID constructor;
+} gActivePictureClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID constructor;
+ jfieldID id;
+} gPictureProfileHandleClassInfo;
+
+struct SurfaceControlActivePictureListener : public gui::BnActivePictureListener {
+ SurfaceControlActivePictureListener(JNIEnv* env, jobject listener)
+ : mListener(env->NewGlobalRef(listener)) {
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mVm) != JNI_OK, "Failed to GetJavaVm");
+ }
+
+ binder::Status onActivePicturesChanged(
+ const std::vector<gui::ActivePicture>& activePictures) override {
+ JNIEnv* env = requireEnv();
+
+ ScopedLocalRef<jobjectArray> activePictureArrayObj(env);
+ activePictureArrayObj.reset(
+ env->NewObjectArray(activePictures.size(), gActivePictureClassInfo.clazz, NULL));
+ if (env->ExceptionCheck() || !activePictureArrayObj.get()) {
+ LOGE_EX(env);
+ LOG_ALWAYS_FATAL("Failed to create an active picture array.");
+ }
+
+ {
+ std::vector<ScopedLocalRef<jobject>> pictureProfileHandleObjs;
+ std::vector<ScopedLocalRef<jobject>> activePictureObjs;
+
+ for (size_t i = 0; i < activePictures.size(); ++i) {
+ pictureProfileHandleObjs.push_back(ScopedLocalRef<jobject>(env));
+ pictureProfileHandleObjs[i].reset(
+ env->NewObject(gPictureProfileHandleClassInfo.clazz,
+ gPictureProfileHandleClassInfo.constructor,
+ activePictures[i].pictureProfileId));
+ if (env->ExceptionCheck() || !pictureProfileHandleObjs[i].get()) {
+ LOGE_EX(env);
+ LOG_ALWAYS_FATAL("Failed to create a picture profile handle.");
+ }
+ activePictureObjs.push_back(ScopedLocalRef<jobject>(env));
+ activePictureObjs[i].reset(env->NewObject(gActivePictureClassInfo.clazz,
+ gActivePictureClassInfo.constructor,
+ activePictures[i].layerId,
+ activePictures[i].ownerUid,
+ pictureProfileHandleObjs[i].get()));
+ if (env->ExceptionCheck() || !activePictureObjs[i].get()) {
+ LOGE_EX(env);
+ LOG_ALWAYS_FATAL("Failed to create an active picture.");
+ }
+ env->SetObjectArrayElement(activePictureArrayObj.get(), i,
+ activePictureObjs[i].get());
+ }
+
+ env->CallVoidMethod(mListener, gListenerClassInfo.onActivePicturesChanged,
+ activePictureArrayObj.get());
+ }
+
+ if (env->ExceptionCheck()) {
+ ALOGE("SurfaceControlActivePictureListener.onActivePicturesChanged failed");
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+ return binder::Status::ok();
+ }
+
+ status_t startListening() {
+ // TODO(b/337330263): Make SF multiple-listener capable
+ return SurfaceComposerClient::setActivePictureListener(this);
+ }
+
+ status_t stopListening() {
+ return SurfaceComposerClient::setActivePictureListener(nullptr);
+ }
+
+protected:
+ virtual ~SurfaceControlActivePictureListener() {
+ JNIEnv* env = requireEnv();
+ env->DeleteGlobalRef(mListener);
+ }
+
+ JNIEnv* requireEnv() {
+ JNIEnv* env = nullptr;
+ if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+ }
+ }
+ return env;
+ }
+
+private:
+ jobject mListener;
+ JavaVM* mVm;
+};
+
+jlong nativeMakeAndStartListening(JNIEnv* env, jobject jthis) {
+ auto listener = sp<SurfaceControlActivePictureListener>::make(env, jthis);
+ status_t err = listener->startListening();
+ if (err != OK) {
+ auto errStr = statusToString(err);
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Failed to start listening, err = %d (%s)", err, errStr.c_str());
+ return 0;
+ }
+ SurfaceControlActivePictureListener* listenerRawPtr = listener.get();
+ listenerRawPtr->incStrong(0);
+ return static_cast<jlong>(reinterpret_cast<intptr_t>(listenerRawPtr));
+}
+
+static void destroy(SurfaceControlActivePictureListener* listener) {
+ listener->stopListening();
+ listener->decStrong(0);
+}
+
+static jlong nativeGetDestructor(JNIEnv* env, jobject clazz) {
+ return static_cast<jlong>(reinterpret_cast<intptr_t>(&destroy));
+}
+
+const JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"nativeGetDestructor", "()J", (void*)nativeGetDestructor},
+ {"nativeMakeAndStartListening", "()J", (void*)nativeMakeAndStartListening}};
+} // namespace
+
+int register_android_view_SurfaceControlActivePictureListener(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlActivePictureListener",
+ gMethods, NELEM(gMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass listenerClazz = env->FindClass("android/view/SurfaceControlActivePictureListener");
+ gListenerClassInfo.clazz = MakeGlobalRefOrDie(env, listenerClazz);
+ gListenerClassInfo.onActivePicturesChanged =
+ env->GetMethodID(listenerClazz, "onActivePicturesChanged",
+ "([Landroid/view/SurfaceControlActivePicture;)V");
+
+ gActivePictureClassInfo.clazz = static_cast<jclass>(
+ env->NewGlobalRef(env->FindClass("android/view/SurfaceControlActivePicture")));
+ gActivePictureClassInfo.constructor =
+ env->GetMethodID(gActivePictureClassInfo.clazz, "<init>",
+ "(IILandroid/media/quality/PictureProfileHandle;)V");
+
+ gPictureProfileHandleClassInfo.clazz = static_cast<jclass>(
+ env->NewGlobalRef(env->FindClass("android/media/quality/PictureProfileHandle")));
+ gPictureProfileHandleClassInfo.constructor =
+ env->GetMethodID(gPictureProfileHandleClassInfo.clazz, "<init>", "(J)V");
+ return 0;
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp
index 6c72544a7958..76ead2a3ca31 100644
--- a/core/jni/com_android_internal_content_FileSystemUtils.cpp
+++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp
@@ -22,7 +22,6 @@
#include <android-base/hex.h>
#include <android-base/unique_fd.h>
#include <bionic/macros.h>
-#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -204,7 +203,8 @@ bool punchHoles(const char *filePath, const uint64_t offset,
return true;
}
-bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
+bool getLoadSegmentPhdrs(const char *filePath, const uint64_t offset,
+ std::vector<Elf64_Phdr> &programHeaders) {
// Open Elf file
Elf64_Ehdr ehdr;
std::ifstream inputStream(filePath, std::ifstream::in);
@@ -227,11 +227,6 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
uint64_t programHeaderOffset = ehdr.e_phoff;
uint16_t programHeaderNum = ehdr.e_phnum;
- IF_ALOGD() {
- ALOGD("Punching holes in file: %s programHeaderOffset: %" PRIu64 " programHeaderNum: %hu",
- filePath, programHeaderOffset, programHeaderNum);
- }
-
// if this is a zip file, also consider elf offset inside a file
uint64_t phOffset;
if (__builtin_add_overflow(offset, programHeaderOffset, &phOffset)) {
@@ -240,7 +235,6 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
}
inputStream.seekg(phOffset);
- std::vector<Elf64_Phdr> programHeaders;
for (int headerIndex = 0; headerIndex < programHeaderNum; headerIndex++) {
Elf64_Phdr header;
inputStream.read((char *)&header, sizeof(header));
@@ -254,6 +248,15 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
programHeaders.push_back(header);
}
+ return true;
+}
+
+bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
+ std::vector<Elf64_Phdr> programHeaders;
+ if (!getLoadSegmentPhdrs(filePath, offset, programHeaders)) {
+ ALOGE("Failed to read program headers from ELF file.");
+ return false;
+ }
return punchHoles(filePath, offset, programHeaders);
}
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.h b/core/jni/com_android_internal_content_FileSystemUtils.h
index 52445e2b4229..4a95686c5a0c 100644
--- a/core/jni/com_android_internal_content_FileSystemUtils.h
+++ b/core/jni/com_android_internal_content_FileSystemUtils.h
@@ -15,8 +15,11 @@
*/
#pragma once
+#include <elf.h>
#include <sys/types.h>
+#include <vector>
+
namespace android {
/*
@@ -35,4 +38,11 @@ bool punchHolesInElf64(const char* filePath, uint64_t offset);
*/
bool punchHolesInZip(const char* filePath, uint64_t offset, uint16_t extraFieldLen);
+/*
+ * This function reads program headers from ELF file. ELF can be specified with file path directly
+ * or it should be at offset inside Apk. Program headers passed to function is populated.
+ */
+bool getLoadSegmentPhdrs(const char* filePath, const uint64_t offset,
+ std::vector<Elf64_Phdr>& programHeaders);
+
} // namespace android \ No newline at end of file
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 7fca1175f3d4..1a0328338980 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -88,6 +88,7 @@ extern int register_android_os_Parcel(JNIEnv* env);
extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_SystemProperties(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv* env);
+extern int register_android_text_Hyphenator(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_util_jar_StrictJarFile(JNIEnv* env);
@@ -133,6 +134,7 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)},
{"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)},
{"android.text.AndroidCharacter", REG_JNI(register_android_text_AndroidCharacter)},
+ {"android.text.Hyphenator", REG_JNI(register_android_text_Hyphenator)},
{"android.util.EventLog", REG_JNI(register_android_util_EventLog)},
{"android.util.Log", REG_JNI(register_android_util_Log)},
{"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)},
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6af742fb23f4..2e0fe9eb13d9 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -256,6 +256,12 @@ message SecureSettingsProto {
}
optional Display display = 100;
+ message DoubleTapPowerButton {
+ optional SettingProto gesture_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto gesture = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional DoubleTapPowerButton double_tap_power_button = 103;
+
message Doze {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -737,5 +743,5 @@ message SecureSettingsProto {
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 103;
+ // Next tag = 104;
}
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index 9779dc0e00b8..16d25657f08e 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -217,6 +217,7 @@ message SystemSettingsProto {
optional SettingProto right_click_zone = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto tap_to_click = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto tap_dragging = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto three_finger_tap_customization = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Touchpad touchpad = 36;
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 0e4e22b09e24..aacd8699c202 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -160,7 +160,9 @@ android_app {
"android.app.contextualsearch.flags-aconfig",
"android.app.flags-aconfig",
"android.appwidget.flags-aconfig",
+ "android.companion.virtualdevice.flags-aconfig",
"android.content.pm.flags-aconfig",
+ "android.media.audio-aconfig",
"android.provider.flags-aconfig",
"camera_platform_flags",
"android.net.platform.flags-aconfig",
@@ -170,6 +172,7 @@ android_app {
"android.os.vibrator.flags-aconfig",
"android.media.tv.flags-aconfig",
"android.security.flags-aconfig",
+ "device_policy_aconfig_flags",
"com.android.hardware.input.input-aconfig",
"aconfig_trade_in_mode_flags",
"art-aconfig-flags",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3e0c1200749e..a13e334e28c8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -914,13 +914,26 @@
android:featureFlag="android.provider.user_keys" />
<!-- Allows an application to set default account for new contacts.
- <p> This permission is only granted to system applications fulfilling the Contacts app role.
+ <p>This permission is only granted to system applications fulfilling the Contacts app role.
<p>Protection level: internal|role
@SystemApi
@hide
-->
<permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"
- android:protectionLevel="internal|role" />
+ android:protectionLevel="internal|role"
+ android:featureFlag="!android.provider.new_default_account_api_enabled"/>
+
+ <!-- Allows an application to set default account for new contacts.
+ <p>This permission is only granted to system applications fulfilling the Contacts app role
+ and the application with known signers.
+ <p>Protection level: internal|role|knownSigner
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"
+ android:protectionLevel="internal|role|knownSigner"
+ android:knownCerts="@array/config_setContactsDefaultAccountKnownSigners"
+ android:featureFlag="android.provider.new_default_account_api_enabled"/>
<!-- ====================================================================== -->
<!-- Permissions for accessing user's calendar -->
@@ -1080,6 +1093,52 @@
<permission android:name="android.permission.SATELLITE_COMMUNICATION"
android:protectionLevel="role|signature|privileged" />
+ <!-- ================================== -->
+ <!-- Permissions associated with picture and sound profiles -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
+ Allows an app to apply a {@link MediaQualityManager.PictureProfile} to a layer via
+ {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and, additionally, system apps via
+ {@link SurfaceControl.Transaction#setPictureProfileHandle}.
+ -->
+ <permission android:name="android.permission.APPLY_PICTURE_PROFILE"
+ android:protectionLevel="normal"
+ android:featureFlag="android.media.tv.flags.apply_picture_profiles"/>
+
+ <!-- @hide
+ Allows MediaQualityService to observe any {@link MediaQualityManager.PictureProfile}
+ applied to any layer in the system by apps via
+ {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and by system apps via
+ {@link SurfaceControl.Transaction#setPictureProfileHandle}.
+ -->
+ <permission android:name="android.permission.OBSERVE_PICTURE_PROFILES"
+ android:protectionLevel="signature|privileged"
+ android:featureFlag="android.media.tv.flags.apply_picture_profiles"/>
+
+ <!--
+ @SystemApi
+ @FlaggedApi("android.media.tv.flags.media_quality_fw")
+ Allows an application to access its picture profile from the media quality database.
+ <p> Protection level: signature|privileged|vendor privileged
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"
+ android:protectionLevel="signature|privileged|vendorPrivileged"
+ android:featureFlag="android.media.tv.flags.media_quality_fw"/>
+
+ <!--
+ @SystemApi
+ @FlaggedApi("android.media.tv.flags.media_quality_fw")
+ Allows an application to access its sound profile from the media quality database.
+ <p> Protection level: signature|privileged|vendor privileged
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE"
+ android:protectionLevel="signature|privileged|vendorPrivileged"
+ android:featureFlag="android.media.tv.flags.media_quality_fw"/>
+
<!-- ====================================================================== -->
<!-- Permissions for accessing external storage -->
<!-- ====================================================================== -->
@@ -2590,6 +2649,22 @@
android:label="@string/permlab_getAccounts" />
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
+ <!-- @SystemApi Allows access to remove an account.
+ @FlaggedApi(android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.REMOVE_ACCOUNTS"
+ android:protectionLevel="signature|role"
+ android:featureFlag="android.app.admin.flags.split_create_managed_profile_enabled" />
+
+ <!-- @SystemApi Allows access to copy an account to another user.
+ @FlaggedApi(android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.COPY_ACCOUNTS"
+ android:protectionLevel="signature|role"
+ android:featureFlag="android.app.admin.flags.split_create_managed_profile_enabled" />
+
<!-- Allows applications to call into AccountAuthenticators.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
@@ -4126,24 +4201,56 @@
android:protectionLevel="signature|installer" />
<uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" />
- <!-- Allows an application to toggle the device's advanced protection mode status.
- @FlaggedApi("android.security.aapm_api")
+ <!-- Allows an application to modify the device's advanced protection mode status, and query
+ the list of enabled features
+ @FlaggedApi(android.security.Flags.FLAG_AAPM_API)
@SystemApi
@hide -->
- <permission android:name="android.permission.SET_ADVANCED_PROTECTION_MODE"
+ <permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE"
android:protectionLevel="signature|privileged"
android:featureFlag="android.security.aapm_api"/>
- <uses-permission android:name="android.permission.SET_ADVANCED_PROTECTION_MODE"
+ <uses-permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE"
android:featureFlag="android.security.aapm_api"/>
<!-- Allows an application to query the device's advanced protection mode status.
- @FlaggedApi("android.security.aapm_api") -->
+ @FlaggedApi(android.security.Flags.FLAG_AAPM_API) -->
<permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE"
android:protectionLevel="normal"
android:featureFlag="android.security.aapm_api"/>
<uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE"
android:featureFlag="android.security.aapm_api"/>
+ <!-- Allows an application to read the state of the IntrusionDetectionService
+ @FlaggedApi(android.security.Flags.FLAG_AFL_API)
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.READ_INTRUSION_DETECTION_STATE"
+ android:featureFlag="android.security.afl_api"
+ android:protectionLevel="signature|privileged" />
+ <uses-permission android:name="android.permission.READ_INTRUSION_DETECTION_STATE"
+ android:featureFlag="android.security.afl_api"/>
+
+ <!-- Allows an application to change the state of the IntrusionDetectionService
+ @FlaggedApi(android.security.Flags.FLAG_AFL_API)
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.MANAGE_INTRUSION_DETECTION_STATE"
+ android:featureFlag="android.security.afl_api"
+ android:protectionLevel="signature|privileged" />
+ <uses-permission android:name="android.permission.MANAGE_INTRUSION_DETECTION_STATE"
+ android:featureFlag="android.security.afl_api"/>
+
+ <!-- Must be required by any IntrusionDetectionEventTransportService to ensure that
+ only the system can bind to it.
+ @FlaggedApi(android.security.Flags.FLAG_AFL_API)
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE"
+ android:featureFlag="android.security.afl_api"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE"
+ android:featureFlag="android.security.afl_api"/>
+
<!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.-->
<permission android:name="android.permission.PROVISION_DEMO_DEVICE"
android:protectionLevel="signature|setup|knownSigner"
@@ -4991,16 +5098,16 @@
android:protectionLevel="signature|privileged|role"
android:featureFlag="com.android.settingslib.flags.settings_catalyst" />
- <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_SETTINGS_CATALYST)
+ <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_WRITE_SYSTEM_PREFERENCE_PERMISSION_ENABLED)
Allows an application to access the Settings Preference services to write settings
values exposed by the system Settings app and system apps that contribute settings surfaced
in the Settings app.
<p>This allows the calling application to write settings values
through the host application, agnostic of underlying storage.
- <p>Protection Level: signature|privileged|appop - appop to be added in followup -->
+ <p>Protection Level: signature|privileged|appop -->
<permission android:name="android.permission.WRITE_SYSTEM_PREFERENCES"
- android:protectionLevel="signature|privileged"
- android:featureFlag="com.android.settingslib.flags.settings_catalyst" />
+ android:protectionLevel="signature|privileged|appop"
+ android:featureFlag="com.android.settingslib.flags.write_system_preference_permission_enabled" />
<!-- ========================================= -->
<!-- Permissions for special development tools -->
@@ -5497,7 +5604,8 @@
<permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE"
android:protectionLevel="signature" />
- <!-- Allows an application to subscribe to keyguard locked (i.e., showing) state.
+ <!-- Allows an application to subscribe to device locked and keyguard locked (i.e., showing)
+ state.
<p>Protection level: signature|role
<p>Intended for use by ROLE_ASSISTANT and signature apps only.
-->
@@ -6401,6 +6509,15 @@
<permission android:name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT"
android:protectionLevel="signature|privileged|role" />
+ <!-- @SystemApi Allows an application to bypass concurrency restrictions while
+ recording audio. For example, apps with this permission can continue to record
+ while a voice call is active.</p>
+ @FlaggedApi(android.media.audio.Flags.FLAG_CONCURRENT_AUDIO_RECORD_BYPASS_PERMISSION)
+ @hide -->
+ <permission android:name="android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION"
+ android:featureFlag="android.media.audio.concurrent_audio_record_bypass_permission"
+ android:protectionLevel="signature|privileged|role" />
+
<!-- @SystemApi Allows an application to capture audio for hotword detection.
<p>Not for use by third-party applications.</p>
@hide -->
@@ -7844,7 +7961,31 @@
<!-- @SystemApi Allows an application to access shared libraries.
@hide -->
<permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer"
+ android:featureFlag="!android.content.pm.sdk_dependency_installer" />
+
+ <!-- @SystemApi Allows an application to access shared libraries.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
+ android:protectionLevel="signature|installer|role"
+ android:featureFlag="android.content.pm.sdk_dependency_installer" />
+
+ <!-- @SystemApi Permission held by the system to allow binding to the dependency installer role
+ holder.
+ @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+ @hide -->
+ <permission android:name="android.permission.BIND_DEPENDENCY_INSTALLER"
+ android:protectionLevel="signature"
+ android:featureFlag="android.content.pm.sdk_dependency_installer" />
+
+ <!-- @SystemApi Allows an application to install shared libraries of types
+ {@link android.content.pm.SharedLibraryInfo#TYPE_STATIC} or
+ {@link android.content.pm.SharedLibraryInfo#TYPE_SDK_PACKAGE}.
+ @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+ @hide -->
+ <permission android:name="android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES"
+ android:protectionLevel="signature|role"
+ android:featureFlag="android.content.pm.sdk_dependency_installer" />
<!-- Allows an app to log compat change usage.
@hide <p>Not for use by third-party applications.</p> -->
@@ -7919,6 +8060,13 @@
<permission android:name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY"
android:protectionLevel="signature|role"/>
+ <!-- Allows an application to create displays that mirror other displays' content.
+ @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ENABLE_LIMITED_VDM_ROLE)
+ @hide @SystemApi -->
+ <permission android:name="android.permission.ADD_MIRROR_DISPLAY"
+ android:protectionLevel="internal|role"
+ android:featureFlag="android.companion.virtualdevice.flags.enable_limited_vdm_role" />
+
<!-- @hide @SystemApi Allows an application to access locusId events in the usage stats. -->
<permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
android:protectionLevel="signature|role" />
@@ -8536,6 +8684,17 @@
<permission android:name="android.permission.SETUP_FSVERITY"
android:protectionLevel="signature|privileged"/>
+ <!-- @SystemApi
+ @FlaggedApi(android.security.Flags.FLAG_SECURE_LOCKDOWN)
+ Allows an application to lock down the device into an enhanced security state.
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_SECURE_LOCK_DEVICE"
+ android:protectionLevel="signature|privileged"
+ android:featureFlag="android.security.secure_lockdown" />
+
<!-- Allows app to enter trade-in-mode.
<p>Protection level: signature|privileged
@hide
@@ -8566,50 +8725,6 @@
android:protectionLevel="signature"/>
<!--
- @SystemApi
- @FlaggedApi("android.media.tv.flags.media_quality_fw")
- Allows an application to access its picture profile from the media quality database.
- <p> Protection level: signature|privileged|vendor privileged
- @hide
- -->
- <permission android:name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"
- android:protectionLevel="signature|privileged|vendorPrivileged"
- android:featureFlag="android.media.tv.flags.media_quality_fw"/>
-
- <!--
- @SystemApi
- @FlaggedApi("android.media.tv.flags.media_quality_fw")
- Allows an application to access its sound profile from the media quality database.
- <p> Protection level: signature|privileged|vendor privileged
- @hide
- -->
- <permission android:name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE"
- android:protectionLevel="signature|privileged|vendorPrivileged"
- android:featureFlag="android.media.tv.flags.media_quality_fw"/>
- <!-- @SystemApi
- @FlaggedApi("android.content.pm.verification_service")
- Allows app to be the verification agent to verify packages.
- <p>Protection level: signature|privileged
- @hide
- -->
- <permission android:name="android.permission.VERIFICATION_AGENT"
- android:protectionLevel="signature|privileged"
- android:featureFlag="android.content.pm.verification_service" />
-
- <!-- @SystemApi
- @FlaggedApi("android.content.pm.verification_service")
- Must be required by a privileged {@link android.content.pm.verify.pkg.VerifierService}
- to ensure that only the system can bind to it.
- This permission should not be held by anything other than the system.
- <p>Not for use by third-party applications. </p>
- <p>Protection level: signature
- @hide
- -->
- <permission android:name="android.permission.BIND_VERIFICATION_AGENT"
- android:protectionLevel="internal"
- android:featureFlag="android.content.pm.verification_service" />
-
- <!--
This permission allows the system to receive PACKAGE_CHANGED broadcasts when the component
state of a non-exported component has been changed.
<p>Not for use by third-party applications. </p>
diff --git a/core/res/res/drawable-watch-v36/btn_background_material_filled.xml b/core/res/res/drawable-watch-v36/btn_background_material_filled.xml
index 0029de14e34a..6e74f64fea60 100644
--- a/core/res/res/drawable-watch-v36/btn_background_material_filled.xml
+++ b/core/res/res/drawable-watch-v36/btn_background_material_filled.xml
@@ -19,7 +19,7 @@
<item>
<shape android:shape="rectangle">
<solid android:color="@color/btn_material_filled_background_color"/>
- <corners android:radius="?android:attr/buttonCornerRadius"/>
+ <corners android:radius="@dimen/config_wearMaterial3_buttonCornerRadius"/>
<size
android:width="@dimen/btn_material_width"
android:height="@dimen/btn_material_height" />
diff --git a/core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml b/core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml
index 105f077cd841..fbd697371329 100644
--- a/core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml
+++ b/core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml
@@ -19,7 +19,7 @@
<item>
<shape android:shape="rectangle">
<solid android:color="@color/btn_material_filled_tonal_background_color"/>
- <corners android:radius="?android:attr/buttonCornerRadius"/>
+ <corners android:radius="@dimen/config_wearMaterial3_buttonCornerRadius"/>
<size
android:width="@dimen/btn_material_width"
android:height="@dimen/btn_material_height" />
diff --git a/core/res/res/drawable/notification_progress.xml b/core/res/res/drawable/notification_progress.xml
index 3a6b60077045..5d272fb00e34 100644
--- a/core/res/res/drawable/notification_progress.xml
+++ b/core/res/res/drawable/notification_progress.xml
@@ -24,9 +24,9 @@
android:segPointGap="@dimen/notification_progress_segPoint_gap">
<segments
android:color="?attr/colorProgressBackgroundNormal"
- android:dashGap="@dimen/notification_progress_segments_dash_gap"
- android:dashWidth="@dimen/notification_progress_segments_dash_width"
- android:width="@dimen/notification_progress_segments_height" />
+ android:height="@dimen/notification_progress_segments_height"
+ android:fadedHeight="@dimen/notification_progress_segments_faded_height"
+ android:cornerRadius="@dimen/notification_progress_segments_corner_radius"/>
<points
android:color="?attr/colorProgressBackgroundNormal"
android:radius="@dimen/notification_progress_points_radius"
diff --git a/core/res/res/layout-sw600dp/preference_list_content_single.xml b/core/res/res/layout-sw600dp/preference_list_content_single.xml
index 88b1aa8d4d00..ebe4eca1b156 100644
--- a/core/res/res/layout-sw600dp/preference_list_content_single.xml
+++ b/core/res/res/layout-sw600dp/preference_list_content_single.xml
@@ -19,6 +19,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent">
diff --git a/core/res/res/layout/list_content_simple.xml b/core/res/res/layout/list_content_simple.xml
index 6f9f1e0f0f6f..961668e6bf2e 100644
--- a/core/res/res/layout/list_content_simple.xml
+++ b/core/res/res/layout/list_content_simple.xml
@@ -20,5 +20,6 @@
<ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
android:drawSelectorOnTop="false"
/>
diff --git a/core/res/res/layout/notification_2025_reply_container.xml b/core/res/res/layout/notification_2025_reply_container.xml
new file mode 100644
index 000000000000..6923b59f34dc
--- /dev/null
+++ b/core/res/res/layout/notification_2025_reply_container.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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
+ -->
+
+<!-- Note: this layout is included from a view stub; layout attributes will be overridden. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingStart="@dimen/notification_2025_content_margin_start">
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:id="@+id/action_divider"
+ android:layout_marginTop="@dimen/notification_content_margin"
+ android:layout_marginBottom="@dimen/notification_content_margin"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:background="@drawable/notification_template_divider" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+ android:singleLine="true" />
+
+ <LinearLayout
+ android:id="@+id/notification_material_reply_text_1_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginEnd="@dimen/notification_content_margin_end">
+ <TextView
+ android:id="@+id/notification_material_reply_text_1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:layout_gravity="center"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+ android:singleLine="true" />
+ <ProgressBar
+ android:id="@+id/notification_material_reply_progress"
+ android:layout_height="@dimen/messaging_group_sending_progress_size"
+ android:layout_width="@dimen/messaging_group_sending_progress_size"
+ android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ style="?android:attr/progressBarStyleSmall" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml
new file mode 100644
index 000000000000..4eac6d991272
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:minHeight="@dimen/notification_headerless_min_height"
+ android:tag="base"
+ >
+
+ <ImageView
+ android:id="@+id/left_icon"
+ android:layout_width="@dimen/notification_2025_left_icon_size"
+ android:layout_height="@dimen/notification_2025_left_icon_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_left_icon_start"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:visibility="gone"
+ />
+
+ <com.android.internal.widget.NotificationRowIconView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_2025_icon_circle_size"
+ android:layout_height="@dimen/notification_2025_icon_circle_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:padding="@dimen/notification_2025_icon_circle_padding"
+ android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size"
+ android:maxDrawableHeight="@dimen/notification_2025_icon_circle_size"
+ />
+
+ <FrameLayout
+ android:id="@+id/alternate_expand_target"
+ android:layout_width="@dimen/notification_2025_content_margin_start"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:importantForAccessibility="no"
+ android:focusable="false"
+ />
+
+ <LinearLayout
+ android:id="@+id/notification_headerless_view_row"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+ android:orientation="horizontal"
+ >
+
+ <LinearLayout
+ android:id="@+id/notification_headerless_view_column"
+ android:layout_width="0px"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+ android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+ android:orientation="vertical"
+ >
+
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_headerless_line_height"
+ android:clipChildren="false"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ >
+
+ <!--
+ NOTE: The notification_top_line_views layout contains the app_name_text.
+ In order to include the title view at the beginning, the Notification.Builder
+ has logic to hide that view whenever this title view is to be visible.
+ -->
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+ />
+
+ <include layout="@layout/notification_top_line_views" />
+
+ </NotificationTopLineView>
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+
+ <com.android.internal.widget.NotificationVanishingFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_headerless_line_height"
+ >
+ <!-- This is the simplest way to keep this text vertically centered without
+ gravity="center_vertical" which causes jumpiness in expansion animations. -->
+ <include
+ layout="@layout/notification_2025_template_text"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_text_height"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="0dp"
+ />
+ </com.android.internal.widget.NotificationVanishingFrameLayout>
+
+ <include
+ layout="@layout/notification_template_progress"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/right_icon"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:maxDrawableWidth="@dimen/notification_right_icon_size"
+ android:maxDrawableHeight="@dimen/notification_right_icon_size"
+ />
+
+ <LinearLayout
+ android:id="@+id/notification_buttons_column"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:orientation="vertical"
+ >
+
+ <include layout="@layout/notification_close_button"
+ android:layout_width="@dimen/notification_close_button_size"
+ android:layout_height="@dimen/notification_close_button_size"
+ android:layout_gravity="end"
+ android:layout_marginEnd="20dp"
+ />
+
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_base.xml b/core/res/res/layout/notification_2025_template_expanded_base.xml
new file mode 100644
index 000000000000..e480fe5eef1e
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_base.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ android:tag="big"
+ >
+
+ <LinearLayout
+ android:id="@+id/notification_action_list_margin_target"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/notification_content_margin"
+ android:orientation="vertical"
+ >
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="top"
+ >
+
+ <include layout="@layout/notification_2025_template_header" />
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:orientation="vertical"
+ >
+
+ <include layout="@layout/notification_template_part_line1" />
+
+ <include layout="@layout/notification_template_text_multiline" />
+
+ <include
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_progress_bar_height"
+ android:layout_marginTop="@dimen/notification_progress_margin_top"
+ layout="@layout/notification_template_progress"
+ />
+ </LinearLayout>
+
+ <include layout="@layout/notification_template_right_icon" />
+ </FrameLayout>
+
+ <ViewStub
+ android:layout="@layout/notification_2025_reply_container"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
+ <include
+ layout="@layout/notification_template_smart_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:layout_marginTop="@dimen/notification_content_margin"
+ />
+
+ <include layout="@layout/notification_material_action_list" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml
new file mode 100644
index 000000000000..b7fe454e09d4
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_header.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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
+ -->
+
+<!-- extends RelativeLayout -->
+<NotificationHeaderView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_header"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_2025_header_height"
+ android:layout_marginBottom="@dimen/notification_header_margin_bottom"
+ android:clipChildren="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ android:importantForAccessibility="no"
+ >
+
+ <ImageView
+ android:id="@+id/left_icon"
+ android:layout_width="@dimen/notification_2025_left_icon_size"
+ android:layout_height="@dimen/notification_2025_left_icon_size"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_left_icon_start"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:visibility="gone"
+ />
+
+ <com.android.internal.widget.NotificationRowIconView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_2025_icon_circle_size"
+ android:layout_height="@dimen/notification_2025_icon_circle_size"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:padding="@dimen/notification_2025_icon_circle_padding"
+ android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size"
+ android:maxDrawableHeight="@dimen/notification_2025_icon_circle_size"
+ />
+
+ <!-- extends ViewGroup -->
+ <NotificationTopLineView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_top_line"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_toStartOf="@id/notification_buttons_column"
+ android:layout_alignWithParentIfMissing="true"
+ android:clipChildren="false"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/notification_2025_content_margin_start"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ >
+
+ <include layout="@layout/notification_top_line_views" />
+
+ </NotificationTopLineView>
+
+ <FrameLayout
+ android:id="@+id/alternate_expand_target"
+ android:layout_width="@dimen/notification_2025_content_margin_start"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:importantForAccessibility="no"
+ android:focusable="false"
+ />
+
+ <LinearLayout
+ android:id="@+id/notification_buttons_column"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:orientation="vertical"
+ >
+
+ <include layout="@layout/notification_close_button"
+ android:layout_width="@dimen/notification_close_button_size"
+ android:layout_height="@dimen/notification_close_button_size"
+ android:layout_gravity="end"
+ android:layout_marginEnd="20dp"
+ />
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ />
+
+ </LinearLayout>
+
+</NotificationHeaderView>
diff --git a/core/res/res/layout/notification_2025_template_heads_up_base.xml b/core/res/res/layout/notification_2025_template_heads_up_base.xml
new file mode 100644
index 000000000000..e4ff835a3524
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_heads_up_base.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2014 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ android:tag="headsUp"
+ >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:orientation="vertical"
+ >
+
+ <include
+ layout="@layout/notification_2025_template_collapsed_base"
+ android:id="@null"
+ />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-20dp"
+ android:clipChildren="false"
+ android:orientation="vertical"
+ >
+
+ <ViewStub
+ android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
+ <include
+ layout="@layout/notification_template_smart_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:layout_marginTop="@dimen/notification_content_margin"
+ />
+
+ <include layout="@layout/notification_material_action_list" />
+ </LinearLayout>
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_text.xml b/core/res/res/layout/notification_2025_template_text.xml
new file mode 100644
index 000000000000..48b1083a5e53
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_text.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<com.android.internal.widget.ImageFloatingTextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/Widget.DeviceDefault.Notification.Text"
+ android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_text_height"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_text_margin_top"
+ android:fadingEdge="horizontal"
+ android:gravity="top"
+ android:maxLines="1"
+ android:textAlignment="viewStart"
+ />
diff --git a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
index 82920bad95cd..149a5a9568f2 100644
--- a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
+++ b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
@@ -34,12 +34,14 @@
android:maxDrawableWidth="@dimen/notification_icon_circle_size"
android:maxDrawableHeight="@dimen/notification_icon_circle_size"
/>
- <com.android.internal.widget.NotificationRowIconView
+ <com.android.internal.widget.CachingIconView
android:id="@+id/conversation_icon"
android:layout_width="@dimen/notification_icon_circle_size"
android:layout_height="@dimen/notification_icon_circle_size"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:clipToOutline="true"
android:maxDrawableWidth="@dimen/notification_icon_circle_size"
android:maxDrawableHeight="@dimen/notification_icon_circle_size"
android:scaleType="centerCrop"
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index bed80edf0ee7..7a2fb0b3b822 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -20,6 +20,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent">
diff --git a/core/res/res/layout/preference_list_content_material.xml b/core/res/res/layout/preference_list_content_material.xml
index 37b411918ef6..23c82509b6b0 100644
--- a/core/res/res/layout/preference_list_content_material.xml
+++ b/core/res/res/layout/preference_list_content_material.xml
@@ -20,6 +20,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent">
diff --git a/core/res/res/layout/preference_list_content_single.xml b/core/res/res/layout/preference_list_content_single.xml
index 726ce78b281f..4f072da99546 100644
--- a/core/res/res/layout/preference_list_content_single.xml
+++ b/core/res/res/layout/preference_list_content_single.xml
@@ -19,6 +19,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent">
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index c43975e4ad3c..44a5df9b60be 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -19,6 +19,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="@android:color/transparent"
diff --git a/core/res/res/layout/preference_list_fragment_material.xml b/core/res/res/layout/preference_list_fragment_material.xml
index db2fe7d038e0..4df76029e606 100644
--- a/core/res/res/layout/preference_list_fragment_material.xml
+++ b/core/res/res/layout/preference_list_fragment_material.xml
@@ -19,6 +19,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="@android:color/transparent"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 9cfaca792f64..a4499efae37d 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Laat die program toe om relatiewe posisie tussen ultrabreëbandtoestelle in die omtrek te bepaal"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"om interaksie met wi‑fi-toestelle in die omtrek te hê"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Laat die program toe om op toestelle in die omtrek te adverteer, aan hulle te koppel en hul relatiewe posisie te bepaal"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"bepaal relatiewe posisie tussen toestelle in die omtrek"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Laat die app toe om relatiewe posisie tussen toestelle in die omtrek te bepaal"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Voorkeur-NFC-betalingdiensinligting"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Laat die program toe om voorkeur-NFC-betalingdiensinligting soos geregistreerde hulpmiddels en roetebestemming te kry."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"beheer kortveldkommunikasie"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Skakel aan"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Gaan terug"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Hangend …"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Satelliet-SOS is nou beskikbaar"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Jy kan vir nooddienste ’n boodskap stuur as daar geen selfoon- of wi-fi-netwerk is nie. Google Boodskappe moet jou verstekboodskapapp wees."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satelliet-SOS word nie gesteun nie"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Satelliet-SOS word nie op hierdie toestel gesteun nie"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satelliet-SOS is nie opgestel nie"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Maak seker jy is aan die internet gekoppel en probeer weer om op te stel"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satelliet-SOS is nie beskikbaar nie"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satelliet-SOS is nie in hierdie land of streek beskikbaar nie"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satelliet-SOS is nie opgestel nie"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Stel Google Boodskappe as jou verstekboodskapapp op om boodskappe per satelliet te stuur"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satelliet-SOS is nie beskikbaar nie"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Skakel ligginginstellings aan om te kyk of satelliet-SOS in hierdie land of streek beskikbaar is"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Satellietboodskappe is beskikbaar"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Jy kan per satelliet ’n boodskap stuur as daar geen selfoon- of wi-fi-netwerk is nie. Google Boodskappe moet jou verstekboodskapapp wees."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satellietboodskappe word nie gesteun nie"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Satellietboodskappe word nie op hierdie toestel gesteun nie"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satellietboodskappe is nie opgestel nie"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Maak seker jy is aan die internet gekoppel en probeer weer om op te stel"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satellietboodskappe is nie beskikbaar nie"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satellietboodskappe is nie in hierdie land of streek beskikbaar nie"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satellietboodskappe is nie opgestel nie"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Stel Google Boodskappe as jou verstekboodskapapp op om boodskappe per satelliet te stuur"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satellietboodskappe is nie beskikbaar nie"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Skakel ligginginstellings aan om te kyk of satellietboodskappe in hierdie land of streek beskikbaar is"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Stel Vingerafdrukslot weer op"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> kan nie meer herken word nie."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> en <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> kan nie meer herken word nie."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c30a5c853421..225f04d53ad0 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"በአቅራቢያ ባሉ ልዕለ-ሰፊ ባንድ መሣሪያዎች መካከል ያለውን አንጻራዊ አቀማመጣቸውን ለማወቅ ንዲችል ለመተግበሪያው ይፍቀዱ"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"በአቅራቢያ ካሉ የWi‑Fi መሣሪያዎች ጋር መስተጋብር መፍጠር"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"መተግበሪያው በአቅራቢያ ያሉ የWi-Fi መሣሪያዎች አንጻራዊ ቦታን እንዲያሳውቅ፣ እንዲያገናኝ እና እንዲያውቅ ያስችለዋል"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"በአቅራቢያ ባሉ መሣሪያዎች መካከል ያለውን አንጻራዊ አካባቢ ይወቁ"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"መተግበሪያው በአቅራቢያ ባሉ መሣሪያዎች መካከል ያለውን አንጻራዊ አካባቢ ለማወቅ እንዲችል ይፍቀዱለት"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ተመራጭ NFC የክፍያ አገልግሎት መረጃ"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"እንደ የተመዘገቡ እርዳታዎች እና የጉዞ መሥመር መዳረሻ የመሳሰለ ተመራጭ nfc የክፍያ አገልግሎት መረጃን ለማግኘት ለመተግበሪያው ያፈቅድለታል።"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ቅርብ የግኑኙነትመስክ (NFC) ተቆጣጠር"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"አብራ"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"ወደኋላ ተመለስ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"በመጠባበቅ ላይ..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"ሳተላይት ኤስኦኤስ አሁን ይገኛል"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"ምንም የሞባይል ወይም Wi-Fi አውታረ መረብ ባይኖርም እንኳን ለድንገተኛ አደጋ አገልግሎቶች መልዕክት መላክ ይችላሉ። Google መልዕክቶች የእርስዎ ነባሪ የመልዕክት መላኪያ መተግበሪያ መሆን አለበት።"</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"ሳተላይት ኤስኦኤስ አይደገፍም"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"ሳተላይት ኤስኦኤስ በዚህ መሣሪያ ላይ አይደገፍም"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"ሳተላይት ኤስኦኤስ አልተዋቀረም"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"ከበይነመረቡ ጋር መገናኘትዎን ያረጋግጡ እና ውቅረትን እንደገና ይሞክሩ"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"ሳተላይት ኤስኦኤስ አይገኝም"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"ሳተላይት ኤስኦኤስ በዚህ አገር ወይም ክልል ውስጥ አይገኝም"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"ሳተላይት ኤስኦኤስ አልተዋቀረም"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"በሳተላይት መልዕክት ለመላክ Google መልዕክቶችን እንደ የእርስዎ ነባሪ የመልዕክት መላኪያ መተግበሪያ ያቀናብሩ"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"ሳተላይት ኤስኦኤስ አይገኝም"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"በዚህ አገር ወይም ክልል ውስጥ ሳተላይት ኤስኦኤስ እንደሚገኝ ለመፈተሽ የአካባቢ ቅንብሮችን ያብሩ"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"የሳተላይት መልዕክት ይገኛል"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"የሞባይል ወይም የWi-Fi አውታረ መረብ ከሌለ በሳተላይት መልዕክት መላክ ይችላሉ። Google መልዕክቶች የእርስዎ ነባሪ የመልዕክት መላኪያ መተግበሪያ መሆን አለበት።"</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"የሳተላይት መልዕክት አይደገፍም"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"የሳተላይት መልዕክት በዚህ መሣሪያ ላይ አይደገፍም"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"የሳተላይት መልዕክት አልተዋቀረም"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"ከበይነመረቡ ጋር መገናኘትዎን ያረጋግጡ እና ውቅረትን እንደገና ይሞክሩ"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"የሳተላይት መልዕክት አይገኝም"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"የሳተላይት መልዕክት በዚህ አገር ወይም ክልል ውስጥ አይገኝም"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"የሳተላይት መልዕክት አልተዋቀረም"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"በሳተላይት መልዕክት ለመላክ Google መልዕክቶችን እንደ የእርስዎ ነባሪ የመልዕክት መላኪያ መተግበሪያ ያቀናብሩ"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"የሳተላይት መልዕክት አይገኝም"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"በዚህ አገር ወይም ክልል ውስጥ የሳተላይት መልዕክት እንደሚገኝ ለመፈተሽ የአካባቢ ቅንብሮችን ያብሩ"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"በጣት አሻራ መክፈቻን እንደገና ያዋቅሩ"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ከእንግዲህ መለየት አይችልም።"</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> እና <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ከእንግዲህ መለየት አይችሉም።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f2080cbbe3d9..484d22047fcf 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -616,10 +616,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"يسمح هذا الإذن للتطبيق بتحديد الموضع النسبي بين الأجهزة المجاورة التي تستخدم النطاق الواسع جدًا."</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"‏التفاعل مع أجهزة Wi‑Fi المجاورة"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"‏للسماح للتطبيق بعرض الإعلانات والاتصال بالأجهزة الأخرى وتحديد الموقع النسبي لأجهزة Wi-Fi المجاورة."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"تحديد الموضع النسبي بين الأجهزة المجاورة"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"يسمح هذا الإذن للتطبيق بتحديد الموضع النسبي بين الأجهزة المجاورة"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"‏معلومات الخدمات المدفوعة باستخدام الاتصال قصير المدى NFC المفضّل"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"‏يسمح هذا الإذن للتطبيق بالحصول على معلومات الخدمات المدفوعة باستخدام الاتصال قصير المدى NFC المفضّل، مثلاً المساعدات المسجّلة ووجهة المسار."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"التحكم في اتصال الحقل القريب"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 1f207d571c5a..fdddc70e56d3 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"এপ্‌টোক নিকটৱৰ্তী আল্ট্ৰা-ৱাইডবেণ্ড ডিভাইচসমূহৰ মাজৰ আপেক্ষিক স্থান নিৰ্ধাৰণ কৰিবলৈ অনুমতি দিয়ক"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"নিকটৱৰ্তী ৱাই-ফাই ডিভাইচসমূহৰ সৈতে ভাব বিনিময় কৰক"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"এপ্‌টোক বিজ্ঞাপন প্ৰচাৰাভিযান কৰিবলৈ, সংযোগ কৰিবলৈ আৰু নিকটৱৰ্তী ৱাই-ফাই ডিভাইচৰ আপেক্ষিক স্থান নিৰ্ধাৰণ কৰিবলৈ অনুমতি দিয়ে"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"নিকটৱৰ্তী ডিভাইচৰ মাজৰ আপেক্ষিক স্থান নিৰ্ধাৰণ কৰক"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"এপ্‌টোক নিকটৱৰ্তী ডিভাইচসমূহৰ মাজৰ আপেক্ষিক স্থান নিৰ্ধাৰণ কৰিবলৈ অনুমতি দিয়ক"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"অগ্ৰাধিকাৰ দিয়া NFC পৰিশোধ সেৱাৰ তথ্য"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"এপ্‌টোক অগ্ৰাধিকাৰ দিয়া nfc পৰিশোধ সেৱাৰ পঞ্জীকৃত সহায়কসমূহ আৰু পৰিশোধ কৰিব লগা লক্ষ্যস্থান দৰে তথ্য পাবলৈ অনুমতি দিয়ে।"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"নিয়েৰ ফিল্ড কমিউনিকেশ্বন নিয়ন্ত্ৰণ কৰক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 07216f55bdcd..003c0dbc6f26 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Tətbiqə yaxınlıqdakı Ultra Genişzolaqlı cihazları arasında nisbi mövqeyi təyin etməyə icazə verin"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"yaxınlıqdakı Wi-Fi cihazları ilə əlaqə qurmaq"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Tətbiqə yaxınlıqdakı Wi-Fi cihazlarında reklam etmək, onlara qoşulmaq və nisbi mövqeyini təyin etmək icazəsi verir"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"yaxınlıqdakı cihazlar arasında nisbi mövqeyin təyini"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Tətbiqin yaxınlıqdakı cihazlar arasında nisbi mövqeyi təyin etməsinə icazə verin"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Tərcih edilən NFC ödəniş xidməti məlumatı"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Tətbiqə qeydiyyatdan keçmiş yardım və marşrut təyinatı kimi tərcih edilən nfc ödəniş xidməti məlumatını əldə etmək icazəsi verir."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"Near Field Communication\'ı kontrol et"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Aktiv edin"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Geri qayıdın"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Gözləmədə..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Təcili peyk bağlantısı artıq əlçatandır"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Mobil və ya Wi-Fi şəbəkəsi yoxdursa, təcili xidmətlərə mesaj göndərə bilərsiniz. Google Mesajlar defolt mesajlaşma tətbiqiniz olmalıdır."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Təcili peyk bağlantısı dəstəklənmir"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Təcili peyk bağlantısı bu cihazda dəstəklənmir"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Təcili peyk bağlantısı ayarlanmayıb"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"İnternetə qoşulduğunuzdan əmin olun və yenidən ayarlamağa cəhd edin"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Təcili peyk bağlantısı əlçatan deyil"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Təcili peyk bağlantısı bu ölkə və ya regionda əlçatan deyil"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Təcili peyk bağlantısı ayarlanmayıb"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Peyk vasitəsilə mesaj göndərmək üçün Google Mesajları defolt mesajlaşma tətbiqi olaraq təyin edin"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Təcili peyk bağlantısı əlçatan deyil"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Bu ölkədə və ya regionda təcili peyk bağlantısının əlçatan olub-olmadığını yoxlamaq üçün məkan ayarlarını aktiv edin"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Peyk mesajlaşması əlçatandır"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Mobil və ya Wi-Fi şəbəkəsi yoxdursa, peyk vasitəsilə mesaj göndərə bilərsiniz. Google Mesajlar defolt mesajlaşma tətbiqiniz olmalıdır."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Peyk mesajlaşması dəstəklənmir"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Peyk mesajlaşması bu cihazda dəstəklənmir"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Peyk mesajlaşması quraşdırılmayıb"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"İnternetə qoşulduğunuzdan əmin olun və yenidən ayarlamağa cəhd edin"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Peyk mesajlaşması əlçatan deyil"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Peyk mesajlaşması bu ölkə və ya regionda əlçatan deyil"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Peyk mesajlaşması quraşdırılmayıb"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Peyk vasitəsilə mesaj göndərmək üçün Google Mesajları defolt mesajlaşma tətbiqi olaraq təyin edin"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Peyk mesajlaşması əlçatan deyil"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Bu ölkədə və ya regionda peyk mesajlaşmasının əlçatan olub-olmadığını yoxlamaq üçün məkan ayarlarını aktiv edin"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Barmaqla Kilidaçmanı yenidən ayarlayın"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> artıq tanınmır."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> və <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> artıq tanınmır."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index ac6a47fd8f84..5a848bafc7eb 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Dozvoljava aplikaciji da određuje relativnu razdaljinu između uređaja ultra-širokog pojasa u blizini"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interakcija sa WiFi uređajima u blizini"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Dozvoljava aplikaciji da se oglašava, povezuje i utvrđuje relativnu poziciju WiFi uređaja u blizini"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"određivanje razdaljine između uređaja u blizini"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Dozvolite aplikaciji da određuje relativnu razdaljinu između uređaja u blizini"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informacije o željenoj NFC usluzi za plaćanje"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Dozvoljava aplikaciji da preuzima informacije o željenoj NFC usluzi za plaćanje, poput registrovanih identifikatora aplikacija i odredišta preusmeravanja."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrola komunikacije u užem polju (Near Field Communication)"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index f492bfa4cc7b..ce98a5ff7473 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Дазволіць праграме вызначаць адлегласць паміж прыладамі паблізу, якія выкарыстоўваюць звышшырокапалосную сувязь"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"узаемадзейнічаць з прыладамі з Wi‑Fi паблізу"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Праграма зможа адпраўляць даныя на прылады Wi-Fi паблізу, падключацца да іх і вызначаць іх месцазнаходжанне"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"вызначаць адноснае месцазнаходжанне прылад паблізу"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Дазвольце праграме вызначаць адноснае месцазнаходжанне прылад паблізу"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Інфармацыя пра прыярытэтны сэрвіс аплаты NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Дазваляе праграме атрымаць доступ да інфармацыі пра прыярытэтны сэрвіс аплаты NFC, напрыклад зарэгістраваныя ідэнтыфікатары праграм і маршруты адпраўкі даных."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"кантроль Near Field Communication"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index c8b171af5bc9..aad5d48f80cd 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Разрешаване на приложението да определя относителната позиция между устройствата с ултрашироколентови сигнали в близост"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"взаимодействие с устройствата с Wi-Fi в близост"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Разрешава на приложението да рекламира, да се свързва и да определя относителната позиция на устройствата с Wi-Fi в близост"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"опр. на относителната позиция м/у у-вата в близост"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Разрешаване на приложението да определя относителната позиция между устройствата в близост"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Информация за предпочитаната услуга за плащане чрез NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Дава възможност на приложението да получава информация за предпочитаната услуга за плащане чрез NFC, като например регистрирани помощни средства и местоназначение."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"контролиране на комуникацията в близкото поле"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Включване"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Назад"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Изчаква..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Функцията „SOS чрез сателит“ вече е налице"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Можете да изпращате съобщения до службите за спешни случаи, ако нямате връзка с мобилна или Wi-Fi мрежа. Google Messages трябва да е основното ви приложение за съобщения."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Функцията „SOS чрез сателит“ не се поддържа"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Функцията „SOS чрез сателит“ не се поддържа на това устройство"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Функцията „SOS чрез сателит“ не е настроена"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Проверете дали имате връзка с интернет, и опитайте да настроите отново"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Функцията „SOS чрез сателит“ не е налице"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Функцията „SOS чрез сателит“ не е налице в тази държава или регион"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Функцията „SOS чрез сателит“ не е настроена"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"За да изпращате съобщения чрез сателит, задайте Google Messages като основното си приложение за съобщения"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Функцията „SOS чрез сателит“ не е налице"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"За да проверите дали функцията „SOS чрез сателит“ е налице в тази държава или регион, включете настройките за местоположението"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Функцията за сателитни съобщения е налице"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Можете да изпращате съобщения чрез сателит, ако нямате връзка с мобилна или Wi-Fi мрежа. Google Messages трябва да е основното ви приложение за съобщения."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Функцията за сателитни съобщения не се поддържа"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Функцията за сателитни съобщения не се поддържа на това устройство"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Функцията за сателитни съобщения не е настроена"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Проверете дали имате връзка с интернет, и опитайте да настроите отново"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Функцията за сателитни съобщения не е налице"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Функцията за сателитни съобщения не е налице в тази държава или регион"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Функцията за сателитни съобщения не е настроена"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"За да изпращате съобщения чрез сателит, задайте Google Messages като основното си приложение за съобщения"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Функцията за сателитни съобщения не е налице"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"За да проверите дали функцията за сателитни съобщения е налице в тази държава или регион, включете настройките за местоположението"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Повторно настройване на „Отключване с отпечатък“"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> вече не може да се разпознае."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> вече не могат да бъдат разпознати."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 0e103cc424b0..d52f6e91f45b 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"অ্যাপকে আশেপাশের Ultra-Wideband ডিভাইসগুলির আপেক্ষিক অবস্থান নির্ণয় করার অনুমতি দিন"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"আশপাশের ওয়াই-ফাই ডিভাইসের সাথে ইন্টার‍্যাক্ট করুন"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"এটির ফলে অ্যাপ আশপাশের ওয়াই-ফাই ডিভাইসের তথ্য দেখতে, তাদের সাথে কানেক্ট করতে এবং তা কত দূরত্বে আছে সেটি জানতে পারবে"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"আশেপাশের ডিভাইসের আপেক্ষিক অবস্থান নির্ণয় করুন"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"অ্যাপকে আশেপাশের ডিভাইসের আপেক্ষিক অবস্থান নির্ণয় করার অনুমতি দিন"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"পছন্দের NFC পেমেন্ট পরিষেবার তথ্য"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"অ্যাপের মাধ্যমে পছন্দসই এনএফসি পেমেন্ট পরিষেবার তথ্য, যেমন রেজিস্ট্রার করার সহায়তা এবং রুট ডেস্টিনেশন সম্পর্কিত তথ্য অ্যাক্সেস করার অনুমতি দেয়।"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"নিয়ার ফিল্ড কমিউনিকেশন নিয়ন্ত্রণ করে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 202afdeb9438..b74b13966405 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Dozvolite aplikaciji da odredi relativni položaj između uređaja ultra širokog opsega u blizini"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"stupanje u interakciju s WiFi uređajima u blizini"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Dozvoljava aplikaciji da se oglašava, povezuje i određuje relativni položaj WiFi uređaja u blizini"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"određivanje relativnog položaja uređaja u blizini"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Dozvolite aplikaciji da odredi relativni položaj između uređaja u blizini"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informacije o preferiranoj usluzi plaćanja putem NFC-a"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Dozvoljava aplikaciji da dobije informacije o preferiranoj usluzi plaćanja putem NFC-a kao što su registrirana pomagala i odredište rute."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"upravljanje NFC-om"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8b28cd7891c8..7500122e6d94 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permet que l\'aplicació determini la posició relativa entre els dispositius de banda ultraampla propers"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interaccionar amb els dispositius Wi‑Fi propers"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permet que l\'aplicació s\'anunciï i es connecti als dispositius Wi‑Fi propers, i en determini la posició relativa"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determin. posició relativa entre dispositius propers"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permet que l\'aplicació determini la posició relativa entre els dispositius propers"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informació preferent sobre el servei de pagament per NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permet que l\'aplicació obtingui informació preferent sobre el servei de pagament per NFC, com ara complements registrats i destinacions de rutes."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlar Comunicació de camp proper (NFC)"</string>
@@ -2436,54 +2434,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Activa"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Torna"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendent..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS per satèl·lit ja està disponible"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Pots enviar missatges als serveis d\'emergències si no tens cap xarxa mòbil ni Wi‑Fi. Missatges de Google ha de ser l\'aplicació de missatgeria predeterminada."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"SOS per satèl·lit no s\'admet"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"SOS per satèl·lit no s\'admet en aquest dispositiu"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS per satèl·lit no està configurat"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Comprova que tinguis connexió a Internet i torna a provar de configurar-lo"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS per satèl·lit no està disponible"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS per satèl·lit no està disponible en aquest país o regió"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS per satèl·lit no està configurat"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Per enviar missatges per satèl·lit, defineix Missatges de Google com a aplicació de missatgeria predeterminada"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS per satèl·lit no està disponible"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Per comprovar si SOS per satèl·lit està disponible en aquest país o regió, activa la configuració d\'ubicació"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Missatges per satèl·lit disponibles"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Pots enviar missatges per satèl·lit si no tens cap xarxa mòbil ni Wi‑Fi. Missatges de Google ha de ser l\'aplicació de missatgeria predeterminada."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Els missatges per satèl·lit no s\'admeten"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Els missatges per satèl·lit no s\'admeten en aquest dispositiu"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Els missatges per satèl·lit no estan configurats"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Comprova que tinguis connexió a Internet i torna a provar de configurar-los"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Els missatges per satèl·lit no estan disponibles"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Els missatges per satèl·lit no estan disponibles en aquest país o regió"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Els missatges per satèl·lit no estan configurats"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Per enviar missatges per satèl·lit, defineix Missatges de Google com a aplicació de missatgeria predeterminada"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Els missatges per satèl·lit no estan disponibles"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Per comprovar si els missatges per satèl·lit estan disponibles en aquest país o regió, activa la configuració d\'ubicació"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Torna a configurar Desbloqueig amb empremta digital"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ja no es pot reconèixer."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ja no es poden reconèixer."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f3a020bbfce4..277d359e5fd0 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Aplikace bude moci zjišťovat vzájemnou pozici mezi ultra-širokopásmovými zařízeními v okolí"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interakce se zařízeními Wi-Fi v okolí"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Umožňuje aplikaci inzerovat, připojovat se a odhadovat relativní polohu zařízení Wi-Fi v okolí"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"zjišťování vzájemné pozice mezi zařízeními v okolí"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Aplikace bude moci zjišťovat vzájemnou pozici mezi zařízeními v okolí"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informace o preferované platební službě NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Umožňuje aplikaci získat informace o preferované platební službě NFC, například o registrovaných pomůckách a cíli směrování."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ovládání technologie NFC"</string>
@@ -2437,54 +2435,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Zapnout"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Zpět"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Čeká na vyřízení…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"K dispozici je funkce SOS přes satelit"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Pokud není k dispozici mobilní síť ani Wi-Fi, můžete na tísňovou linku poslat zprávu. Jako výchozí aplikace na odesílání zpráv musí být nastavené Google zprávy."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Funkce SOS přes satelit není podporována"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Funkce SOS přes satelit není na tomto zařízení podporována"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Funkce SOS přes satelit není nastavena"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Zkontrolujte připojení k internetu a zkuste nastavení provést znovu"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Funkce SOS přes satelit není k dispozici"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS před satelit není v této zemi nebo oblasti k dispozici"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Funkce SOS přes satelit není nastavena"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Pokud chcete odesílat zprávy přes satelit, nastavte Google zprávy jako výchozí aplikaci na odesílání zpráv"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Funkce SOS přes satelit není k dispozici"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Pokud chcete zjistit, zda je v této zemi nebo oblasti dostupná funkce SOS přes satelit, zapněte nastavení polohy"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Jsou k dispozici satelitní zprávy"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Pokud není k dispozici mobilní síť ani Wi-Fi, můžete odesílat zprávy přes satelit. Jako výchozí aplikace na odesílání zpráv musí být nastavené Google zprávy."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satelitní zprávy nejsou podporovány"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Satelitní zprávy nejsou na tomto zařízení podporovány"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satelitní zprávy nejsou nastaveny"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Zkontrolujte připojení k internetu a zkuste nastavení provést znovu"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satelitní zprávy nejsou k dispozici"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satelitní zprávy nejsou v této zemi nebo oblasti dostupné"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satelitní zprávy nejsou nastaveny"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Pokud chcete odesílat zprávy přes satelit, nastavte Google zprávy jako výchozí aplikaci na odesílání zpráv"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satelitní zprávy nejsou k dispozici"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Pokud chcete zjistit, zda jsou v této zemi nebo oblasti dostupné satelitní zprávy, zapněte nastavení polohy"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Opětovné nastavení odemknutí otiskem prstu"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> se nedaří rozpoznat."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> se nedaří rozpoznat."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b481682b0448..9db6076ee6fa 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Tillad, at appen fastlægger den relative position mellem UWB-enheder (Ultra-Wideband) i nærheden"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagere med Wi‑Fi-enheder i nærheden"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Giver appen tilladelse til at informere om, oprette forbindelse til og fastslå den relative placering af Wi‑Fi-enheder i nærheden"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"fastlægge relativ position mellem enheder i nærheden"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Tillad, at appen fastlægger den relative position mellem enheder i nærheden"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Foretrukne oplysninger vedrørende NFC-betalingstjeneste"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Tillader, at appen får foretrukne oplysninger vedrørende NFC-betalingstjeneste, f.eks. registrerede hjælpemidler og rutedestinationer."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"administrere Near Field Communication"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Aktivér"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Gå tilbage"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Afventer…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS-meldinger via satellit er nu tilgængelig"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Du kan sende beskeder til nødtjenester, hvis du ikke har forbindelse til et mobil- eller Wi-Fi-netværk. Google Beskeder skal være din standardapp til beskeder."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"SOS-meldinger via satellit understøttes ikke"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"SOS-meldinger via satellit understøttes ikke på denne enhed"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS-meldinger via satellit er ikke konfigureret"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Sørg for, at du har forbindelse til internettet, og prøv at konfigurere igen"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS-meldinger via satellit er ikke tilgængelig"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS-meldinger via satellit er ikke tilgængelig i dette land eller denne region"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS-meldinger via satellit er ikke konfigureret"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Hvis du vil sende beskeder via satellit, skal du angive Google Beskeder som din standardapp til beskeder"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS-meldinger via satellit er ikke tilgængelig"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Hvis du vil tjekke, om SOS-meldinger via satellit er tilgængelig i dette land eller denne region, skal du aktivere lokationsindstillinger"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Satellitbeskeder er tilgængelige"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Du kan sende beskeder via satellit, hvis du ikke har forbindelse til et mobil- eller Wi-Fi-netværk. Google Beskeder skal være din standardapp til beskeder."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satellitbeskeder understøttes ikke"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Satellitbeskeder understøttes ikke på denne enhed"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satellitbeskeder er ikke konfigureret"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Sørg for, at du har forbindelse til internettet, og prøv at konfigurere igen"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satellitbeskeder er ikke tilgængelige"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satellitbeskeder er ikke tilgængelige i dette land eller denne region"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satellitbeskeder er ikke konfigureret"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Hvis du vil sende beskeder via satellit, skal du angive Google Beskeder som din standardapp til beskeder"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satellitbeskeder er ikke tilgængelige"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Hvis du vil tjekke, om satellitbeskeder er tilgængelige i dette land eller denne region, skal du aktivere lokationsindstillinger"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurer fingeroplåsning igen"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> kan ikke længere genkendes."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> kan ikke længere genkendes."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 64afb5adffc4..9561b3f8a3c5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Ermöglicht der App, die relative Distanz zwischen Ultrabreitband-Geräten in der Nähe zu bestimmen"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Mit WLAN-Geräten in der Nähe interagieren"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Erlaubt der App, Inhalte an WLAN-Geräte in der Nähe zu senden, sich mit ihnen zu verbinden und ihre relative Position zu ermitteln"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"Relative Position zu Geräten in der Nähe bestimmen"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Ermöglicht es der App, die relative Position zu Geräten in der Nähe zu bestimmen"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informationen zum bevorzugten NFC-Zahlungsdienst"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Ermöglicht der App, Informationen zum bevorzugten NFC-Zahlungsdienst abzurufen, etwa registrierte Hilfsmittel oder das Routenziel."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"Nahfeldkommunikation steuern"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Aktivieren"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Zurück"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ausstehend…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"„Notruf über Satellit“ jetzt verfügbar"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Du kannst dem Rettungsdienst eine Nachricht senden, wenn kein Mobilfunknetz oder WLAN verfügbar ist. Dazu muss Google Messages als Standard-Messaging-App festgelegt sein."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"„Notruf über Satellit“ nicht unterstützt"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"„Notruf über Satellit“ wird auf diesem Gerät nicht unterstützt"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"„Notruf über Satellit“ nicht eingerichtet"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Vergewissere dich, dass du mit dem Internet verbunden bist, und versuche noch einmal, die Einrichtung durchzuführen"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"„Notruf über Satellit“ nicht verfügbar"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"„Notruf über Satellit“ ist in diesem Land oder in dieser Region nicht verfügbar"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"„Notruf über Satellit“ nicht eingerichtet"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Wenn du Nachrichten per Satellit senden möchtest, musst du Google Messages als Standard-Messaging-App festlegen"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"„Notruf über Satellit“ nicht verfügbar"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Wenn du wissen möchtest, ob „Notruf über Satellit“ in diesem Land oder dieser Region verfügbar ist, aktiviere die Standorteinstellungen"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"„Nachrichten per Satellit“ verfügbar"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Du kannst Nachrichten per Satellit senden, wenn kein Mobilfunknetz oder WLAN verfügbar ist. Dazu muss Google Messages als Standard-Messaging-App festgelegt sein."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"„Nachrichten per Satellit“ nicht unterstützt"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"„Nachrichten per Satellit“ wird auf diesem Gerät nicht unterstützt"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"„Nachrichten per Satellit“ nicht eingerichtet"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Vergewissere dich, dass du mit dem Internet verbunden bist, und versuche noch einmal, die Einrichtung durchzuführen"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"„Nachrichten per Satellit“ nicht verfügbar"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"„Nachrichten per Satellit“ ist in diesem Land oder dieser Region nicht verfügbar"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"„Nachrichten per Satellit“ nicht eingerichtet"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Wenn du Nachrichten per Satellit senden möchtest, musst du Google Messages als Standard-Messaging-App festlegen"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"„Nachrichten per Satellit“ nicht verfügbar"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Wenn du wissen möchtest, ob „Nachrichten per Satellit“ in diesem Land oder dieser Region verfügbar ist, aktiviere die Standorteinstellungen"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Entsperrung per Fingerabdruck neu einrichten"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> wird nicht mehr erkannt."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> und <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> werden nicht mehr erkannt."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 4ad85d97201a..551fe701e7dd 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Επιτρέψτε στην εφαρμογή να προσδιορίζει τη σχετική θέση μεταξύ κοντινών συσκευών Ultra-Wideband"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"αλληλεπίδραση με κοντινές συσκευές Wi‑Fi"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Επιτρέπει στην εφαρμογή: προβολή διαφημίσεων, σύνδεση και καθορισμό της σχετικής τοποθεσίας των κοντινών συσκευών Wi‑Fi"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"προσδιορ. σχετ. θέσης μεταξύ συσκ. σε κοντ. απόστ."</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Επιτρέψτε στην εφαρμογή να προσδιορίζει τη σχετική θέση μεταξύ συσκευών σε κοντινή απόσταση"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Πληροφορίες προτιμώμενης υπηρεσίας πληρωμών NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Επιτρέπει στην εφαρμογή να λαμβάνει πληροφορίες προτιμώμενης υπηρεσίας πληρωμής NFC, όπως καταχωρημένα βοηθήματα και προορισμό διαδρομής."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ελέγχει την Επικοινωνία κοντινού πεδίου (FNC)"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Ενεργοποίηση"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Επιστροφή"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Σε εκκρεμότητα…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Το δορυφορικό SOS είναι πλέον διαθέσιμο"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Μπορείτε να στέλνετε μηνύματα σε υπηρεσίες έκτακτης ανάγκης, εάν δεν υπάρχει δίκτυο κινητής τηλεφωνίας ή Wi-Fi. Το Google Messages πρέπει να είναι η προεπιλεγμένη εφαρμογή ανταλλαγής μηνυμάτων."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Το δορυφορικό SOS δεν υποστηρίζεται"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Το δορυφορικό SOS δεν υποστηρίζεται σε αυτή τη συσκευή"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Το δορυφορικό SOS δεν έχει ρυθμιστεί"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Βεβαιωθείτε ότι είστε συνδεδεμένοι στο διαδίκτυο και δοκιμάστε ξανά τη ρύθμιση"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Το δορυφορικό SOS δεν είναι διαθέσιμο"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Το δορυφορικό SOS δεν είναι διαθέσιμο σε αυτή τη χώρα ή την περιοχή"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Το δορυφορικό SOS δεν έχει ρυθμιστεί"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Για να ανταλλάζετε μηνύματα μέσω δορυφόρου, ορίστε το Google Messages ως την προεπιλεγμένη εφαρμογή ανταλλαγής μηνυμάτων"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Το δορυφορικό SOS δεν είναι διαθέσιμο"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Για να ελέγξετε αν το δορυφορικό SOS είναι διαθέσιμο σε αυτή τη χώρα ή την περιοχή, ενεργοποιήστε τις ρυθμίσεις τοποθεσίας"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου είναι διαθέσιμη"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Μπορείτε να ανταλλάζετε μηνύματα μέσω δορυφόρου, εάν δεν υπάρχει δίκτυο κινητής τηλεφωνίας ή Wi-Fi. Το Google Messages πρέπει να είναι η προεπιλεγμένη εφαρμογή ανταλλαγής μηνυμάτων."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου δεν υποστηρίζεται"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου δεν υποστηρίζεται σε αυτή τη συσκευή"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου δεν έχει ρυθμιστεί"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Βεβαιωθείτε ότι είστε συνδεδεμένοι στο διαδίκτυο και δοκιμάστε ξανά τη ρύθμιση"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου δεν είναι διαθέσιμη"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου δεν είναι διαθέσιμη σε αυτή τη χώρα ή την περιοχή"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου δεν έχει ρυθμιστεί"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Για να ανταλλάζετε μηνύματα μέσω δορυφόρου, ορίστε το Google Messages ως την προεπιλεγμένη εφαρμογή ανταλλαγής μηνυμάτων"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Η ανταλλαγή μηνυμάτων μέσω δορυφόρου δεν είναι διαθέσιμη"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Για να ελέγξετε αν η ανταλλαγή μηνυμάτων μέσω δορυφόρου είναι διαθέσιμη σε αυτή τη χώρα ή την περιοχή, ενεργοποιήστε τις ρυθμίσεις τοποθεσίας"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Επαναρρύθμιση λειτουργίας Ξεκλείδωμα με δακτυλικό αποτύπωμα"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Δεν είναι πλέον δυνατή η αναγνώριση του <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Δεν είναι πλέον δυνατή η αναγνώριση του <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> και του <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a82b567a087e..5cedb1fa6655 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Allow the app to determine relative position between nearby ultra-wideband devices"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interact with nearby Wi‑Fi devices"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Allows the app to advertise, connect and determine the relative position of nearby Wi‑Fi devices"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determine relative position between nearby devices"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Allow the app to determine relative position between nearby devices"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Preferred NFC payment service information"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Allows the app to get preferred NFC payment service information, such as registered aids and route destination."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"control Near-Field Communication"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index bf3b985ae6e8..4e728ff0f814 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Allow the app to determine relative position between nearby ultra-wideband devices"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interact with nearby Wi‑Fi devices"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Allows the app to advertise, connect and determine the relative position of nearby Wi‑Fi devices"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determine relative position between nearby devices"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Allow the app to determine relative position between nearby devices"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Preferred NFC payment service information"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Allows the app to get preferred NFC payment service information, such as registered aids and route destination."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"control Near-Field Communication"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 5c9c52148750..578e4795f2b4 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Allow the app to determine relative position between nearby ultra-wideband devices"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interact with nearby Wi‑Fi devices"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Allows the app to advertise, connect and determine the relative position of nearby Wi‑Fi devices"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determine relative position between nearby devices"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Allow the app to determine relative position between nearby devices"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Preferred NFC payment service information"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Allows the app to get preferred NFC payment service information, such as registered aids and route destination."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"control Near-Field Communication"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index ab6f6ce07c1d..da3c4c4c27eb 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permite que la app determine la posición relativa con dispositivos Ultra Wideband cercanos"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interactuar con dispositivos Wi-Fi cercanos"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permite que la app muestre anuncios, se conecte y determine la posición relativa de los dispositivos Wi-Fi cercanos"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determinar posición relativa entre disp. cercanos"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permite que la app determine la posición relativa con dispositivos cercanos"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Información sobre servicio de pago NFC preferido"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que la app reciba información del servicio de pago NFC preferido, como el servicio de asistencia registrado y el destino de la ruta."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlar la Transmisión de datos en proximidad"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 23e1ae635730..37bf70e9bbd1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permite que la aplicación determine la posición relativa de los dispositivos de banda ultraancha cercanos"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interactuar con dispositivos Wi-Fi cercanos"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permite a la aplicación emitir y conectarse a dispositivos Wi-Fi cercanos y determinar su posición relativa"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determinar posición relativa de dispositivos cercanos"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permite que la aplicación determine la posición relativa de los dispositivos cercanos"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Información sobre el servicio de pago por NFC preferido"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que la aplicación obtenga información sobre el servicio de pago por NFC preferido, como identificadores de aplicación registrados y destinos de rutas."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlar Comunicación de campo cercano (NFC)"</string>
@@ -1411,7 +1409,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB activa"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar depuración USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar la depuración por USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración por USB"</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string>
@@ -2436,54 +2434,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Activar"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Volver"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendiente..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS por satélite ya está disponible"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Puedes enviar mensajes a los servicios de emergencias si no hay una red móvil o Wi-Fi disponible. Mensajes de Google debe ser tu aplicación de mensajería predeterminada."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"No se admite SOS por satélite"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Este dispositivo no admite SOS por satélite"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS por satélite no está configurado"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Comprueba que tienes conexión a Internet e inténtalo de nuevo"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS por satélite no está disponible"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS por satélite no está disponible en este país o territorio"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS por satélite no configurado"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Para enviar mensajes por satélite, configura Mensajes de Google como tu aplicación de mensajería predeterminada"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS por satélite no está disponible"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Para comprobar si SOS por satélite está disponible en este país o territorio, activa los ajustes de ubicación"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Mensajes por satélite disponibles"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Puedes enviar mensajes por satélite si no hay una red móvil o Wi-Fi disponible. Mensajes de Google debe ser tu aplicación de mensajería predeterminada."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Mensajes por satélite no admitidos"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Este dispositivo no admite los mensajes por satélite"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Mensajes por satélite no configurados"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Comprueba que tienes conexión a Internet e inténtalo de nuevo"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Mensajes por satélite no disponibles"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Los mensajes por satélite no están disponibles en este país o territorio"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Mensajes por satélite no configurados"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Para enviar mensajes por satélite, configura Mensajes de Google como tu aplicación de mensajería predeterminada"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Mensajes por satélite no disponibles"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Para comprobar si los mensajes por satélite están disponibles en este país o territorio, activa los ajustes de ubicación"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configura Desbloqueo con huella digital de nuevo"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ya no puede reconocerse."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> y <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ya no pueden reconocerse."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index d22c93b30ac9..0d79e8aa0333 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Võimaldab rakendusel määrata lähedalasuvate ülilairibaühendust kasutavate seadmete suhtelise kauguse üksteisest"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Läheduses olevate WiFi-seadmetega suhtlemine"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Lubab rakendusel läheduses olevatele WiFi-seadmetele reklaamida, nendega ühenduse luua ja määrata nende suhteline asend"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"Määrata läheduses olevate seadmete suhtelise kauguse üksteisest."</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Võimaldab rakendusel määrata läheduses olevate seadmete suhtelise kauguse üksteisest"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Eelistatud NFC-makseteenuse teave"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Võimaldab rakendusel hankida eelistatud NFC-makseteenuse teavet (nt registreeritud abi ja marsruudi sihtkoht)."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"lähiväljaside juhtimine"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Lülita sisse"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Mine tagasi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ootel …"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Satelliit-SOS on nüüd saadaval"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Saate hädaabiteenustele sõnumi saata, kui mobiilside- või WiFi-võrku pole. Google Messages peab olema teie vaikesõnumsiderakendus."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satelliit-SOSi ei toetata"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"See seade ei toeta satelliit-SOSi"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satelliit-SOS pole seadistatud"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Veenduge, et teil oleks internetiühendus, ja proovige uuesti seadistada"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satelliit-SOS pole saadaval"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satelliit-SOS ei ole selles riigis või piirkonnas saadaval"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satelliit-SOSi pole seadistatud"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Satelliidi teel sõnumite saatmiseks määrake Google Messages oma sõnumside vaikerakenduseks"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satelliit-SOS pole saadaval"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Et kontrollida, kas satelliit-SOS on selles riigis või piirkonnas saadaval, lülitage sisse asukohaseaded"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Saadaval on satelliidipõhine sõnumside"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Kui mobiilside- või WiFi-võrku pole, saate sõnumeid saata satelliidi teel. Google Messages peab olema teie vaikesõnumsiderakendus."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satelliidipõhist sõnumsidet ei toetata"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"See seade ei toeta satelliidipõhist sõnumsidet"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satelliidipõhine sõnumside pole seadistatud"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Veenduge, et teil oleks internetiühendus, ja proovige uuesti seadistada"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satelliidipõhine sõnumside pole saadaval"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satelliidipõhine sõnumside ei ole selles riigis või piirkonnas saadaval"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satelliidipõhine sõnumside pole seadistatud"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Satelliidi teel sõnumite saatmiseks määrake Google Messages oma sõnumside vaikerakenduseks"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satelliidipõhine sõnumside pole saadaval"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Et kontrollida, kas satelliidipõhine sõnumside on selles riigis või piirkonnas saadaval, lülitage sisse asukohaseaded"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Seadistage sõrmejäljega avamine uuesti"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Sõrmejälge <xliff:g id="FINGERPRINT">%s</xliff:g> ei saa enam tuvastada."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Sõrmejälgi <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ei saa enam tuvastada."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 914dfb72c06e..b96f9eb97c21 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Banda ultrazabala darabilten inguruko gailuen arteko distantzia erlatiboa zehazteko baimena ematen dio aplikazioari"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"inguruko wifi-gailuekin interakzioan jardun"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Inguruko wifi-gailuetan iragartzeko, haiekin konektatzeko eta haien kokapena zehazteko baimena ematen dio aplikazioari"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"zehaztu inguruko gailuen arteko distantzia erlatiboa"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Inguruko gailuen arteko distantzia erlatiboa zehazteko baimena ematen dio aplikazioari"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"NFC bidezko ordainketa-zerbitzu lehenetsiari buruzko informazioa"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"NFC bidezko ordainketa-zerbitzu lehenetsiari buruzko informazioa jasotzeko baimena ematen dio aplikazioari, hala nola erregistratutako laguntzaileak eta ibilbidearen helmuga."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrolatu Near Field Communication komunikazioa"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Aktibatu"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Egin atzera"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Zain…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Satelite bidezko SOS komunikazioa erabilgarri dago orain"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Larrialdi-zerbitzuekin mezuak trukatu ahal izango dituzu sare mugikorrik edo wifi-sarerik ez badago. Google-ren Mezuak aplikazioak izan behar du mezularitza-aplikazio lehenetsia."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satelite bidezko SOS komunikazioa ez da bateragarria"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Satelite bidezko SOS komunikazioa ez da bateragarria gailu honekin"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satelite bidezko SOS komunikazioa ez dago konfiguratuta"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Ziurtatu Internetera konektatuta zaudela eta saiatu konfiguratzen berriro"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satelite bidezko SOS komunikazioa ez dago erabilgarri"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satelite bidezko SOS komunikazioa ez dago erabilgarri herrialde edo lurralde honetan"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satelite bidezko SOS komunikazioa ez dago konfiguratuta"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Satelite bidez mezuak trukatzeko, ezarri Google-ren Mezuak mezularitza-aplikazio lehenetsi gisa"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satelite bidezko SOS komunikazioa ez dago erabilgarri"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Herrialde edo lurralde honetan satelite bidezko SOS komunikazioa erabilgarri dagoen egiaztatzeko, aktibatu kokapen-ezarpenak"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Satelite bidezko mezularitza erabilgarri dago"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Satelite bidez trukatu ahal izango dituzu mezuak sare mugikorrik edo wifi-sarerik ez badago. Google-ren Mezuak aplikazioak izan behar du mezularitza-aplikazio lehenetsia."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satelite bidezko mezularitza ez da bateragarria"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Satelite bidezko mezularitza ez da bateragarria gailu honekin"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satelite bidezko mezularitza ez dago konfiguratuta"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Ziurtatu Internetera konektatuta zaudela eta saiatu konfiguratzen berriro"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satelite bidezko mezularitza ez dago erabilgarri"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satelite bidezko mezularitza ez dago erabilgarri herrialde edo lurralde honetan"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satelite bidezko mezularitza ez dago konfiguratuta"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Satelite bidez mezuak trukatzeko, ezarri Google-ren Mezuak mezularitza-aplikazio lehenetsi gisa"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satelite bidezko mezularitza ez dago erabilgarri"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Herrialde edo lurralde honetan satelite bidezko mezularitza erabilgarri dagoen egiaztatzeko, aktibatu kokapen-ezarpenak"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfiguratu berriro hatz-marka bidez desblokeatzeko eginbidea"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ez da ezagutzen jada."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> eta <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ez dira ezagutzen jada."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index c3e4b4680752..7627ff37d2bc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"به برنامه اجازه داده می‌شود موقعیت نسبی بین دستگاه‌های «فراپهن‌باند» اطراف را مشخص کند"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"‏برقراری تعامل با دستگاه‌های Wi-Fi اطراف"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"‏به برنامه اجازه می‌دهد در دستگاه‌های Wi-Fi اطراف تبلیغ کند، به آن‌ها متصل شود، و موقعیت نسبی آن‌ها را تشخیص دهد"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"تعیین موقعیت نسبی بین دستگاه‌های اطراف"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"به برنامه اجازه داده می‌شود موقعیت نسبی بین دستگاه‌های اطراف را تعیین کند"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"‏اطلاعات ترجیحی سرویس پرداخت NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"‏به برنامه اجازه می‌دهد اطلاعات ترجیحی سرویس پرداخت NFC، مانند کمک‌های ثبت‌شده و مقصد مسیر را دریافت کند."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"کنترل ارتباط راه نزدیک"</string>
@@ -918,7 +916,7 @@
<string name="phoneTypeCustom" msgid="5120365721260686814">"سفارشی"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"خانه"</string>
<string name="phoneTypeMobile" msgid="1178852541462086735">"تلفن همراه"</string>
- <string name="phoneTypeWork" msgid="6604967163358864607">"کاری"</string>
+ <string name="phoneTypeWork" msgid="6604967163358864607">"محل کار"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"نمابر محل کار"</string>
<string name="phoneTypeFaxHome" msgid="6678559953115904345">"نمابر خانه"</string>
<string name="phoneTypePager" msgid="576402072263522767">"پی‌جو"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"روشن کردن"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"برگشتن"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"درحال تعلیق…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"«درخواست کمک ماهواره‌ای» اکنون دردسترس است"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"‏اگر شبکه Wi-Fi یا تلفن همراه وجود ندارد، می‌توانید به خدمات اضطراری پیام ارسال کنید. «پیام‌نگار Google» باید برنامه پیام‌رسانی پیش‌فرض شما باشد."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"«درخواست کمک ماهواره‌ای» پشتیبانی نمی‌شود"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"«درخواست کمک ماهواره‌ای» در این دستگاه پشتیبانی نمی‌شود"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"«درخواست کمک ماهواره‌ای» راه‌اندازی نشده است"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"مطمئن شوید به اینترنت متصل هستید و دوباره راه‌اندازی را امتحان کنید"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"«درخواست کمک ماهواره‌ای» دردسترس نیست"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"«درخواست کمک ماهواره‌ای» در این کشور یا منطقه دردسترس نیست"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"درخواست کمک ماهواره‌ای راه‌اندازی نمی‌شود"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"‏برای ارسال پیام ازطریق ماهواره، «پیام‌نگار Google» را به‌عنوان برنامه پیام‌رسانی پیش‌فرض تنظیم کنید"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"«درخواست کمک ماهواره‌ای» دردسترس نیست"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"برای بررسی دردسترس بودن «درخواست کمک ماهواره‌ای» در این کشور یا منطقه، تنظیمات مکان را روشن کنید"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"پیام‌رسانی ماهواره‌ای دردسترس است"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"‏اگر شبکه تلفن همراه یا Wi-Fi وجود ندارد، می‌توانید ازطریق ماهواره پیام ارسال کنید. «پیام‌نگار Google» باید برنامه پیام‌رسانی پیش‌فرض شما باشد."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"پیام‌رسانی ماهواره‌ای پشتیبانی نمی‌شود"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"پیام‌رسانی ماهواره‌ای در این دستگاه پشتیبانی نمی‌شود"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"پیام‌رسانی ماهواره‌ای راه‌اندازی نمی‌شود"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"مطمئن شوید به اینترنت متصل هستید و دوباره راه‌اندازی را امتحان کنید"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"پیام‌رسانی ماهواره‌ای دردسترس نیست"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"پیام‌رسانی ماهواره‌ای در این کشور یا منطقه دردسترس نیست"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"پیام‌رسانی ماهواره‌ای راه‌اندازی نمی‌شود"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"‏برای ارسال پیام ازطریق ماهواره، «پیام‌نگار Google» را به‌عنوان برنامه پیام‌رسانی پیش‌فرض تنظیم کنید"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"پیام‌رسانی ماهواره‌ای دردسترس نیست"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"برای بررسی دردسترس بودن پیام‌رسانی ماهواره‌ای در این کشور یا منطقه، تنظیمات مکان را فعال کنید"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"راه‌اندازی مجدد «قفل‌گشایی با اثر انگشت»"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"‫<xliff:g id="FINGERPRINT">%s</xliff:g> دیگر قابل‌شناسایی نیست."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"‫<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> و <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> دیگر قابل‌شناسایی نیستند."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index fb7c4fed3f47..78fb2a07f756 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Sallii sovelluksen määrittää UVB-taajuutta käyttävien laitteiden sijainnin suhteessa toisiinsa"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"käyttää lähellä olevia Wi-Fi-laitteita"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Sallii sovelluksen ilmoittaa ja määrittää lähellä olevien Wi-Fi-laitteiden suhteellisen sijainnin sekä yhdistää niihin"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"määrittää laitteiden suhteellisen sijainnin"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Sallii sovelluksen määrittää lähellä olevien laitteiden sijainnin suhteessa toisiinsa"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Ensisijaiset NFC-maksupalvelutiedot"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Sallii sovelluksen noutaa tietoja rekisteröidyistä sovellustunnuksista, maksureitin kohteesta ja muita ensisijaisia NFC-maksupalvelutietoja."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"hallitse Near Field Communication -tunnistusta"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Laita päälle"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Takaisin"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Odottaa…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Satellite SOS on nyt käytettävissä"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Voit lähettää viestin hätäkeskukseen, jos sinulla ei ole mobiili‑ tai Wi-Fi-verkkoyhteyttä. Google Messages täytyy valita oletusviestisovellukseksi."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satellite SOS ei tueta"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Satellite SOS ei tueta tällä laitteella"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satellite SOS ei ole otettu käyttöön"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Varmista, että internetyhteys on muodostettu, ja yritä käyttöönottoa uudelleen"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satellite SOS ei ole saatavilla"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satellite SOS ei ole saatavilla tällä alueella"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satellite SOS ei ole otettu käyttöön"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Jos haluat lähettää viestejä satelliitin kautta, aseta Google Messages oletusviestisovellukseksi"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satellite SOS ei ole saatavilla"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Voit tarkistaa, onko Satellite SOS saatavilla tällä alueella, laittamalla sijaintiasetukset päälle"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Satelliittiviestintä saatavilla"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Voit lähettää viestin satelliitin kautta, jos sinulla ei ole mobiili‑ tai Wi-Fi-verkkoyhteyttä. Google Messages täytyy valita oletusviestisovellukseksi."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satelliittiviestintää ei tueta"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Satelliittiviestejä ei tueta tällä laitteella"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satelliittiviestintää ei ole otettu käyttöön"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Varmista, että internetyhteys on muodostettu, ja yritä käyttöönottoa uudelleen"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satelliittiviestintä ei ole käytettävissä"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satelliittiviestintä ei ole saatavilla tällä alueella"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satelliittiviestintää ei ole otettu käyttöön"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Jos haluat lähettää viestejä satelliitin kautta, aseta Google Messages oletusviestisovellukseksi"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satelliittiviestintä ei ole käytettävissä"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Voit tarkistaa, onko satelliittiviestit saatavilla tällä alueella, laittamalla sijaintiasetukset päälle"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ota sormenjälkiavaus uudelleen käyttöön"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ei enää ole tunnistettavissa."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> eivät enää ole tunnistettavissa."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 18ef10995e90..163d70d49230 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Autorisez l\'appli à déterminer la position relative entre des appareils à bande ultralarge à proximité"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagir avec les appareils Wi-Fi à proximité"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permet à l\'appli de diffuser des annonces, de se connecter et de déterminer la position relative des appareils Wi-Fi à proximité"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"Dét. position relative entre appareils à proximité"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Autorisez l\'appli à déterminer la position relative entre des appareils à proximité"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Information sur le service préféré de paiement CCP"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permet à l\'appli d\'obtenir de l\'information sur le service préféré de paiement CCP comme les aides enregistrées et la route de destination."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"gérer la communication en champ proche"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index bd064d1dc61e..75b8e3125da0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Autoriser l\'appli à déterminer la position relative entre des appareils ultra-wideband à proximité"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagir avec les appareils Wi-Fi à proximité"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permet à l\'appli de déterminer la position approximative des appareils Wi‑Fi à proximité, de les afficher et de s\'y connecter"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"déterminer l\'emplacement relatif entre des appareils à proximité"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Autorisez l\'appli à déterminer l\'emplacement relatif entre des appareils à proximité"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informations sur le service de paiement NFC préféré"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permet à l\'application d\'obtenir des informations sur le service de paiement NFC préféré, y compris les ID d\'applications et les destinations de routage enregistrés."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"contrôler la communication en champ proche"</string>
@@ -2436,54 +2434,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Activer"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Retour"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS par satellite est maintenant disponible"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Vous pouvez envoyer des messages aux services d\'urgence s\'il n\'y a pas de réseau mobile ou Wi-Fi. Google Messages doit être votre application de chat par défaut."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"SOS par satellite n\'est pas disponible"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"SOS par satellite n\'est pas disponible sur cet appareil"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS par satellite n\'est pas configuré"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Vérifiez votre connexion à Internet, puis essayez à nouveau de lancer la configuration."</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS par satellite n\'est pas disponible"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS par satellite n\'est pas disponible dans ce pays ou cette région"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS par satellite non configuré"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Pour envoyer des messages par satellite, définissez Google Messages comme application de chat par défaut"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS par satellite n\'est pas disponible"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Pour savoir si SOS par satellite est disponible dans ce pays ou cette région, activez les paramètres de localisation"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Messagerie par satellite disponible"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Vous pouvez envoyer des messages par satellite s\'il n\'y a pas de réseau mobile ou Wi-Fi. Google Messages doit être votre application de chat par défaut."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Messagerie par satellite non disponible"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"La messagerie par satellite n\'est pas disponible sur cet appareil"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Messagerie par satellite non configurée"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Vérifiez votre connexion à Internet, puis essayez à nouveau de lancer la configuration."</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Messagerie par satellite non disponible"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"La messagerie par satellite n\'est pas disponible dans ce pays ou cette région"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Messagerie par satellite non configurée"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Pour envoyer des messages par satellite, définissez Google Messages comme application de chat par défaut"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Messagerie par satellite non disponible"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Pour savoir si la messagerie par satellite est disponible dans ce pays ou cette région, activez les paramètres de localisation"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Reconfigurer le déverrouillage par empreinte digitale"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ne peut plus être reconnue."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> et <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ne peuvent plus être reconnues."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 292a952b1d46..70a7ec9c7a19 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permite que a aplicación determine a posición relativa entre os dispositivos próximos que usen banda ultralarga"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interactuar con dispositivos wifi próximos"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permítelle á aplicación enviar anuncios e conectarse a dispositivos wifi próximos, e determinar a súa posición relativa"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"fixar a posición relativa entre disp. próximos"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permite que a aplicación determine a posición relativa entre os dispositivos próximos"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Información do servizo de pagos de NFC preferido"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que a aplicación obteña información do servizo de pagos de NFC preferido, como as axudas rexistradas e o destino da ruta."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlar Near Field Communication"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Activar"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Volver"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS por satélite xa está dispoñible"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Podes enviar mensaxes aos servizos de emerxencia se non tes conexión con ningunha rede wifi nin de telefonía móbil. Debes ter definida Mensaxes de Google como aplicación predeterminada de mensaxaría."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Non se admite SOS por satélite"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Non se admite SOS por satélite neste dispositivo"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS por satélite non se configurou"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Asegúrate de ter conexión a Internet e tenta volver facer a configuración"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS por satélite non está dispoñible"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS por satélite non está dispoñible neste país ou rexión"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS por satélite non se configurou"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Para intercambiar mensaxes por satélite, cómpre establecer Mensaxes de Google como aplicación de mensaxaría predeterminada"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS por satélite non está dispoñible"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Para comprobar se está dispoñible SOS por satélite neste país ou rexión, activa a configuración de localización"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Mensaxaría por satélite dispoñible"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Podes intercambiar mensaxes por satélite se non tes conexión con ningunha rede wifi nin de telefonía móbil. Debes ter definida Mensaxes de Google como aplicación predeterminada de mensaxaría."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Mensaxaría por satélite non admitida"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Non se admite a mensaxaría por satélite neste dispositivo"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Mensaxaría por satélite non configurada"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Asegúrate de ter conexión a Internet e tenta volver facer a configuración"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Mensaxaría por satélite non dispoñible"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"A mensaxaría por satélite non está dispoñible neste país ou rexión"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Mensaxaría por satélite non configurada"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Para intercambiar mensaxes por satélite, cómpre establecer Mensaxes de Google como aplicación de mensaxaría predeterminada"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Mensaxaría por satélite non dispoñible"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Para ver se está dispoñible a mensaxaría por satélite neste país ou rexión, activa a configuración de localización"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configura de novo o desbloqueo dactilar"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> xa non se recoñece."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> xa non se recoñecen."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 70454a307791..1535e4f5d463 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ઍપને નજીકના અલ્ટ્રા-વાઇડબૅન્ડ ડિવાઇસની વચ્ચેનું સંબંધિત અંતર નક્કી કરવાની મંજૂરી આપો"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"નજીકના વાઇ-ફાઇ ડિવાઇસ સાથે ક્રિયાપ્રતિક્રિયા કરો"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"ઍપને નજીકના વાઇ-ફાઇ ડિવાઇસની માહિતી બતાવવાની, તેની સાથે કનેક્ટ કરવાની અને તેની સંબંધિત સ્થિતિ નક્કી કરવાની મંજૂરી આપો"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ડિવાઇસની વચ્ચેનું સાપેક્ષ અંતર નક્કી કરો"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ઍપને નજીકના ડિવાઇસની વચ્ચેનું સાપેક્ષ અંતર નક્કી કરવાની મંજૂરી આપો"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"પસંદગીની NFC ચુકવણીની સેવા વિશે માહિતી"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"આ મંજૂરીને આપવાથી, ઍપ તમારી પસંદગીની NFC ચુકવણીની સેવા વિશે માહિતી મેળવી શકે છે, જેમ કે રજિસ્ટર થયેલી સહાય અને નિર્ધારિત સ્થાન."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"નિઅર ફીલ્ડ કમ્યુનિકેશન નિયંત્રિત કરો"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"ચાલુ કરો"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"પાછા જાઓ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"બાકી..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"ઇમર્જન્સી સૅટલાઇટ સહાય હવે ઉપલબ્ધ છે"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"જો મોબાઇલ કે વાઇ-ફાઇ નેટવર્ક ન હોય, તો તમે ઇમર્જન્સી સર્વિસને મેસેજ કરી શકો છો. Google Messages તમારી ડિફૉલ્ટ મેસેજિંગ ઍપ હોવી આવશ્યક છે."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"ઇમર્જન્સી સૅટલાઇટ સહાયને સપોર્ટ કરવામાં આવતો નથી"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"આ ડિવાઇસ પર ઇમર્જન્સી સૅટલાઇટ સહાયને સપોર્ટ કરવામાં આવતો નથી"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"ઇમર્જન્સી સૅટલાઇટ સહાયનું સેટઅપ કર્યું નથી"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"તમે ઇન્ટરનેટથી કનેક્ટેડ હોવાની ખાતરી કરો અને ફરી સેટઅપ કરવાનો પ્રયાસ કરો"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"ઇમર્જન્સી સૅટલાઇટ સહાય ઉપલબ્ધ નથી"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"આ દેશ કે પ્રદેશમાં ઇમર્જન્સી સૅટલાઇટ સહાય ઉપલબ્ધ નથી"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"ઇમર્જન્સી સૅટલાઇટ સહાયનું સેટઅપ કરેલું નથી"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"સૅટલાઇટ દ્વારા મેસેજ મોકલવા માટે, Google Messagesને તમારી ડિફૉલ્ટ મેસેજિંગ ઍપ તરીકે સેટ કરો"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"ઇમર્જન્સી સૅટલાઇટ સહાય ઉપલબ્ધ નથી"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"આ દેશ કે પ્રદેશમાં ઇમર્જન્સી સૅટલાઇટ સહાય ઉપલબ્ધ છે કે કેમ તે ચેક કરવા માટે, લોકેશન સેટિંગ ચાલુ કરો"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"સૅટલાઇટ મેસેજિંગ ઉપલબ્ધ છે"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"જો કોઈ મોબાઇલ કે વાઇ-ફાઇ નેટવર્ક ઉપલબ્ધ ન હોય, તો તમે સૅટલાઇટ દ્વારા મેસેજ મોકલી શકો છો. Google Messages તમારી ડિફૉલ્ટ મેસેજિંગ ઍપ હોવી આવશ્યક છે."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"સૅટલાઇટ મેસેજિંગને સપોર્ટ કરવામાં આવતો નથી"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"આ ડિવાઇસ પર સૅટલાઇટ મેસેજિંગને સપોર્ટ કરવામાં આવતો નથી"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"સૅટલાઇટ મેસેજિંગનું સેટઅપ કર્યું નથી"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"તમે ઇન્ટરનેટથી કનેક્ટેડ હોવાની ખાતરી કરો અને ફરી સેટઅપ કરવાનો પ્રયાસ કરો"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"સૅટલાઇટ મેસેજિંગ ઉપલબ્ધ નથી"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"આ દેશ કે પ્રદેશમાં સૅટલાઇટ મેસેજિંગ ઉપલબ્ધ નથી"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"સૅટલાઇટ મેસેજિંગનું સેટઅપ કર્યું નથી"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"સૅટલાઇટ દ્વારા મેસેજ મોકલવા માટે, Google Messagesને તમારી ડિફૉલ્ટ મેસેજિંગ ઍપ તરીકે સેટ કરો"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"સૅટલાઇટ મેસેજિંગ ઉપલબ્ધ નથી"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"આ દેશ કે પ્રદેશમાં સૅટલાઇટ મેસેજિંગ ઉપલબ્ધ છે કે કેમ તે ચેક કરવા માટે, લોકેશન સેટિંગ ચાલુ કરો"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ફિંગરપ્રિન્ટ અનલૉક સુવિધાનું ફરી સેટઅપ કરો"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"હવે <xliff:g id="FINGERPRINT">%s</xliff:g> ઓળખી શકાતી નથી."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"હવે <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> અને <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ઓળખી શકાતી નથી."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5422f1befc40..c5825fe097db 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -322,7 +322,7 @@
<string name="permgrouplab_location" msgid="1858277002233964394">"जगह की जानकारी"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"इस डिवाइस की जगह तक पहुंचने दें"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"कैलेंडर"</string>
- <string name="permgroupdesc_calendar" msgid="6762751063361489379">"अपने कैलेंडर को ऐक्सेस करें"</string>
+ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"आपके कैलेंडर को ऐक्सेस करने की अनुमति"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"मैसेज (एसएमएस)"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"मैसेज (एसएमएस) भेजें और देखें"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"फ़ाइल"</string>
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ऐप्लिकेशन को आस-पास मौजूद Ultra-Wideband डिवाइसों के बीच की दूरी का पता लगाने की अनुमति दें"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"आस-पास मौजूद वाई-फ़ाई डिवाइसों से इंटरैक्ट करें"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"इससे, ऐप्लिकेशन आस-पास मौजूद वाई-फ़ाई डिवाइसों की जानकारी दिखा पाएगा, उनसे कनेक्ट कर पाएगा, और उनकी दूरी पता लगा पाएगा"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"आस-पास मौजूद डिवाइसों के बीच की दूरी का पता लगाएं"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ऐप्लिकेशन को, आस-पास मौजूद डिवाइसों के बीच की दूरी का पता लगाने की अनुमति दें"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"NFC का इस्तेमाल करने वाली पैसे चुकाने की पसंदीदा सेवा की जानकारी"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"अगर ऐप्लिकेशन को अनुमति दी जाती है, तो वह पैसे चुकाने की आपकी उस पसंदीदा सेवा के बारे में जानकारी पा सकता है जो NFC का इस्तेमाल करती है. इसमें रजिस्टर किए गए डिवाइस और उनके आउटपुट के रूट जैसी जानकारी शामिल होती है."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"नियर फ़ील्‍ड कम्‍यूनिकेशन नियंत्रित करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0594788fa9ce..954f4cb1842c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Dopušta aplikaciji da odredi približni položaj između uređaja u blizini koji upotrebljavaju ultraširokopojasno povezivanje"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interakcija s Wi-Fi uređajima u blizini"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Aplikaciji omogućuje oglašavanje, povezivanje i određivanje približnog položaja Wi-Fi uređaja u blizini"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"određivanje rel. položaja između uređaja u blizini"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Dopustite aplikaciji da odredi relativni položaj između uređaja u blizini"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informacije o preferiranoj usluzi plaćanja NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Omogućuje aplikaciji primanje informacija o preferiranoj usluzi plaćanja NFC kao što su registrirana pomagala i odredište."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"upravljanje beskontaktnom komunikacijom (NFC)"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 8adb234830aa..58a5cbdbc2ab 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Az alkalmazás meghatározhatja a közeli, ultraszélessávú eszközök közötti relatív pozíciót"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"műveletek végrehajtása a közeli Wi‑Fi-eszközökkel"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Engedélyezi az alkalmazás számára, hogy közzétegye és meghatározza a közeli Wi-Fi-eszközök viszonylagos helyzetét, és csatlakozzon hozzájuk."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"közeli eszközök közötti relatív pozíció meghatározása"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Az alkalmazás meghatározhatja a közeli eszközök közötti relatív pozíciót"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Preferált NFC fizetési szolgáltatási információk"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Lehetővé teszi az alkalmazás számára preferált NFC fizetési szolgáltatási információk (pl. regisztrált alkalmazásazonosítók és útvonali cél) lekérését."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"NFC technológia vezérlése"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Bekapcsolás"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Vissza"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Függőben…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Mostantól rendelkezésre áll a műholdas SOS"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Mobil- vagy Wi-Fi-hálózat nélkül is küldhet üzenetet a segélyhívó szolgálatnak. Ehhez a Google Messagest kell beállítani alapértelmezett üzenetküldő almazásként."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Nem támogatott a műholdas SOS"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Ezen az eszközön nem támogatott a műholdas SOS."</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Nincs beállítva a műholdas SOS"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Ellenőrizze, hogy csatlakozik-e az internethez, majd próbálja újra a beállítást."</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Nem áll rendelkezésre a műholdas SOS"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Ebben az országban vagy régióban nem áll rendelkezésre a műholdas SOS."</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Nincs beállítva a műholdas SOS"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Műholdas üzenetváltáshoz állítsa be a Google Messagest alapértelmezett üzenetküldő alkalmazásként."</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Nem áll rendelkezésre a műholdas SOS"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Ha szeretné ellenőrizni, hogy rendelkezésre áll-e a műholdas SOS ebben az országban vagy régióban, kapcsolja be a helybeállításokat."</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Rendelkezésre áll a műholdas üzenetváltás"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Műholdon keresztül is küldhet üzenetet, ha nincs mobil- vagy Wi-Fi-hálózat. Ehhez a Google Messagest kell beállítani alapértelmezett üzenetküldő almazásként."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Nem támogatott a műholdas üzenetváltás"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Ezen az eszközön nem támogatott a műholdas üzenetváltás."</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Nincs beállítva a műholdas üzenetváltás"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Ellenőrizze, hogy csatlakozik-e az internethez, majd próbálja újra a beállítást."</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Nem áll rendelkezésre a műholdas üzenetváltás"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Ebben az országban vagy régióban nem áll rendelkezésre a műholdas üzenetváltás."</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Nincs beállítva a műholdas üzenetváltás"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Műholdas üzenetváltáshoz állítsa be a Google Messagest alapértelmezett üzenetküldő alkalmazásként."</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Nem áll rendelkezésre a műholdas üzenetváltás"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Ha szeretné ellenőrizni, hogy rendelkezésre áll-e a műholdas üzenetváltás ebben az országban vagy régióban, kapcsolja be a helybeállításokat."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"A Feloldás ujjlenyomattal funkció újbóli beállítása"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"A következő már nem felismerhető: <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"A következők már nem felismerhetők: <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> és <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 4a16d2f37194..f457c42d9cd4 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Թույլատրել հավելվածին որոշել գերլայնաշերտ կապի տեխնոլոգիան աջակցող մոտակա սարքերի միջև հարաբերական դիրքավորումը"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"փոխներգործել մոտակա Wi‑Fi սարքերի հետ"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Թույլ է տալիս հավելվածին տվյալներ փոխանցել մոտակա Wi‑Fi սարքերին, միանալ դրանց և որոշել դրանց մոտավոր դիրքը։"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"որոշել մոտակա սարքերի միջև հարաբերական դիրքավորումը"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Թույլատրել հավելվածին որոշել մոտակա սարքերի միջև հարաբերական դիրքավորումը"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Տեղեկություններ NFC վճարային ծառայության մասին"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Թույլ է տալիս հավելվածին ստանալ նախընտրելի NFC վճարային ծառայության մասին տեղեկություններ (օր․՝ գրանցված լրացուցիչ սարքերի և երթուղու նպատակակետի մասին տվյալներ)։"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"վերահսկել Մոտ Տարածությամբ Հաղորդակցումը"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Միացնել"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Հետ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Առկախ է…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Satellite SOS-ը այժմ հասանելի է"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Դուք կարող եք հաղորդագրություն գրել արտակարգ իրավիճակների ծառայություններին բջջային կամ Wi-Fi ցանցի բացակայության դեպքում։ Google Messages-ը պետք է լինի հաղորդագրման ձեր կանխադրված հավելվածը։"</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satellite SOS-ը չի աջակցվում"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Satellite SOS-ը այս սարքում չի աջակցվում"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satellite SOS-ը կարգավորված չէ"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Համոզվեք, որ միացած եք ինտերնետին, և նորից փորձեք կարգավորել"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satellite SOS-ը հասանելի չէ"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satellite SOS-ը հասանելի չէ այս երկրում կամ տարածաշրջանում"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satellite SOS-ը կարգավորված չէ"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Արբանյակային կապով հաղորդագրություններ ուղարկելու համար Google Messages-ը դարձրեք հաղորդագրման ձեր կանխադրված հավելվածը"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satellite SOS-ը հասանելի չէ"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Միացրեք տեղադրության կարգավորումները, որպեսզի ստուգեք՝ արդյոք Satellite SOS գործառույթը հասանելի է այս երկրում կամ տարածաշրջանում"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Արբանյակային հաղորդագրումը հասանելի է"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Բջջային կամ Wi-Fi ցանցի բացակայության դեպքում դուք կարող եք հաղորդագրություններ ուղարկել արբանյակային կապով։ Google Messages-ը պետք է լինի հաղորդագրման ձեր կանխադրված հավելվածը։"</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Արբանյակային հաղորդագրումը չի աջակցվում"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Արբանյակային հաղորդագրումն այս սարքում չի աջակցվում"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Արբանյակային հաղորդագրումը կարգավորված չէ"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Համոզվեք, որ միացած եք ինտերնետին, և նորից փորձեք կարգավորել"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Արբանյակային հաղորդագրումը հասանելի չէ"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Արբանյակային հաղորդագրումը հասանելի չէ այս երկրում կամ տարածաշրջանում"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Արբանյակային հաղորդագրումը կարգավորված չէ"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Արբանյակային կապով հաղորդագրություններ ուղարկելու համար Google Messages-ը դարձրեք հաղորդագրման ձեր կանխադրված հավելվածը"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Արբանյակային հաղորդագրումը հասանելի չէ"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Միացրեք տեղադրության կարգավորումները, որպեսզի ստուգեք՝ արդյոք արբանյակային հաղորդագրումը հասանելի է այս երկրում կամ տարածաշրջանում"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Նորից կարգավորեք մատնահետքով ապակողպումը"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> մատնահետքն այլևս չի կարող ճանաչվել։"</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> և <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> մատնահետքերն այլևս չեն կարող ճանաչվել։"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e90137fd761f..88764c4112b8 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Mengizinkan aplikasi menentukan posisi relatif antar-perangkat Ultra-Wideband di sekitar"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"berinteraksi dengan perangkat Wi-Fi di sekitar"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Mengizinkan aplikasi menampilkan, menghubungkan, dan menentukan posisi relatif perangkat Wi-Fi di sekitar"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"menentukan posisi relatif antar-perangkat di sekitar"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Izinkan aplikasi menentukan posisi relatif antar-perangkat di sekitar"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informasi Layanan Pembayaran NFC Pilihan"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Mengizinkan aplikasi untuk mendapatkan informasi layanan pembayaran NFC pilihan seperti bantuan terdaftar dan tujuan rute."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrol NFC"</string>
@@ -1397,7 +1395,7 @@
<string name="no_permissions" msgid="5729199278862516390">"Tidak perlu izin"</string>
<string name="perm_costs_money" msgid="749054595022779685">"ini mungkin tidak gratis"</string>
<string name="dlg_ok" msgid="5103447663504839312">"Oke"</string>
- <string name="usb_charging_notification_title" msgid="1674124518282666955">"Daya perangkat sedang diisi via USB"</string>
+ <string name="usb_charging_notification_title" msgid="1674124518282666955">"Mengisi daya perangkat ini via USB"</string>
<string name="usb_supplying_notification_title" msgid="5378546632408101811">"Mengisi daya perangkat yang terhubung via USB"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"Transfer file USB diaktifkan"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"PTP via USB diaktifkan"</string>
@@ -1763,7 +1761,7 @@
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Alat bantu dengar"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> diaktifkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dinonaktifkan."</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Lepaskan tombol volume. Untuk mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tekan dan tahan kedua tombol volume lagi selama 3 detik."</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Lepaskan tombol volume. Untuk mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tekan kedua tombol volume lagi selama 3 detik."</string>
<string name="accessibility_button_prompt_text" msgid="6105393217162198616">"Pilih fitur"</string>
<string name="accessibility_gesture_prompt_text" msgid="6452246951969541792">"Pilih fitur"</string>
<string name="accessibility_gesture_3finger_prompt_text" msgid="77745752309056152">"Pilih fitur"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Aktifkan"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Kembali"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Tertunda..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS via Satelit kini tersedia"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Anda dapat mengirim pesan ke layanan darurat jika tidak ada jaringan seluler atau Wi-Fi. Google Message harus menjadi aplikasi pesan default Anda."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"SOS via Satelit tidak didukung"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"SOS via Satelit tidak didukung di perangkat ini"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS via Satelit tidak disiapkan"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Pastikan perangkat Anda terhubung ke internet, lalu coba siapkan lagi"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS via Satelit tidak tersedia"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS via Satelit tidak tersedia di negara atau wilayah ini"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS via Satelit tidak disiapkan"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Untuk mengirim pesan melalui satelit, setel Google Message sebagai aplikasi pesan default"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS via Satelit tidak tersedia"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Untuk memeriksa apakah SOS via Satelit tersedia di negara atau wilayah ini, aktifkan setelan lokasi"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Fitur pesan satelit tersedia"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Anda dapat mengirim pesan melalui satelit jika tidak ada jaringan seluler atau Wi-Fi. Google Message harus menjadi aplikasi pesan default Anda."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Fitur pesan satelit tidak didukung"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Fitur pesan satelit tidak didukung di perangkat ini"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Fitur pesan satelit tidak disiapkan"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Pastikan perangkat Anda terhubung ke internet, lalu coba siapkan lagi"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Fitur pesan satelit tidak tersedia"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Fitur pesan satelit tidak tersedia di negara atau wilayah ini"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Fitur pesan satelit tidak disiapkan"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Untuk mengirim pesan melalui satelit, setel Google Message sebagai aplikasi pesan default"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Fitur pesan satelit tidak tersedia"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Untuk memeriksa apakah fitur pesan satelit tersedia di negara atau wilayah ini, aktifkan setelan lokasi"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Siapkan Buka dengan Sidik Jari lagi"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> tidak dapat dikenali lagi."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dan <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> tidak dapat dikenali lagi."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 9ca5731ad1eb..8e92ed1532c1 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Leyfa forritinu að ákvarða fjarlægð milli nálægra tækja með ofurbreiðband"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"eiga í samskiptum við nálæg WiFi-tæki"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Leyfir forritinu að auglýsa, tengja og áætla staðsetningu nálægra WiFi-tækja"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"greina áætlaða fjarlægð á milli nálægra tækja"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Leyfðu forritinu að greina áætlaða fjarlægð á milli nálægra tækja"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Upplýsingar um valda NFC-greiðsluþjónustu"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Gerir forritinu kleift að fá valda NFC-greiðsluþjónustu, svo sem skráða aðstoð og áfangastað leiðar."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"stjórna nándarsamskiptum (NFC)"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ac0e4580b7a0..49f1f21131e2 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Consenti all\'app di stabilire la posizione relativa tra dispositivi a banda ultralarga nelle vicinanze"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Interazione con dispositivi Wi-Fi vicini"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Consente all\'app di trasmettere annunci e connettersi a dispositivi Wi‑Fi vicini e di stabilirne la posizione relativa."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"stabilire la posizione relativa tra dispositivi nelle vicinanze"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Consenti all\'app di stabilire la posizione relativa tra dispositivi nelle vicinanze"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informazioni del servizio di pagamento NFC preferito"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Consente all\'app di recuperare informazioni del servizio di pagamento NFC preferito, quali destinazione della route e identificatori applicazione registrati."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controllo Near Field Communication"</string>
@@ -2436,54 +2434,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Attiva"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Indietro"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"In attesa…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS satellitare è disponibile"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Puoi inviare messaggi ai servizi di emergenza se non disponi di una rete mobile o Wi-Fi. Google Messaggi deve essere l\'app di messaggistica predefinita."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"SOS satellitare non supportato"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"SOS satellitare non è supportato su questo dispositivo"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS satellitare non configurato"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Assicurati di avere una connessione a internet attiva e prova a ripetere la configurazione"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS satellitare non disponibile"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS satellitare non è disponibile in questo paese o in questa regione"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS satellitare non configurato"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Per inviare messaggi via satellite, imposta Google Messaggi come app di messaggistica predefinita"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS satellitare non disponibile"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Per verificare se SOS satellitare è disponibile in questo paese o in questa regione, attiva le impostazioni di localizzazione"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Messaggi via satellite disponibili"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Puoi inviare messaggi via satellite se non disponi di una rete mobile o Wi-Fi. Google Messaggi deve essere l\'app di messaggistica predefinita."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Messaggi via satellite non supportati"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"I messaggi via satellite non sono supportati su questo dispositivo"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Messaggi via satellite non configurati"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Assicurati di avere una connessione a internet attiva e prova a ripetere la configurazione"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Messaggi via satellite non disponibili"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"I messaggi via satellite non sono disponibili in questo paese o in questa regione"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Messaggi via satellite non configurati"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Per inviare messaggi via satellite, imposta Google Messaggi come app di messaggistica predefinita"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Messaggi via satellite non disponibili"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Per verificare se i messaggi via satellite sono disponibili in questo paese o in questa regione, attiva le impostazioni di localizzazione"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Riconfigura lo Sblocco con l\'Impronta"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> non può più essere riconosciuto."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> non possono più essere riconosciuti."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 386f5318f53a..0e8f472cb107 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"‏האפליקציה תזהה את המיקום היחסי בין מכשירים קרובים שמשדרים בטכנולוגיית Ultra Wideband ‏(UWB)"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"‏אינטראקציה עם מכשירי Wi-Fi בקרבת מקום"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"‏האפליקציה תוכל לפרסם במכשירי Wi-Fi בקרבת מקום, להתחבר אליהם ולהעריך את המיקום היחסי שלהם"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"זיהוי המיקום היחסי בין מכשירים קרובים"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"האפליקציה תזהה את המיקום היחסי בין מכשירים קרובים"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"‏פרטים על שירות תשלום מועדף ב-NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"‏מאפשרת לאפליקציה לקבל פרטים על שירות תשלום מועדף ב-NFC, כמו עזרים רשומים ויעד של נתיב."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"שליטה בתקשורת מטווח קצר"</string>
@@ -1411,7 +1409,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"המכשיר זיהה התקן אודיו אנלוגי"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ההתקן שחיברת לא תואם לטלפון הזה. יש להקיש לקבלת מידע נוסף."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"‏ניפוי באגים ב-USB מחובר"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"‏יש להקיש כדי לכבות את ניפוי הבאגים ב-USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"‏צריך להקיש כדי להשבית את ניפוי הבאגים ב-USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"‏יש ללחוץ על ההתראה כדי להשבית ניפוי באגים ב-USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ניפוי הבאגים האלחוטי מחובר"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"יש להקיש כדי להשבית ניפוי באגים אלחוטי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 339144611afd..6eabd4afaf3d 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"付近の Ultra Wideband デバイス間の相対位置の特定をアプリに許可します"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"付近の Wi-Fi デバイスとの通信"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"付近の Wi-Fi デバイスについて、情報の表示、接続、相対位置の確認をアプリに許可します"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"付近のデバイス間の相対位置の特定"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"付近のデバイス間の相対位置の特定をアプリに許可します"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"優先される NFC お支払いサービスの情報"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"登録されている支援やルートの目的地など、優先される NFC お支払いサービスの情報を取得することをアプリに許可します。"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"NFCの管理"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 58f78901ef5e..4ffa312f7c53 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ნებას რთავს აპს, დაადგინოს შედარებითი პოზიცია ახლომახლო ულტრაფართო სიხშირის მოწყობილობების შესახებ"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"ინტერაქცია ახლომახლო Wi-Fi მოწყობილობებთან"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"საშუალებას აძლევს აპს, განაცხადოს ახლომახლო Wi-Fi მოწყობილობების შესახებ, დაუკავშირდეს მათ და განსაზღვროს მათი შედარებითი პოზიცია"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ახლომახლო მოწყობილობებთან მიმართ. პოზიციის დადგენა"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"აპისთვის ახლომახლო მოწყობილობებთან მიმართებაში პოზიციის დადგენის ნების დართვა"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"უპირატესი NFC გადახდის სერვისის ინფორმაცია"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"საშუალებას აძლევს აპს, მიიღოს უპირატესი NFC გადახდის სერვისის ინფორმაცია, მაგალითად, რეგისტრირებული დახმარება და დანიშნულება."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ახლო მოქმედების რადიოკავშირი (NFC) მართვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 737f950567a1..6355d86a8ac9 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Қолданбаға маңайдағы кең жолақты құрылғылардың бір-біріне қатысты орнын анықтауға мүмкіндік береді."</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"маңайдағы Wi-Fi құрылғыларымен байланысу"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Қолданба маңайдағы Wi‑Fi құрылғыларына жарнама беріп, оларға қосылып, шамамен орналасқан жерін анықтай алады."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"маңайдағы құрылғылардың салыстырмалы орнын анықтау"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Қолданбаның маңайдағы құрылғылардың салыстырмалы орнын анықтауына рұқсат береді."</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Таңдаулы NFC төлеу қызметі туралы ақпарат"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Қолданба тіркелген көмектер және баратын жер маршруты сияқты таңдаулы NFC төлеу қызметі туралы ақпаратты ала алатын болады."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"NFC функциясын басқару"</string>
@@ -1398,7 +1396,7 @@
<string name="perm_costs_money" msgid="749054595022779685">"бұған төлем қажет болуы мүмкін"</string>
<string name="dlg_ok" msgid="5103447663504839312">"Жарайды"</string>
<string name="usb_charging_notification_title" msgid="1674124518282666955">"Құрылғы USB арқылы зарядталып тұр"</string>
- <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Жалғанған құрылғы USB арқылы зарядталуда"</string>
+ <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Жалғанған құрылғы USB арқылы зарядталып жатыр"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB арқылы файл жіберу мүмкіндігі қосылды"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"PTP режимі USB арқылы қосылды"</string>
<string name="usb_tether_notification_title" msgid="8828527870612663771">"USB-тетеринг режимі қосылды"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Қосу"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Артқа"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Дайын емес…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Satellite SOS функциясы енді қолжетімді"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Мобильдік немесе Wi-Fi желісі жоқ болған жағдайда, құтқару қызметтеріне хабар жіберуге болады. Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satellite SOS функциясына қолдау көрсетілмейді"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Satellite SOS функциясына бұл құрылғыда қолдау көрсетілмейді."</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satellite SOS функциясы реттелмеген"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Құрылғыңыздың интернетке қосылғанын тексеріп, қайта реттеп көріңіз."</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satellite SOS функциясы қолжетімді емес"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satellite SOS функциясы бұл елде немесе аймақта қолжетімді емес."</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satellite SOS функциясы реттелмеген"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Жерсерік арқылы хабар алмасу үшін, Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satellite SOS функциясы қолжетімді емес"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Satellite SOS функциясының бұл елде немесе аймақта қолжетімді екенін тексеру үшін, локация параметрлерін қосыңыз."</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Жерсерік арқылы хабар алмасу функциясы қолжетімді"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Мобильдік немесе Wi-Fi желісі жоқ болған жағдайда, жерсерік арқылы хабар алмаса аласыз. Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Жерсерік арқылы хабар алмасу функциясына қолдау көрсетілмейді"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Жерсерік арқылы хабар алмасу функциясына бұл құрылғыда қолдау көрсетілмейді."</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Жерсерік арқылы хабар алмасу функциясы реттелмеген"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Құрылғыңыздың интернетке қосылғанын тексеріп, қайта реттеп көріңіз."</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Жерсерік арқылы хабар алмасу функциясы қолжетімді емес"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Жерсерік арқылы хабар алмасу функциясы бұл елде немесе аймақта қолжетімді емес."</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Жерсерік арқылы хабар алмасу функциясы реттелмеген"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Жерсерік арқылы хабар алмасу үшін, Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Жерсерік арқылы хабар алмасу функциясы қолжетімді емес"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Жерсерік арқылы хабар алмасу функциясының бұл елде немесе аймақта қолжетімді екенін тексеру үшін, локация параметрлерін қосыңыз."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Саусақ ізімен ашу функциясын қайта реттеу"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> бұдан былай танылмайды."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> және <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> бұдан былай танылмайды."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 0ecad8f60fe1..4163be41f7fd 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"អនុញ្ញាតឱ្យ​កម្មវិធី​កំណត់ចម្ងាយ​ពាក់ព័ន្ធ​រវាងឧបករណ៍ Ultra-Wideband ដែលនៅជិត"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"ធ្វើអន្តរកម្ម​ជាមួយឧបករណ៍ Wi‑Fi ដែលនៅជិត"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"អនុញ្ញាតឱ្យ​កម្មវិធី​ផ្សាយពាណិជ្ជកម្ម ភ្ជាប់ និងកំណត់ទីតាំង​ពាក់ព័ន្ធរបស់​ឧបករណ៍ Wi‑Fi ដែលនៅជិត"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"កំណត់ទីតាំងធៀបរវាងឧបករណ៍នៅជិត"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"អនុញ្ញាតឱ្យកម្មវិធីកំណត់ទីតាំងធៀបរវាងឧបករណ៍នៅជិត"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ព័ត៌មានអំពី​សេវាបង់ប្រាក់តាម NFC ជាអាទិភាព"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"អនុញ្ញាតឱ្យ​កម្មវិធី​ទទួលបាន​ព័ត៌មានអំពី​សេវាបង់ប្រាក់តាម nfc ជាអាទិភាព​ដូចជា គោលដៅផ្លូវ និង​ព័ត៌មាន​កំណត់អត្តសញ្ញាណ​កម្មវិធី ដែលបានចុះឈ្មោះ​ជាដើម។"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ពិនិត្យ​ការ​ទាក់ទង​នៅ​ក្បែរ (NFC)"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index c64f6ec1e7a7..234ba66a5bc3 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ಸಮೀಪದಲ್ಲಿರುವ ಅಲ್ಟ್ರಾ-ವೈಡ್‌ಬ್ಯಾಂಡ್ ಸಾಧನಗಳ ನಡುವೆ ಸಂಬಂಧಿತ ಸ್ಥಾನವನ್ನು ನಿರ್ಧರಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸಿ"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"ಹತ್ತಿರದ ವೈ -ಫೈ ಸಾಧನಗಳ ಜೊತೆಗೆ ಸಂವಹನ ನಡೆಸಿ"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"ಹತ್ತಿರದ ವೈ -ಫೈ ಸಾಧನಗಳ ಸಂಬಂಧಿತ ಸ್ಥಾನವನ್ನು ಸೂಚಿಸಲು, ಕನೆಕ್ಟ್ ಮಾಡಲು ಮತ್ತು ನಿರ್ಧರಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ಸಮೀಪದ ಸಾಧನಗಳ ನಡುವಿನ ಸಂಬಂಧಿತ ಸ್ಥಾನವನ್ನು ನಿರ್ಧರಿಸಿ"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ನಡುವಿನ ಸಂಬಂಧಿತ ಸ್ಥಾನವನ್ನು ನಿರ್ಧರಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸಿ"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ಆದ್ಯತೆಯ NFC ಪಾವತಿ ಸೇವಾ ಮಾಹಿತಿ"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"ನೋಂದಾಯಿತ ಆ್ಯಪ್ ಗುರುತಿಸುವಿಕೆಗಳು ಮತ್ತು ಮಾರ್ಗ ಗಮ್ಯಸ್ಥಾನಗಳಂತಹ ಆದ್ಯತೆಯ NFC ಪಾವತಿ ಸೇವೆಗಳ ಬಗ್ಗೆ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ಸಮೀಪ ಕ್ಷೇತ್ರ ಸಂವಹನವನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
@@ -837,7 +835,7 @@
<string name="permlab_writeVerificationStateE2eeContactKeys" msgid="3990742344778360457">"ಇತರ ಆ್ಯಪ್‌ಗಳ ಮಾಲೀಕತ್ವದ E2EE ಸಂಪರ್ಕ ಕೀಗಳ ಪರಿಶೀಲನೆಯ ಸ್ಥಿತಿಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಿ"</string>
<string name="permdesc_writeVerificationStateE2eeContactKeys" msgid="8453156829747427041">"ಇತರ ಆ್ಯಪ್‌ಗಳ ಮಾಲೀಕತ್ವದ E2EE ಸಂಪರ್ಕ ಕೀಗಳ ಪರಿಶೀಲನೆಯ ಸ್ಥಿತಿಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"ಪಾಸ್‌ವರ್ಡ್ ನಿಮಯಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
- <string name="policydesc_limitPassword" msgid="4105491021115793793">"ಪರದೆ ಲಾಕ್‌ನಲ್ಲಿನ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಿನ್‌ಗಳ ಅನುಮತಿಸಲಾದ ಅಕ್ಷರಗಳ ಪ್ರಮಾಣವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
+ <string name="policydesc_limitPassword" msgid="4105491021115793793">"ಸ್ಕ್ರೀನ್ ಲಾಕ್‌ನಲ್ಲಿನ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಿನ್‌ಗಳ ಅನುಮತಿಸಲಾದ ಅಕ್ಷರಗಳ ಪ್ರಮಾಣವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"ಪರದೆಯ ಅನ್‌ಲಾಕ್ ಪ್ರಯತ್ನಗಳನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"ಸ್ಕ್ರೀನ್ ಅನ್‌ಲಾಕ್‌ ಮಾಡುವಾಗ ತಪ್ಪಾಗಿ ಟೈಪ್‌ ಮಾಡಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ, ಮತ್ತು ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್‌ ಮಾಡಿದ್ದರೆ ಟ್ಯಾಬ್ಲೆಟ್‌ ಅನ್ನು ಲಾಕ್‌ ಮಾಡಿ ಅಥವಾ ಟ್ಯಾಬ್ಲೆಟ್‌ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"ಪರದೆಯನ್ನು ಅನ್ಲಾಕ್ ಮಾಡುವಾಗ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ನಿಮ್ಮ Android TV ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್ ಮಾಡಿದರೆ ನಿಮ್ಮ ಎಲ್ಲಾ Android TV ಸಾಧನದ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕುತ್ತದೆ."</string>
@@ -871,7 +869,7 @@
<string name="policylab_disableCamera" msgid="5749486347810162018">"ಕ್ಯಾಮರಾಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"ಎಲ್ಲಾ ಸಾಧನ ಕ್ಯಾಮರಾಗಳ ಬಳಕೆಯನ್ನು ತಡೆಯಿರಿ."</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"ಕೆಲವು ಸ್ಕ್ರೀನ್ ಲಾಕ್ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
- <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"ಕೆಲವು ಪರದೆ ಲಾಕ್‌ನ ವೈಶಿಷ್ಟ್ಯಗಳ ಬಳಕೆಯನ್ನು ತಡೆಯಿರಿ."</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"ಕೆಲವು ಸ್ಕ್ರೀನ್ ಲಾಕ್‌ನ ವೈಶಿಷ್ಟ್ಯಗಳ ಬಳಕೆಯನ್ನು ತಡೆಯಿರಿ."</string>
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"ಮನೆ"</item>
<item msgid="7740243458912727194">"ಮೊಬೈಲ್"</item>
@@ -1410,7 +1408,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ಅನ್‌ಲಾಗ್ ಆಡಿಯೋ ಆ್ಯಕ್ಸೆಸರಿ ಪತ್ತೆಯಾಗಿದೆ"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ಲಗತ್ತಿಸಲಾದ ಸಾಧನವು ಈ ಫೋನಿನೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆ ಕನೆಕ್ಟ್‌ ಆಗಿದೆ"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆ ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ಡೀಬಗಿಂಗ್ ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ವೈರ್‌ಲೆಸ್ ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"ವೈರ್‌ಲೆಸ್ ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
@@ -1680,8 +1678,8 @@
<string name="media_route_status_available" msgid="1477537663492007608">"ಲಭ್ಯ"</string>
<string name="media_route_status_not_available" msgid="480912417977515261">"ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="media_route_status_in_use" msgid="6684112905244944724">"ಬಳಕೆಯಲ್ಲಿದೆ"</string>
- <string name="display_manager_built_in_display_name" msgid="1015775198829722440">"ಬಿಲ್ಟ್-ಇನ್ ಪರದೆ"</string>
- <string name="display_manager_hdmi_display_name" msgid="1022758026251534975">"HDMI ಪರದೆ"</string>
+ <string name="display_manager_built_in_display_name" msgid="1015775198829722440">"ಬಿಲ್ಟ್-ಇನ್ ಸ್ಕ್ರೀನ್"</string>
+ <string name="display_manager_hdmi_display_name" msgid="1022758026251534975">"HDMI ಸ್ಕ್ರೀನ್"</string>
<string name="display_manager_overlay_display_name" msgid="5306088205181005861">"ಓವರ್‌ಲೇ #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", ಸುರಕ್ಷಿತ"</string>
@@ -2409,7 +2407,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಅನ್ನು <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> ಗೆ ಸೆಟ್ ಮಾಡಲಾಗಿದೆ… ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್‌ಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"ಕೀಬೋರ್ಡ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"ಖಾಸಗಿ"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"ಪ್ರೈವೆಟ್"</string>
<string name="profile_label_clone" msgid="769106052210954285">"ಕ್ಲೋನ್"</string>
<string name="profile_label_work" msgid="3495359133038584618">"ಕೆಲಸ"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"ಕೆಲಸ 2"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d63d43e4cddd..59af8fb584ce 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"앱이 근처의 초광대역 기기 간 상대적 위치를 파악하도록 허용"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"근처 Wi‑Fi 기기와 상호작용"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"앱이 광역 신호를 보내 근처에 있는 Wi‑Fi 기기의 상대적인 위치를 확인하고 연결할 수 있도록 허용합니다."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"근처 기기 간 상대 위치 파악"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"앱이 근처 기기 간 상대 위치를 파악하도록 허용"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"기본 NFC 결제 서비스 정보"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"앱이 등록된 AID와 경로 목적지 같은 기본 NFC 결제 서비스 정보를 확인하도록 허용합니다."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"NFC(Near Field Communication) 제어"</string>
@@ -659,7 +657,7 @@
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"화면 잠금 사용"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"계속하려면 화면 잠금용 사용자 인증 정보를 입력하세요"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"센서를 세게 누르세요"</string>
- <string name="fingerprint_acquired_insufficient" msgid="2410176550915730974">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="2410176550915730974">"지문을 인식할 수 없습니다. 다시 시도해 주세요"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"지문 센서를 닦은 후 다시 시도해 보세요."</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"센서를 닦은 후 다시 시도해 보세요."</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"센서를 세게 누르세요"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e09036a1b679..cbb0a13963b3 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Колдонмо кең тилкелүү тармак аркылуу туташа турган жакын жердеги түзмөктөрдү аныктай алат"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Жакын жердеги Wi‑Fi түзмөктөрүнө байланышуу"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Колдонмо жакын жердеги Wi-Fi түзмөктөргө туташып, алардын жайгашкан жерин аныктап, ар кандай нерселерди өткөрө алат."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"жакын жердеги түзмөктөр арасындагы салыштырмалуу абалды аныктоо"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Колдонмого жакын жердеги түзмөктөр ортосундагы салыштырмалуу абалды аныктоого уруксат берүү"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Тандалган NFC төлөм кызматы жөнүндө маалымат"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Колдонмого катталган жардам же көздөлгөн жерге маршрут сыяктуу тандалган nfc төлөм кызматы жөнүндө маалыматты алууга уруксат берүү."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"Near Field Communication көзөмөлү"</string>
@@ -2409,7 +2407,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Баскычтопко төмөнкү калып коюлду: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Өзгөртүү үчүн басыңыз."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физикалык баскычтоптор конфигурацияланды"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Баскычтопторду көрүү үчүн басыңыз"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Купуя"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Жеке"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
<string name="profile_label_work" msgid="3495359133038584618">"Жумуш"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Жумуш 2"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Күйгүзүү"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Артка кайтуу"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Кезекте турат..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Спутник SOS эми жеткиликтүү"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Мобилдик Интернет же Wi-Fi тармагы жок болсо, кырсыктаганда жардамга келчү кызматтарга билдирүү жөнөтө аласыз. Google Messages демейки жазышуу колдонмоңуз болушу керек."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Спутник SOS колдоого алынбайт"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Бул түзмөктө спутник SOS колдоого алынбайт"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Спутник SOS туураланган жок"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Интернет байланышыңызды текшерип, кайра тууралап көрүңүз"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Спутник SOS жеткиликсиз"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Спутник SOS бул өлкөдө же аймакта жеткиликсиз"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Спутник SOS туураланган жок"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Спутник аркылуу жазышуу үчүн Google Messages кызматын демейки жазышуу колдонмосу катары тандаңыз"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Спутник SOS жеткиликсиз"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Бул өлкөдө же аймакта спутник SOS функциясынын жеткиликтүүлүгүн текшерүү үчүн жайгашкан жерди аныктоо параметрлерин күйгүзүңүз"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Спутник аркылуу байланышуу жеткиликтүү"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Мобилдик же Wi-Fi тармагы жок болсо, спутник аркылуу жазыша аласыз. Google Messages демейки жазышуу колдонмоңуз болушу керек."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Спутник аркылуу байланышуу колдоого алынбайт"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Бул түзмөктө спутник аркылуу байланышуу колдоого алынбайт"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Спутник аркылуу байланышуу туураланган жок"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Интернет байланышыңызды текшерип, кайра тууралап көрүңүз"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Спутник аркылуу байланышуу жеткиликсиз"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Бул өлкөдө же аймакта спутник аркылуу байланышуу жеткиликсиз"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Спутник аркылуу байланышуу туураланган жок"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Спутник аркылуу жазышуу үчүн Google Messages кызматын демейки жазышуу колдонмосу катары тандаңыз"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Спутник аркылуу байланышуу жеткиликсиз"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Бул өлкөдө же аймакта спутник аркылуу байланышуу функциясынын жеткиликтүүлүгүн текшерүү үчүн жайгашкан жерди аныктоо параметрлерин күйгүзүңүз"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Манжа изи менен ачуу функциясын кайра тууралаңыз"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> мындан ары таанылбайт."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> жана <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> мындан ары таанылбайт."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index a9ebcd765502..5af4a84c7caf 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ອະນຸຍາດໃຫ້ແອັບກຳນົດຕຳແໜ່ງທີ່ສຳພັນກັນລະຫວ່າງອຸປະກອນ Ultra-Wideband ທີ່ຢູ່ໃກ້ຄຽງ"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"ໂຕ້ຕອບກັບອຸປະກອນ Wi‑Fi ທີ່ຢູ່ໃກ້ຄຽງ"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"ອະນຸຍາດໃຫ້ແອັບໂຄສະນາ, ເຊື່ອມຕໍ່ ແລະ ກຳນົດຕຳແໜ່ງສຳພັນຂອງອຸປະກອນ Wi-Fi ທີ່ຢູ່ໃກ້ຄຽງໄດ້"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ກຳນົດຕຳແໜ່ງທີ່ກ່ຽວຂ້ອງກັນລະຫວ່າງອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ອະນຸຍາດໃຫ້ແອັບກຳນົດຕຳແໜ່ງທີ່ກ່ຽວຂ້ອງກັນລະຫວ່າງອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ຂໍ້ມູນບໍລິການການຈ່າຍເງິນ NFC ທີ່ຕ້ອງການ"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"ອະນຸຍາດໃຫ້ແອັບຮັບຂໍ້ມູນບໍລິການການຈ່າຍເງິນ NFC ທີ່ຕ້ອງການໄດ້ ເຊັ່ນ: ການຊ່ວຍເຫຼືອແບບລົງທະບຽນ ແລະ ປາຍທາງເສັ້ນທາງ."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ຄວບຄຸມ Near Field Communication"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 21fddd010ca4..cb7cc896d42f 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Leisti programai nustatyti apytikslę netoliese esančių itin plataus dažnio juostos įrenginių poziciją"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"sąveikauti su „Wi‑Fi“ įrenginiais netoliese"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Leidžiama programai reklamuoti, prisijungti ir nustatyti apytikslę netoliese esančių „Wi-Fi“ įrenginių poziciją"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"nustatyti apytikslę netoliese esančių įrenginių poziciją"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Leisti programai nustatyti apytikslę netoliese esančių įrenginių poziciją"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Pageidaujama ARL mokėjimo paslaugos informacija"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Programai leidžiama gauti pageidaujamą ARL mokamos paslaugos informaciją, pvz., užregistruotą pagalbą ir maršrutų tikslus."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"valdyti artimo lauko perdavimą (angl. „Near Field Communication“)"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 15ee04a5f1d7..b72fb074ab14 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Atļaut lietotnei noteikt relatīvo atrašanās vietu starp tuvumā esošām ultraplatjoslas ierīcēm"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Mijiedarbība ar tuvumā esošām Wi‑Fi ierīcēm"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Atļauj lietotnei nodot datus tuvumā esošām Wi‑Fi ierīcē, izveidot savienojumu ar tām un noteikt to relatīvo pozīciju."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"atrašanās vietas noteikšana relatīvi ierīcēm"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Atļaut lietotnei noteikt relatīvo atrašanās vietu starp tuvumā esošām ierīcēm"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informācija par vēlamo NFC maksājumu pakalpojumu"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Ļauj lietotnei iegūt informāciju par vēlamo NFC maksājumu pakalpojumu, piemēram, par reģistrētajiem lietojumprogrammu ID un maršruta galamērķi."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrolē tuvlauka saziņu"</string>
@@ -2436,54 +2434,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Ieslēgt"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Atpakaļ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Gaida…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Funkcija “Satelīta SOS” tagad ir pieejama"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Varat nosūtīt ziņojumu ārkārtas palīdzības dienestiem, ja nav pieejams ne mobilais, ne Wi-Fi tīkls. Lietotnei Google ziņojumi ir jābūt iestatītai kā noklusējuma ziņojumapmaiņas lietotnei."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Funkcija “Satelīta SOS” netiek atbalstīta"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Šajā ierīcē funkcija Satelīta SOS netiek atbalstīta."</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Funkcija “Satelīta SOS” nav iestatīta"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Pārliecinieties, vai ir izveidots savienojums ar internetu, un vēlreiz mēģiniet veikt iestatīšanu."</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Funkcija “Satelīta SOS” nav pieejama"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Šajā valstī vai reģionā funkcija “Satelīta SOS” nav pieejama."</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Funkcija “Satelīta SOS” nav iestatīta"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Lai varētu sūtīt ziņojumus, izmantojot satelītu, iestatiet lietotni Google ziņojumi kā noklusējuma ziņojumapmaiņas lietotni."</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Funkcija “Satelīta SOS” nav pieejama"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Lai pārbaudītu, vai funkcija “Satelīta SOS” ir pieejama šajā valstī vai reģionā, ieslēdziet atrašanās vietas iestatījumus."</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Satelīta ziņojumapmaiņa ir pieejama"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Varat sūtīt ziņojumus, izmantojot satelītu, ja nav pieejams ne mobilais, ne Wi-Fi tīkls. Lietotnei Google ziņojumi ir jābūt iestatītai kā noklusējuma ziņojumapmaiņas lietotnei."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satelīta ziņojumapmaiņa netiek atbalstīta"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Šajā ierīcē satelīta ziņojumapmaiņa netiek atbalstīta."</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satelīta ziņojumapmaiņa nav iestatīta"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Pārliecinieties, vai ir izveidots savienojums ar internetu, un vēlreiz mēģiniet veikt iestatīšanu."</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satelīta ziņojumapmaiņa nav pieejama"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Šajā valstī vai reģionā satelīta ziņojumapmaiņa nav pieejama."</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satelīta ziņojumapmaiņa nav iestatīta"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Lai varētu sūtīt ziņojumus, izmantojot satelītu, iestatiet lietotni Google ziņojumi kā noklusējuma ziņojumapmaiņas lietotni."</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satelīta ziņojumapmaiņa nav pieejama"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Lai pārbaudītu, vai satelīta ziņojumapmaiņa ir pieejama šajā valstī vai reģionā, ieslēdziet atrašanās vietas iestatījumus."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Vēlreiz iestatiet autorizāciju ar pirksta nospiedumu"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Pirksta nospiedumu (<xliff:g id="FINGERPRINT">%s</xliff:g>) vairs nevar atpazīt."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Pirkstu nospiedumus (<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> un <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>) vairs nevar atpazīt."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b5187726028b..0b0e3ef81cca 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Дозволува апликацијата да ја одреди релативната положба помеѓу уредите со ултраширок појас во близина"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"да има интеракција со уредите со Wi‑Fi во близина"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Дозволува апликацијата да рекламира, да се поврзува и да ја одредува релативната положба на уреди со Wi‑Fi во близина"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"да ја одредува рел. положба меѓу уреди во близина"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Дозволува апликацијата да ја одредува релативната положба меѓу уредите во близина"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Информации за претпочитаната услуга за плаќање преку NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Дозволува апликацијата да добие информации за претпочитаната услуга за плаќање преку NFC, како регистрирани помагала и дестинација на маршрутата."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"контролирај комуникација на блиско поле"</string>
@@ -2409,9 +2407,9 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Распоредот на тастатурата е поставен на <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Допрете за да промените."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физичките тастатури се конфигурирани"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Допрете за да ги видите тастатурите"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Приватно"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Приватен"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Клониран профил"</string>
- <string name="profile_label_work" msgid="3495359133038584618">"Работно"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Работен"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Работен профил 2"</string>
<string name="profile_label_work_3" msgid="4834572253956798917">"Работен профил 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Профил за тестирање"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Вклучи"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Врати се назад"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Во фаза на чекање…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"„Сателитски SOS“ сега е достапна"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Може да разменувате пораки со службите за итни случаи ако нема мобилна или Wi-Fi мрежа. Google Messages мора да биде ваша стандардна апликација за разменување пораки."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"„Сателитски SOS“ не е поддржана"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"„Сателитски SOS“ не е поддржана на уредов"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"„Сателитски SOS“ не е поставена"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Проверете дали сте поврзани на интернет и обидете се да поставите повторно"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"„Сателитски SOS“ не е достапна"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"„Сателитски SOS“ не е достапна во земјава или регионов"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"„Сателитски SOS“ не е поставена"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"За да разменувате пораки преку сателит, поставете ја Google Messages како стандардна апликација за разменување пораки"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"„Сателитски SOS“ не е достапна"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"За да проверите дали „Сателитски SOS“ е достапна во земјава или регионов, вклучете ги поставките за локација"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Достапна е „Сателитска размена на пораки“"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Може да разменувате пораки преку сателит ако нема мобилна или Wi-Fi мрежа. Google Messages мора да биде ваша стандардна апликација за разменување пораки."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"„Сателитска размена на пораки“ не е поддржана"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"„Сателитска размена на пораки“ не е поддржана на уредов"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"„Сателитска размена на пораки“ не е поставена"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Проверете дали сте поврзани на интернет и обидете се да поставите повторно"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"„Сателитска размена на пораки“ не е достапна"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"„Сателитска размена на пораки“ не е достапна во земјава или регионов"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"„Сателитска размена на пораки“ не е поставена"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"За да разменувате пораки преку сателит, поставете ја Google Messages како стандардна апликација за разменување пораки"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"„Сателитска размена на пораки“ не е достапна"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"За да проверите дали е достапна „Сателитска размена на пораки“ во земјава или регионов, вклучете ги поставките за локација"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Поставете „Отклучување со отпечаток“ повторно"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> веќе не може да се препознае."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> веќе не може да се препознаат."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index aabeb9b98646..fe5974b3df24 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"സമീപമുള്ള അൾട്രാ-വെെഡ്ബാൻഡ് ഉപകരണങ്ങൾ തമ്മിലുള്ള ആപേക്ഷിക സ്ഥാനം നിർണ്ണയിക്കാൻ ആപ്പിനെ അനുവദിക്കുക"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"സമീപമുള്ള വൈഫൈ ഉപകരണങ്ങളുമായി ഇടപഴകുക"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"സമീപമുള്ള വൈഫൈ ഉപകരണങ്ങൾ കാണിക്കാനും അവയിലേക്ക് കണക്റ്റ് ചെയ്യാനും അവയുടെ ആപേക്ഷിക സ്ഥാനം നിർണ്ണയിക്കാനും ആപ്പിനെ അനുവദിക്കൂ"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"സമീപമുള്ള ഉപകരണങ്ങൾ തമ്മിലുള്ള ആപേക്ഷിക സ്ഥാനം നിർണ്ണയിക്കൂ"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"സമീപമുള്ള ഉപകരണങ്ങൾ തമ്മിലുള്ള ആപേക്ഷിക സ്ഥാനം നിർണ്ണയിക്കാൻ ആപ്പിനെ അനുവദിക്കുക"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"തിരഞ്ഞെടുത്ത NFC പേയ്‌മെന്റ് സേവനത്തെ സംബന്ധിച്ച വിവരങ്ങൾ"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"റൂട്ട് ലക്ഷ്യസ്ഥാനം, രജിസ്‌റ്റർ ചെയ്തിരിക്കുന്ന സഹായങ്ങൾ എന്നിവ പോലുള്ള, തിരഞ്ഞെടുത്ത NFC പേയ്‌മെന്റ് സേവനത്തെ സംബന്ധിച്ച വിവരങ്ങൾ ലഭിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"സമീപ ഫീൽഡുമായുള്ള ആശയവിനിമയം നിയന്ത്രിക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index c625d31dbd79..376a03350b23 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Аппад ойролцоох ультра өргөн зурвасын төхөөрөмжүүдийн хоорондох холбоотой байрлалыг тодорхойлохыг зөвшөөрөх"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"ойролцоох Wi-Fi төхөөрөмжүүдтэй харилцах"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Аппад ойролцоох Wi-Fi төхөөрөмжүүдтэй холбоотой байрлалыг мэдэгдэх, холбох, тодорхойлохыг зөвшөөрнө"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ойр төхөөрөмжүүдийн хоорондох харьцангуй байрлалыг тодорхойл"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Аппад ойролцоох төхөөрөмжүүдийн хоорондох харьцангуй байрлалыг тодорхойлохыг зөвшөөрнө үү"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Сонгосон NFC төлбөрийн үйлчилгээний мэдээлэл"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Бүртгүүлсэн төхөөрөмж болон маршрутын хүрэх цэг зэрэг сонгосон nfc төлбөрийн үйлчилгээний мэдээллийг авахыг аппад зөвшөөрдөг."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ойролцоо талбарын холбоог удирдах"</string>
@@ -917,7 +915,7 @@
</string-array>
<string name="phoneTypeCustom" msgid="5120365721260686814">"Тусгай"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"Гэрийн"</string>
- <string name="phoneTypeMobile" msgid="1178852541462086735">"Мобайл"</string>
+ <string name="phoneTypeMobile" msgid="1178852541462086735">"Гар утас"</string>
<string name="phoneTypeWork" msgid="6604967163358864607">"Ажлын"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"Ажлын факс"</string>
<string name="phoneTypeFaxHome" msgid="6678559953115904345">"Гэрийн Факс"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Асаах"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Буцах"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Хүлээгдэж буй..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Хиймэл дагуул SOS одоо боломжтой боллоо"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Та хөдөлгөөнт холбооны эсвэл Wi-Fi сүлжээ байхгүй бол яаралтай тусламжийн үйлчилгээ рүү мессеж бичих боломжтой. Google Мессеж таны өгөгдмөл мессеж апп байх ёстой."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Хиймэл дагуул SOS-г дэмждэггүй"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Хиймэл дагуул SOS-г энэ төхөөрөмж дээр дэмждэггүй"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Хиймэл дагуул SOS-г тохируулаагүй байна"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Та интернэтэд холбогдсон эсэхийг шалгаад, тохируулгыг дахин оролдоно уу"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Хиймэл дагуул SOS боломжгүй байна"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Хиймэл дагуул SOS энэ улс эсвэл бүс нутагт боломжгүй"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Хиймэл дагуул SOS-г тохируулаагүй байна"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Хиймэл дагуулаар дамжин мессеж бичихийн тулд Google Мессежийг өгөгдмөл мессеж аппаараа тохируулна уу"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Хиймэл дагуул SOS боломжгүй байна"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Энэ улс эсвэл бүс нутагт Хиймэл дагуул SOS боломжтой эсэхийг шалгахын тулд байршлын тохиргоог асаана уу"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Хиймэл дагуулаар дамжин мессеж бичих боломжтой"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Хэрэв хөдөлгөөнт холбооны эсвэл Wi-Fi сүлжээ байхгүй бол та хиймэл дагуулаар дамжин мессеж бичих боломжтой. Google Мессеж таны өгөгдмөл мессеж апп байх ёстой."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Хиймэл дагуулаар дамжин мессеж бичихийг дэмждэггүй"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Хиймэл дагуулаар дамжин мессеж бичихийг энэ төхөөрөмж дээр дэмждэггүй"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Хиймэл дагуулаар дамжин мессеж бичихийг тохируулаагүй"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Та интернэтэд холбогдсон эсэхийг шалгаад, тохируулгыг дахин оролдоно уу"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Хиймэл дагуулаар дамжин мессеж бичих боломжгүй"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Энэ улс эсвэл бүс нутагт хиймэл дагуулаар дамжин мессеж бичих боломжгүй"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Хиймэл дагуулаар дамжин мессеж бичихийг тохируулаагүй"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Хиймэл дагуулаар дамжин мессеж бичихийн тулд Google Мессежийг өгөгдмөл мессеж аппаараа тохируулна уу"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Хиймэл дагуулаар дамжин мессеж бичих боломжгүй"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Энэ улс эсвэл бүс нутагт хиймэл дагуулаар дамжин мессеж бичих боломжтой эсэхийг шалгахын тулд байршлын тохиргоог асаана уу"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Хурууны хээгээр түгжээ тайлахыг дахин тохируулна уу"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>-г цаашид таних боломжгүй."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> болон <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>-г цаашид таних боломжгүй."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 3240d5914056..e640f729d093 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ॲपला जवळच्या अल्ट्रा-वाइडबँड डिव्हाइसदरम्यानचे संबंधित स्थान निर्धारित करण्याची अनुमती द्या"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"जवळपासच्या वाय-फाय डिव्हाइसशी संवाद साधा"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"ॲपला जाहिरात करण्याची, कनेक्ट करण्याची आणि जवळपासच्या वाय-फाय डिव्हाइसचे संबंधित स्थान निर्धारित करण्याची परवानगी देते"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"जवळपासच्या डिव्हाइसदरम्यान संबंधित स्थान निश्चित करा"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ॲपला जवळच्या डिव्हाइसदरम्यानचे संबंधित स्थान निर्धारित करण्याची अनुमती द्या"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"प्राधान्यकृत NFC पेमेंट सेवा माहिती"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"नोंदणीकृत एड्स आणि मार्ग गंतव्यस्थान सारखी प्राधान्यकृत एनएफसी पेमेंट सेवेची माहिती मिळवण्यासाठी अ‍ॅपला अनुमती देते."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"फील्ड जवळील कम्युनिकेशन नियंत्रित करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index bd780ae0be92..3946ac1df42f 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Benarkan apl menentukan kedudukan relatif antara peranti Ultrajalur Lebar berdekatan"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"berinteraksi dengan peranti Wi-Fi berdekatan"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Membenarkan apl mengiklankan, menyambung dan menentukan kedudukan relatif peranti Wi-Fi berdekatan"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"tentukan kedudukan relatif antara peranti berdekatan"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Benarkan apl menentukan kedudukan relatif antara peranti berdekatan"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Maklumat Perkhidmatan Pembayaran NFC Pilihan"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Membenarkan apl mendapatkan maklumat perkhidmatan pembayaran nfc pilihan seperti bantuan berdaftar dan destinasi laluan."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"mengawal Komunikasi Medan Dekat"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index e4c2acaba9f5..fc0072557cb0 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"အနီးရှိ ‘အလွန်ကျယ်ပြန့်သော လှိုင်းအလျားသုံးစက်များ’ ကြား မှန်းခြေနေရာကို သတ်မှတ်ရန် အက်ပ်ကို ခွင့်ပြုမည်"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"အနီးရှိ Wi-Fi စက်များနှင့် ပြန်လှန်တုံ့ပြန်ခြင်း"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"ကြော်ငြာရန်၊ ချိတ်ဆက်ရန်နှင့် အနီးတစ်ဝိုက်ရှိ Wi-Fi စက်များ၏ နေရာကို သတ်မှတ်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"အနီးတစ်ဝိုက်ရှိ စက်များကြား ဆက်စပ်နေရာသတ်မှတ်ခြင်း"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"အနီးတစ်ဝိုက်ရှိ စက်များကြား ဆက်စပ်နေရာသတ်မှတ်ရန် အက်ပ်ကိုခွင့်ပြုသည်"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ဦးစားပေး NFC ငွေပေးချေမှုဆိုင်ရာ ဝန်ဆောင်မှု အချက်အလက်များ"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"အက်ပ်အား ဦစားပေး NFC ငွေပေးချေမှုဆိုင်ရာ ဝန်ဆောင်မှု အချက်အလက်များဖြစ်သည့် မှတ်ပုံတင်ထားသော အကူအညီများနှင့် သွားလာရာ လမ်းကြောင်းတို့ကို ရယူရန် ခွင့်ပြုသည်။"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"Near Field Communicationအား ထိန်းချုပ်ရန်"</string>
@@ -2446,7 +2444,7 @@
<string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satellite SOS ကို စနစ်ထည့်သွင်းမထားပါ"</string>
<string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"ဂြိုဟ်တုမှတစ်ဆင့် မက်ဆေ့ဂျ်ပို့ရန် Google Messages ကို သင်၏ မက်ဆေ့ဂျ်ပို့ရန် မူရင်းအက်ပ်အဖြစ် သတ်မှတ်ပါ"</string>
<string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satellite SOS မရနိုင်ပါ"</string>
- <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"satellite SOS ကို ဤနိုင်ငံ (သို့) ဒေသတွင် ရနိုင်ခြင်းရှိ၊ မရှိ စစ်ဆေးရန် တည်နေရာပြ ဆက်တင်များကို ဖွင့်ပါ"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Satellite SOS ကို ဤနိုင်ငံ (သို့) ဒေသတွင် ရနိုင်ခြင်းရှိ၊ မရှိ စစ်ဆေးရန် တည်နေရာပြ ဆက်တင်များကို ဖွင့်ပါ"</string>
<string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"ဂြိုဟ်တုမှတစ်ဆင့် မက်ဆေ့ဂျ်ပို့ခြင်း ရနိုင်သည်"</string>
<string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"မိုဘိုင်း (သို့) Wi-Fi ကွန်ရက် မရှိသည့်အခါ ဂြိုဟ်တုမှတစ်ဆင့် မက်ဆေ့ဂျ်ပို့နိုင်သည်။ Google Messages သည် သင်၏ မူရင်းမက်ဆေ့ဂျ်ပို့ရန်အက်ပ် ဖြစ်ရမည်။"</string>
<string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"ဂြိုဟ်တုမှတစ်ဆင့် မက်ဆေ့ဂျ်ပို့ခြင်းကို ပံ့ပိုးမထားပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ec4cd961faee..c1095d3978ef 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"tillate at appen fastslår den relative posisjonen mellom enheter i nærheten som bruker ultrabredbånd"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"samhandle med wifi-enheter i nærheten"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Lar appen annonsere, koble til og fastslå den relative posisjonen til wifi-enheter i nærheten"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"Relativ posisjon mellom enheter i nærheten"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Tillat at appen avgjør den relative posisjonen mellom enheter i nærheten"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informasjon om prioritert NFC-betalingstjeneste"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Gir appen tilgang til informasjon om prioritert NFC-betalingstjeneste, for eksempel registrerte hjelpemidler og destinasjon."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontroller overføring av data med NFC-teknologi"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Slå på"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Gå tilbake"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Venter …"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Nå er SOS-alarm via satellitt tilgjengelig"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Du kan sende meldinger til nødtjenestene hvis du ikke har mobil- eller wifi-dekning. Google Meldinger må være standardappen for meldinger."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"SOS-alarm via satellitt støttes ikke"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"SOS-alarm via satellitt støttes ikke på denne enheten"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS-alarm via satellitt er ikke konfigurert"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Sjekk at du er koblet til internett, og prøv konfigureringen på nytt"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"SOS-alarm via satellitt er ikke tilgjengelig"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"SOS-alarm via satellitt er ikke tilgjengelig i dette landet eller denne regionen"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"SOS-alarm via satellitt er ikke konfigurert"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"For å sende meldinger via satellitt må du angi Google Meldinger som standardapp for meldinger"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"SOS-alarm via satellitt er ikke tilgjengelig"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"For å sjekke om SOS-alarm via satellitt er tilgjengelig i dette landet eller denne regionen, slå på posisjonsinnstillingene"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Satellittmeldinger er tilgjengelige"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Du kan sende meldinger via satellitt hvis du ikke har mobil- eller wifi-dekning. Google Meldinger må være standardappen for meldinger."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satellittmeldinger støttes ikke"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Satellittmeldinger støttes ikke på denne enheten"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satellittmeldinger er ikke konfigurert"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Sjekk at du er koblet til internett, og prøv konfigureringen på nytt"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satellittmeldinger er ikke tilgjengelige"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satellittmeldinger er ikke tilgjengelige i dette landet eller denne regionen"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satellittmeldinger er ikke konfigurert"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"For å sende meldinger via satellitt må du angi Google Meldinger som standardapp for meldinger"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Satellittmeldinger er ikke tilgjengelige"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"For å sjekke om satellittmeldinger er tilgjengelige i dette landet eller denne regionen, slå på posisjonsinnstillinger"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurer opplåsingen med fingeravtrykk på nytt"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> gjenkjennes ikke lenger."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> gjenkjennes ikke lenger."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0dc0bd3d04a9..beda131e3de4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"यो एपलाई नजिकै रहेका अल्ट्रा-वाइडब्यान्ड चल्ने डिभाइसहरूबिचको तुलनात्मक स्थान पत्ता लगाउन दिनुहोस्"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Wi-Fi चल्ने नजिकै रहेका डिभाइसहरूमा चलाउन दिन्छ"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"यसले एपलाई Wi-Fi चल्ने नजिकै रहेका डिभाइसहरूमा विज्ञापन गर्न, कनेक्ट गर्न र सापेक्ष स्थिति निर्धारण गर्न दिन्छ"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"नजिकै रहेका डिभाइसहरूबिचको तुलनात्मक स्थान पत्ता लगाउने"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"यो एपलाई नजिकै रहेका डिभाइसहरूबिचको तुलनात्मक स्थान पत्ता लगाउन दिनुहोस्"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"NFC भुक्तानी सेवासम्बन्धी रुचाइएको जानकारी"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"यसले एपलाई दर्ता गरिएका सहायता तथा मार्गको गन्तव्य जस्ता रुचाइएका NFC भुक्तानी सेवासम्बन्धी जानकारी प्राप्त गर्न दिन्छ।"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"नजिक क्षेत्र संचार नियन्त्रणहरू"</string>
@@ -2173,8 +2171,8 @@
<string name="mime_type_audio_ext" msgid="2615491023840514797">"<xliff:g id="EXTENSION">%1$s</xliff:g> अडियो"</string>
<string name="mime_type_video" msgid="7071965726609428150">"भिडियो"</string>
<string name="mime_type_video_ext" msgid="185438149044230136">"<xliff:g id="EXTENSION">%1$s</xliff:g> भिडियो"</string>
- <string name="mime_type_image" msgid="2134307276151645257">"छवि"</string>
- <string name="mime_type_image_ext" msgid="5743552697560999471">"<xliff:g id="EXTENSION">%1$s</xliff:g> छवि"</string>
+ <string name="mime_type_image" msgid="2134307276151645257">"फोटो"</string>
+ <string name="mime_type_image_ext" msgid="5743552697560999471">"<xliff:g id="EXTENSION">%1$s</xliff:g> फोटो"</string>
<string name="mime_type_compressed" msgid="8737300936080662063">"अभिलेख"</string>
<string name="mime_type_compressed_ext" msgid="4775627287994475737">"<xliff:g id="EXTENSION">%1$s</xliff:g> अभिलेख"</string>
<string name="mime_type_document" msgid="3737256839487088554">"कागजात"</string>
@@ -2211,7 +2209,7 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad को बिचको बटन"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"छवि पठाइयो"</string>
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"फोटो पठाइयो"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"वार्तालाप"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"सामूहिक वार्तालाप"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
@@ -2409,7 +2407,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"किबोर्ड लेआउट <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> भाषामा सेट गरिएको छ… बदल्न ट्याप गर्नुहोस्।"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"भौतिक किबोर्डहरू कन्फिगर गरिएका छन्"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"किबोर्डहरू हेर्न ट्याप गर्नुहोस्"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"निजी"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"निजी स्पेस"</string>
<string name="profile_label_clone" msgid="769106052210954285">"क्लोन"</string>
<string name="profile_label_work" msgid="3495359133038584618">"कार्य"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"कार्य प्रोफाइल २"</string>
diff --git a/core/res/res/values-night/colors_dynamic.xml b/core/res/res/values-night/colors_dynamic.xml
new file mode 100644
index 000000000000..7e95ff4f409e
--- /dev/null
+++ b/core/res/res/values-night/colors_dynamic.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- Colors specific to Material themes. -->
+<resources>
+ <color name="materialColorBackground">@color/system_background_dark</color>
+ <color name="materialColorControlActivated">@color/system_control_activated_dark</color>
+ <color name="materialColorControlHighlight">@color/system_control_highlight_dark</color>
+ <color name="materialColorControlNormal">@color/system_control_normal_dark</color>
+ <color name="materialColorError">@color/system_error_dark</color>
+ <color name="materialColorErrorContainer">@color/system_error_container_dark</color>
+ <color name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</color>
+ <color name="materialColorInversePrimary">@color/system_inverse_primary_dark</color>
+ <color name="materialColorInverseSurface">@color/system_inverse_surface_dark</color>
+ <color name="materialColorOnBackground">@color/system_on_background_dark</color>
+ <color name="materialColorOnError">@color/system_on_error_dark</color>
+ <color name="materialColorOnErrorContainer">@color/system_on_error_container_dark</color>
+ <color name="materialColorOnPrimary">@color/system_on_primary_dark</color>
+ <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</color>
+ <color name="materialColorOnSecondary">@color/system_on_secondary_dark</color>
+ <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</color>
+ <color name="materialColorOnSurface">@color/system_on_surface_dark</color>
+ <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</color>
+ <color name="materialColorOnTertiary">@color/system_on_tertiary_dark</color>
+ <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</color>
+ <color name="materialColorOutline">@color/system_outline_dark</color>
+ <color name="materialColorOutlineVariant">@color/system_outline_variant_dark</color>
+ <color name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</color>
+ <color name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</color>
+ <color name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</color>
+ <color name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</color>
+ <color name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</color>
+ <color name="materialColorPrimary">@color/system_primary_dark</color>
+ <color name="materialColorPrimaryContainer">@color/system_primary_container_dark</color>
+ <color name="materialColorScrim">@color/system_scrim_dark</color>
+ <color name="materialColorSecondary">@color/system_secondary_dark</color>
+ <color name="materialColorSecondaryContainer">@color/system_secondary_container_dark</color>
+ <color name="materialColorShadow">@color/system_shadow_dark</color>
+ <color name="materialColorSurface">@color/system_surface_dark</color>
+ <color name="materialColorSurfaceBright">@color/system_surface_bright_dark</color>
+ <color name="materialColorSurfaceContainer">@color/system_surface_container_dark</color>
+ <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</color>
+ <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</color>
+ <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</color>
+ <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</color>
+ <color name="materialColorSurfaceDim">@color/system_surface_dim_dark</color>
+ <color name="materialColorSurfaceTint">@color/system_surface_tint_dark</color>
+ <color name="materialColorSurfaceVariant">@color/system_surface_variant_dark</color>
+ <color name="materialColorTertiary">@color/system_tertiary_dark</color>
+ <color name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</color>
+ <color name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</color>
+ <color name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</color>
+ <color name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</color>
+ <color name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</color>
+ <color name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</color>
+ <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color>
+ <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color>
+ <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color>
+ <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color>
+ <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color>
+ <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color>
+ <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color>
+ <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color>
+ <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color>
+ <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color>
+ <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color>
+ <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color>
+ <color name="customColorBrandA">@color/system_brand_a_dark</color>
+ <color name="customColorBrandB">@color/system_brand_b_dark</color>
+ <color name="customColorBrandC">@color/system_brand_c_dark</color>
+ <color name="customColorBrandD">@color/system_brand_d_dark</color>
+ <color name="customColorClockHour">@color/system_clock_hour_dark</color>
+ <color name="customColorClockMinute">@color/system_clock_minute_dark</color>
+ <color name="customColorClockSecond">@color/system_clock_second_dark</color>
+ <color name="customColorOnShadeActive">@color/system_on_shade_active_dark</color>
+ <color name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</color>
+ <color name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</color>
+ <color name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</color>
+ <color name="customColorOnThemeApp">@color/system_on_theme_app_dark</color>
+ <color name="customColorOverviewBackground">@color/system_overview_background_dark</color>
+ <color name="customColorShadeActive">@color/system_shade_active_dark</color>
+ <color name="customColorShadeDisabled">@color/system_shade_disabled_dark</color>
+ <color name="customColorShadeInactive">@color/system_shade_inactive_dark</color>
+ <color name="customColorThemeApp">@color/system_theme_app_dark</color>
+ <color name="customColorThemeAppRing">@color/system_theme_app_ring_dark</color>
+ <color name="customColorThemeNotif">@color/system_theme_notif_dark</color>
+ <color name="customColorUnderSurface">@color/system_under_surface_dark</color>
+ <color name="customColorWeatherTemp">@color/system_weather_temp_dark</color>
+ <color name="customColorWidgetBackground">@color/system_widget_background_dark</color>
+</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e55334740778..48c8be196bc0 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"De app toestaan om de relatieve positie tussen ultrabreedbandapparaten in de buurt te bepalen"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interactie met wifi-apparaten in de buurt"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Hiermee kan de app uitzenden, verbindingen maken en de relatieve positie bepalen van wifi-apparaten in de buurt"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"relatieve positie tussen apparaten in de buurt bepalen"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Sta toe dat de app de relatieve positie tussen apparaten in de buurt bepaalt"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informatie over voorkeursservice voor NFC-betaling"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Hiermee kun je zorgen dat de app informatie krijgt over de voorkeursservice voor NFC-betaling, zoals geregistreerde hulpmiddelen en routebestemmingen."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"Near Field Communication regelen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 2515bb5052eb..a99afa5a0a2f 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ଆଖପାଖର ଅଲଟ୍ରା-ୱାଇଡବ୍ୟାଣ୍ଡ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପେକ୍ଷିକ ଅବସ୍ଥିତିକୁ ନିର୍ଦ୍ଧାରଣ କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"ଆଖପାଖର ୱାଇ-ଫାଇ ଡିଭାଇସଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରନ୍ତୁ"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"ଆଖପାଖର ୱାଇ-ଫାଇ ଡିଭାଇସରେ ବିଜ୍ଞାପନ ଦେବା, ତା ସହ ସଂଯୋଗ କରିବା ଓ ତା’ର ଆପେକ୍ଷିକ ଅବସ୍ଥିତି ନିର୍ଦ୍ଧାରଣ କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ଆଖପାଖର ଡିଭାଇସ ମଧ୍ୟରେ ଆପେକ୍ଷିକ ଅବସ୍ଥିତିକୁ ନିର୍ଦ୍ଧାରଣ କର"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପେକ୍ଷିକ ଅବସ୍ଥିତିକୁ ନିର୍ଦ୍ଧାରଣ କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ପସନ୍ଦର NFC ପେମେଣ୍ଟ ସେବା ସୂଚନା"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"ପଞ୍ଜିକୃତ ଯନ୍ତ୍ର ଏବଂ ମାର୍ଗ ଲକ୍ଷସ୍ଥଳ ପରି ପସନ୍ଦର nfc ପେମେଣ୍ଟ ସେବା ସୂଚନା ପାଇବାକୁ ଆପ୍ ଅନୁମତି କରିଥାଏ।"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ନିଅର୍ ଫିଲ୍ଡ କମ୍ୟୁନିକେଶନ୍ ଉପରେ ନିୟନ୍ତ୍ରଣ ରଖନ୍ତୁ"</string>
@@ -1993,7 +1991,7 @@
<string name="importance_from_user" msgid="2782756722448800447">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ପ୍ରମୁଖତା ଆପଣ ସେଟ୍‍ କରନ୍ତି।"</string>
<string name="importance_from_person" msgid="4235804979664465383">"ସମ୍ପୃକ୍ତ ଲୋକଙ୍କ କାରଣରୁ ଏହା ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଅଟେ।"</string>
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"କଷ୍ଟମ୍ ଆପ୍ ବିଜ୍ଞପ୍ତି"</string>
- <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ (ପୂର୍ବରୁ ଏହି ଆକାଉଣ୍ଟ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ନାମରେ ଅଛି) ଅନୁମତି ଦେବେ?"</string>
+ <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ୟୁଜର ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ (ପୂର୍ବରୁ ଏହି ଆକାଉଣ୍ଟ ୟୁଜରଙ୍କ ନାମରେ ଅଛି) ଅନୁମତି ଦେବେ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ୟୁଜର ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="supervised_user_creation_label" msgid="6884904353827427515">"ନିରୀକ୍ଷିତ ୟୁଜର ଯୋଗ କରନ୍ତୁ"</string>
<string name="language_selection_title" msgid="52674936078683285">"ଏକ ଭାଷା ଯୋଗ କରନ୍ତୁ"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"ପଛକୁ ଫେରନ୍ତୁ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ବାକି ଅଛି…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"ବର୍ତ୍ତମାନ ସେଟେଲାଇଟ SOS ଉପଲବ୍ଧ ଅଛି"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"କୌଣସି ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ନଥିଲେ ଆପଣ ଜରୁରୀକାଳୀନ ସେବାଗୁଡ଼ିକୁ ମେସେଜ କରିପାରିବେ। Google Messages ଆପଣଙ୍କର ଡିଫଲ୍ଟ ମେସେଜିଂ ଆପ ହେବା ଆବଶ୍ୟକ।"</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"ସେଟେଲାଇଟ SOS ସପୋର୍ଟ କରୁନାହିଁ"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"ଏହି ଡିଭାଇସରେ ସେଟେଲାଇଟ SOS ସପୋର୍ଟ କରୁନାହିଁ"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"ସେଟେଲାଇଟ SOS ସେଟ ଅପ କରାଯାଇନାହିଁ"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"ଆପଣ ଇଣ୍ଟର୍ନେଟ ସହ କନେକ୍ଟ ଅଛନ୍ତି ବୋଲି ସୁନିଶ୍ଚିତ କରି ପୁଣି ସେଟଅପ କରିବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"ସେଟେଲାଇଟ SOS ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"ଏହି ଦେଶ କିମ୍ବା ଅଞ୍ଚଳରେ ସେଟେଲାଇଟ SOS ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"ସେଟେଲାଇଟ SOS ସେଟ ଅପ କରାଯାଇନାହିଁ"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"ସେଟେଲାଇଟ ମାଧ୍ୟମରେ ମେସେଜ କରିବା ପାଇଁ Google Messagesକୁ ଆପଣଙ୍କର ଡିଫଲ୍ଟ ମେସେଜିଂ ଆପ ଭାବେ ସେଟ କରନ୍ତୁ"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"ସେଟେଲାଇଟ SOS ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"ଏହି ଦେଶ କିମ୍ବା ଅଞ୍ଚଳରେ ସେଟେଲାଇଟ SOS ଉପଲବ୍ଧ ଅଛି ନା ନାହିଁ ତାହା ଯାଞ୍ଚ କରିବାକୁ ଲୋକେସନ ସେଟିଂସ ଚାଲୁ କରନ୍ତୁ"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"ସେଟେଲାଇଟ ମେସେଜିଂ ଉପଲବ୍ଧ ଅଛି"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"କୌଣସି ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ନଥିଲେ ଆପଣ ସେଟେଲାଇଟ ମାଧ୍ୟମରେ ମେସେଜ କରିପାରିବେ। Google Messages ଆପଣଙ୍କର ଡିଫଲ୍ଟ ମେସେଜିଂ ଆପ ହେବା ଆବଶ୍ୟକ।"</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"ସେଟେଲାଇଟ ମେସେଜିଂ ସପୋର୍ଟ କରୁନାହିଁ"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"ଏହି ଡିଭାଇସରେ ସେଟେଲାଇଟ ମେସେଜିଂ ସପୋର୍ଟ କରୁନାହିଁ"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"ସେଟେଲାଇଟ ମେସେଜିଂ ସେଟ ଅପ କରାଯାଇନାହିଁ"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"ଆପଣ ଇଣ୍ଟର୍ନେଟ ସହ କନେକ୍ଟ ଅଛନ୍ତି ବୋଲି ସୁନିଶ୍ଚିତ କରି ପୁଣି ସେଟଅପ କରିବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"ସେଟେଲାଇଟ ମେସେଜିଂ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"ଏହି ଦେଶ କିମ୍ବା ଅଞ୍ଚଳରେ ସେଟେଲାଇଟ ମେସେଜିଂ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"ସେଟେଲାଇଟ ମେସେଜିଂ ସେଟ ଅପ କରାଯାଇନାହିଁ"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"ସେଟେଲାଇଟ ମାଧ୍ୟମରେ ମେସେଜ କରିବା ପାଇଁ Google Messagesକୁ ଆପଣଙ୍କର ଡିଫଲ୍ଟ ମେସେଜିଂ ଆପ ଭାବେ ସେଟ କରନ୍ତୁ"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"ସେଟେଲାଇଟ ମେସେଜିଂ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"ଏହି ଦେଶ କିମ୍ବା ଅଞ୍ଚଳରେ ସେଟେଲାଇଟ ମେସେଜିଂ ଉପଲବ୍ଧ ଅଛି ନା ନାହିଁ ତାହା ଯାଞ୍ଚ କରିବାକୁ ଲୋକେସନ ସେଟିଂସ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>କୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ।"</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ଏବଂ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>କୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 574d991b9dfc..b46301744701 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ਐਪ ਨੂੰ ਨਜ਼ਦੀਕੀ ਅਲਟ੍ਰਾ-ਵਾਈਡਬੈਂਡ ਡੀਵਾਈਸਾਂ ਦੇ ਵਿਚਾਲੇ ਸੰਬੰਧਿਤ ਸਥਿਤੀ ਨੂੰ ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"ਨਜ਼ਦੀਕੀ ਵਾਈ-ਫਾਈ ਡੀਵਾਈਸਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰੋ"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"ਐਪ ਨੂੰ ਨਜ਼ਦੀਕੀ ਵਾਈ-ਫਾਈ ਡੀਵਾਈਸਾਂ \'ਤੇ ਵਿਗਿਆਪਨ ਦੇਣ, ਕਨੈਕਟ ਕਰਨ ਅਤੇ ਉਨ੍ਹਾਂ ਦੀ ਸੰਬੰਧਿਤ ਸਥਿਤੀ ਨੂੰ ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਵਿਚਾਲੇ ਸੰਬੰਧਿਤ ਸਥਿਤੀ ਨਿਰਧਾਰਿਤ ਕਰੋ"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ਐਪ ਨੂੰ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਦੇ ਵਿਚਾਲੇ ਸੰਬੰਧਿਤ ਸਥਿਤੀ ਨੂੰ ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ਤਰਜੀਹੀ NFC ਭੁਗਤਾਨਸ਼ੁਦਾ ਸੇਵਾ ਜਾਣਕਾਰੀ"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"ਐਪ ਨੂੰ ਤਰਜੀਹੀ NFC ਭੁਗਤਾਨਸ਼ੁਦਾ ਸੇਵਾ ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰਨ ਦਿੰਦਾ ਹੈ ਜਿਵੇਂ ਕਿ ਰਜਿਸਟਰ ਕੀਤੇ ਸਾਧਨ ਅਤੇ ਮੰਜ਼ਿਲ ਰਸਤਾ।"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ਨਜ਼ਦੀਕੀ ਖੇਤਰ ਸੰਚਾਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f267877b3a18..4f34fc5ed84e 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Zezwól na określanie przez aplikację względnego położenia urządzeń ultraszerokopasmowych w pobliżu"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interakcje z urządzeniami Wi-Fi w pobliżu"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Zezwala aplikacji na przesyłanie informacji o sobie, łączenie się z urządzeniami Wi‑Fi w pobliżu i określanie ich względnego położenia"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"określanie względnego położenia urządzeń w pobliżu"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Zezwól na określanie przez aplikację względnego położenia urządzeń w pobliżu"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informacje o preferowanych usługach płatniczych NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Pozwala aplikacji uzyskiwać informacje o preferowanych usługach płatniczych NFC, np. zarejestrowanych pomocach i miejscach docelowych tras."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrolowanie łączności Near Field Communication"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 1719648d10f0..a2192767258a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -323,7 +323,7 @@
<string name="permgrouplab_location" msgid="1858277002233964394">"Localização"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"acesse o local do dispositivo"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"Agenda"</string>
- <string name="permgroupdesc_calendar" msgid="6762751063361489379">"acesse sua agenda"</string>
+ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"acessar sua agenda"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"envie e veja mensagens SMS"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"Arquivos"</string>
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permitir que o app determine o posicionamento relativo entre dispositivos de banda ultralarga por perto"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagir com dispositivos Wi-Fi por perto"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permite que o app divulgue, faça conexão e determine a posição relativa de dispositivos Wi-Fi por perto."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determinar o posicionamento relativo entre dispositivos por perto"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permitir que o app determine o posicionamento relativo entre dispositivos por perto"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informações preferidas de serviço de pagamento por NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que o app acesse as informações preferidas de serviço de pagamento por NFC, como auxílios registrados ou destinos de trajetos."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlar a comunicação a curta distância"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index b8fc6a96f783..a898121434e5 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permita que a app determine a posição relativa entre os dispositivos de banda ultralarga próximos"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagir com dispositivos Wi‑Fi próximos"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permite que a app anuncie, estabeleça ligação e determine a posição relativa de dispositivos Wi‑Fi próximos"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determinar a posição relativa entre disp. próximos"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permita que a app determine a posição relativa entre os dispositivos próximos"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informações de serviços de pagamento com NFC preferenciais"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que a app obtenha informações de serviços de pagamento com NFC preferenciais, como apoios registados e destino da rota."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlo Near Field Communication"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1719648d10f0..a2192767258a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -323,7 +323,7 @@
<string name="permgrouplab_location" msgid="1858277002233964394">"Localização"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"acesse o local do dispositivo"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"Agenda"</string>
- <string name="permgroupdesc_calendar" msgid="6762751063361489379">"acesse sua agenda"</string>
+ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"acessar sua agenda"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"envie e veja mensagens SMS"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"Arquivos"</string>
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permitir que o app determine o posicionamento relativo entre dispositivos de banda ultralarga por perto"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagir com dispositivos Wi-Fi por perto"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permite que o app divulgue, faça conexão e determine a posição relativa de dispositivos Wi-Fi por perto."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"determinar o posicionamento relativo entre dispositivos por perto"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permitir que o app determine o posicionamento relativo entre dispositivos por perto"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informações preferidas de serviço de pagamento por NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que o app acesse as informações preferidas de serviço de pagamento por NFC, como auxílios registrados ou destinos de trajetos."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlar a comunicação a curta distância"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7843bbe1e9f1..8b7a29683d8e 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Permite-i aplicației să stabilească poziția relativă dintre dispozitivele Ultra-Wideband din apropiere"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"să interacționeze cu dispozitive Wi‑Fi din apropiere"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permite aplicației să se conecteze la dispozitive Wi-Fi din apropiere, să transmită anunțuri și să stabilească poziția relativă a acestora"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"stabilește poziția dispozitivelor din apropiere"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Permite-i aplicației să stabilească poziția relativă dintre dispozitivele din apropiere"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informații despre serviciul de plăți NFC preferat"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite aplicației să obțină informații despre serviciul de plăți NFC preferat, de exemplu, identificatorii de aplicație înregistrați și destinația traseului."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlare schimb de date prin Near Field Communication"</string>
@@ -2437,7 +2435,7 @@
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Înapoi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"În așteptare..."</string>
<string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Funcția SOS prin satelit este acum disponibilă"</string>
- <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Poți să trimiți mesaje serviciilor de urgență dacă nu este disponibilă o rețea mobilă sau Wi-Fi. Mesaje Google trebuie să fie aplicația ta pentru mesaje prestabilită."</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Poți să trimiți mesaje serviciilor de urgență dacă nu este disponibilă o rețea mobilă sau Wi-Fi. Mesaje Google trebuie să fie aplicația ta prestabilită pentru mesaje."</string>
<string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Funcția SOS prin satelit nu este acceptată"</string>
<string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Funcția SOS prin satelit nu este acceptată pe acest dispozitiv"</string>
<string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Funcția SOS prin satelit nu este configurată"</string>
@@ -2445,11 +2443,11 @@
<string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Funcția SOS prin satelit nu este disponibilă"</string>
<string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Funcția SOS prin satelit nu este disponibilă în această țară sau regiune"</string>
<string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Funcția SOS prin satelit nu este configurată"</string>
- <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Pentru a trimite mesaje prin satelit, setează Mesaje Google ca aplicație pentru mesaje prestabilită"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Pentru a trimite mesaje prin satelit, setează Mesaje Google ca aplicație prestabilită pentru mesaje"</string>
<string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Funcția SOS prin satelit nu este disponibilă"</string>
<string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Pentru a verifica dacă funcția SOS prin satelit este disponibilă în această țară sau regiune, activează setările privind locația"</string>
<string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Mesajele prin satelit sunt disponibile"</string>
- <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Dacă nu este disponibilă o rețea mobilă sau Wi-Fi, poți să trimiți mesaje prin satelit. Mesaje Google trebuie să fie aplicația ta pentru mesaje prestabilită."</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Dacă nu este disponibilă o rețea mobilă sau Wi-Fi, poți să trimiți mesaje prin satelit. Mesaje Google trebuie să fie aplicația ta prestabilită pentru mesaje."</string>
<string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Mesajele prin satelit nu sunt acceptate"</string>
<string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Mesajele prin satelit nu sunt acceptate pe acest dispozitiv"</string>
<string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Mesajele prin satelit nu sunt configurate"</string>
@@ -2457,7 +2455,7 @@
<string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Mesajele prin satelit nu sunt disponibile"</string>
<string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Mesajele prin satelit nu sunt disponibile în această țară sau regiune"</string>
<string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Mesajele prin satelit nu sunt configurate"</string>
- <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Pentru a trimite mesaje prin satelit, setează Mesaje Google ca aplicație pentru mesaje prestabilită"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Pentru a trimite mesaje prin satelit, setează Mesaje Google ca aplicație prestabilită pentru mesaje"</string>
<string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Mesajele prin satelit nu sunt disponibile"</string>
<string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Pentru a verifica dacă mesajele prin satelit sunt disponibile în această țară sau regiune, activează setările privind locația"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurează din nou Deblocarea cu amprenta"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8caa8b60c120..386830e83e66 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Приложение сможет определять относительное позиционирование устройств с технологией сверхширокополосной связи поблизости"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Взаимодействие с устройствами Wi‑Fi поблизости"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Приложение сможет передавать данные на устройства Wi‑Fi рядом, подключаться к ним и определять их примерное местоположение."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"относительное местоположение устройств поблизости"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Приложение сможет определять относительное местоположение устройств поблизости."</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Сведения о предпочтительном платежном сервисе NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Приложение сможет получать сведения о предпочтительном платежном сервисе NFC (например, зарегистрированные идентификаторы AID и конечный пункт маршрута)."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"Управление NFC-модулем"</string>
@@ -2444,11 +2442,11 @@
<string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Спутниковый SOS не настроен"</string>
<string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Проверьте подключение к интернету и повторите попытку."</string>
<string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Спутниковый SOS недоступен"</string>
- <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Функция недоступна в этой стране или регионе."</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Функция недоступна в стране или в этом регионе."</string>
<string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Спутниковый SOS не настроен"</string>
<string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Чтобы использовать эту функцию, необходимо выбрать Google Сообщения в качестве мессенджера по умолчанию."</string>
<string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Спутниковый SOS недоступен"</string>
- <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Чтобы узнать, можно ли использовать спутниковый SOS в этой стране или регионе, включите настройки геолокации."</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Чтобы узнать, можно ли использовать спутниковый SOS в стране или в этом регионе, включите настройки геолокации."</string>
<string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Доступен спутниковый обмен сообщениями"</string>
<string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Вы можете обмениваться сообщениями по спутниковой связи, даже когда подключение к мобильной сети или Wi-Fi недоступно. Google Сообщения должны быть выбраны в качестве мессенджера по умолчанию."</string>
<string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Спутниковый обмен сообщениями не поддерживается"</string>
@@ -2456,11 +2454,11 @@
<string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Спутниковый обмен сообщениями не настроен"</string>
<string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Проверьте подключение к интернету и повторите попытку."</string>
<string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Спутниковый обмен сообщениями недоступен"</string>
- <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Функция недоступна в этой стране или регионе."</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Функция недоступна в стране или в этом регионе."</string>
<string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Спутниковый обмен сообщениями не настроен"</string>
<string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Чтобы использовать эту функцию, необходимо выбрать Google Сообщения в качестве мессенджера по умолчанию."</string>
<string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Спутниковый обмен сообщениями недоступен"</string>
- <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Чтобы узнать, можно ли обмениваться сообщениями по спутниковой связи в этой стране или регионе, включите настройки геолокации."</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Чтобы узнать, можно ли обмениваться сообщениями по спутниковой связи в стране или в этом регионе, включите настройки геолокации."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Настройте разблокировку по отпечатку пальца заново"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Отпечаток \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" больше нельзя распознать."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Отпечатки \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" и \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" больше нельзя распознать."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index f150cd189f45..e969a8ed523f 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"අවට ඇති අල්ට්‍රා-වයිඩ්බෑන්ඩ් උපාංග අතර සාපේක්ෂ පිහිටීම නිර්ණය කිරීමට යෙදුමට ඉඩ දීම"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"අවට Wi‑Fi උපාංග සමග අන්තර්ක්‍රියා කරන්න"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"වෙළඳ දැන්වීම් පළ කිරීමට, සම්බන්ධ වීමට සහ අවට ඇති Wi-Fi උපාංගවල සාපේක්ෂ පිහිටීම නිර්ණය කිරීමට යෙදුමට ඉඩ දෙයි"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"අවට උපාංග අතර සාපේක්ෂ පිහිටීම තීරණය කරන්න"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"අවට උපාංග අතර සාපේක්ෂ පිහිටීම තීරණය කිරීමට යෙදුමට ඉඩ දෙන්න"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"කැමති NFC ගෙවීම් සේවා තොරතුරු"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"ලියාපදිංචි කළ ආධාර සහ ගමන් මාර්ග ගමනාන්ත වැනි කැමති nfc ගෙවීම් සේවා තොරතුරු ලබා ගැනීමට යෙදුමට ඉඩ දෙයි."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ආසන්න ක්ෂේත්‍ර සන්නිවේදනය පාලනය කරන්න"</string>
@@ -2409,7 +2407,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"යතුරු පුවරුව <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> ලෙස සකසා ඇත… වෙනස් කිරීමට තට්ටු කරන්න."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"භෞතික යතුරු පුවරුව වින්‍යාස කෙරිණි"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"යතුරු පුවරු බැලීමට තට්ටු කරන්න"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"පෞද්ගලික"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"රහසිගත"</string>
<string name="profile_label_clone" msgid="769106052210954285">"ක්ලෝන කරන්න"</string>
<string name="profile_label_work" msgid="3495359133038584618">"කාර්යාලය"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"කාර්යාලය 2"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"ක්‍රියාත්මක කරන්න"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"ආපසු යන්න"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"පොරොත්තුයි..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"චන්ද්‍රිකා SOS දැන් ලබා ගත හැක"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"ජංගම හෝ Wi-Fi ජාලයක් නොමැති නම් ඔබට හදිසි සේවා පණිවිඩ යැවීමට හැක. Google Messages ඔබේ පෙරනිමි පණිවිඩකරණ යෙදුම විය යුතු යි."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"චන්ද්‍රිකා SOS සහාය නොදක්වයි"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"මෙම උපාංගය මත චන්ද්‍රිකා SOS සහාය නොදක්වයි"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"චන්ද්‍රිකා SOS පිහිටුවා නැත"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"ඔබ අන්තර්ජාලයට සම්බන්ධ වී ඇති බවට වග බලා ගෙන නැවත පිහිටුවීමට උත්සාහ කරන්න"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"චන්‍ද්‍රික SOS ලබා ගත නොහැක"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"චන්ද්‍රිකා SOS මෙම රටෙහි හෝ කලාපයෙහි ලබා ගත නොහැක"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"චන්ද්‍රිකා SOS පිහිටුවා නැත"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"චන්ද්‍රිකා මඟින් පණිවිඩ යැවීමට, Google Messages ඔබේ පෙරනිමි පණිවිඩ යැවීමේ යෙදුම ලෙස සකසන්න"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"චන්‍ද්‍රික SOS ලබා ගත නොහැක"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"මෙම රටෙහි හෝ කලාපය තුළ චන්ද්‍රිකා SOS ලබා ගත හැකි දැයි පරීක්ෂා කිරීමට, ස්ථාන සැකසීම් ක්‍රියාත්මක කරන්න"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"චන්ද්‍රිකා පණිවිඩ යැවීම ලබා ගත හැක"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"ජංගම හෝ Wi-Fi ජාලයක් නොමැති නම් ඔබට චන්ද්‍රිකාවෙන් පණිවිඩයක් යැවිය හැක. Google Messages ඔබේ පෙරනිමි පණිවිඩකරණ යෙදුම විය යුතු යි."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"චන්ද්‍රිකා පණිවිඩ යැවීමට සහය නොදක්වයි"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"මෙම උපාංගය මත චන්ද්‍රිකා පණිවිඩ යැවීමට සහය නොදක්වයි"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"චන්ද්‍රිකා පණිවිඩ යැවීම පිහිටුවා නැත"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"ඔබ අන්තර්ජාලයට සම්බන්ධ වී ඇති බවට වග බලා ගෙන නැවත පිහිටුවීමට උත්සාහ කරන්න"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"චන්ද්‍රිකා පණිවිඩ යැවීම ලබා ගත නොහැක"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"චන්ද්‍රිකා පණිවිඩ යැවීම මෙම රටෙහි හෝ කලාපයෙහි ලබා ගත නොහැක"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"චන්ද්‍රිකා පණිවිඩ යැවීම පිහිටුවා නැත"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"චන්ද්‍රිකා මඟින් පණිවිඩ යැවීමට, Google Messages ඔබේ පෙරනිමි පණිවිඩ යැවීමේ යෙදුම ලෙස සකසන්න"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"චන්ද්‍රිකා පණිවිඩ යැවීම ලබා ගත නොහැක"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"මෙම රටෙහි හෝ කලාපය තුළ චන්ද්‍රිකා පණිවිඩ යැවීම ලබා ගත හැකි දැයි පරීක්ෂා කිරීමට, ස්ථාන සැකසීම් ක්‍රියාත්මක කරන්න"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ඇඟිලි සලකුණු අගුලු හැරීම නැවත සකසන්න"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> තවදුරටත් හඳුනා ගත නොහැක."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> සහ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> තවදුරටත් හඳුනා ගත නොහැක."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e17e25f4734d..d211d8c481f7 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Povoľte aplikácii určovať relatívnu polohu medzi zariadeniami s ultraširokopásmovým pripojením v okolí"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interakcia so zariadeniami Wi-Fi v okolí"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Umožňuje aplikácii oznamovať a rozpoznávať relatívnu polohu zariadení Wi‑Fi v okolí a pripájať sa k nim"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"určovať relatívnu polohu medzi zariadeniami v okolí"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Povoľte aplikácii určovať relatívnu polohu medzi zariadeniami v okolí"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Preferované informácie platenej služby NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Umožňuje aplikácii získavať preferované informácie platenej služby NFC, napríklad o registrovanej pomoci a trasách k cieľu."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ovládať technológiu NFC"</string>
@@ -2437,54 +2435,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Zapnúť"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Prejsť späť"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Nespracovaná…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Pomoc cez satelit je teraz k dispozícii"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Tiesňovej linke môžete poslať správu, keď nie je dostupná mobilná sieť ani sieť Wi‑Fi. Správy Google musíte mať nastavené ako predvolený komunikátor."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Pomoc cez satelit nie je podporovaná"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Pomoc cez satelit nie je v tomto zariadení podporovaná"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Pomoc cez satelit nie je nastavená"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Skontrolujte, či máte internetové pripojenie, a skúste nastavenie zopakovať"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Pomoc cez satelit nie je k dispozícii"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Pomoc cez satelit nie je v tejto krajine alebo regióne k dispozícii"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Pomoc cez satelit nie je nastavená"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Ak chcete posielať správy cez satelit, nastavte Správy Google ako predvolený komunikátor"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Pomoc cez satelit nie je k dispozícii"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Ak chcete skontrolovať, či je pomoc cez satelit v tejto krajine alebo regióne k dispozícii, zapnite nastavenia polohy"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Správy cez satelit sú k dispozícii"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Keď nie je dostupná mobilná sieť ani sieť Wi‑Fi, môžete posielať správy cez satelit. Správy Google musíte mať nastavené ako predvolený komunikátor."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Správy cez satelit nie sú podporované"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Správy cez satelit nie sú v tomto zariadení podporované"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Správy cez satelit nie sú nastavené"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Skontrolujte, či máte internetové pripojenie, a skúste nastavenie zopakovať"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Správy cez satelit nie sú k dispozícii"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Správy cez satelit nie sú v tejto krajine alebo regióne k dispozícii"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Správy cez satelit nie sú nastavené"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Ak chcete posielať správy cez satelit, nastavte Správy Google ako predvolený komunikátor"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Správy cez satelit nie sú k dispozícii"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Ak chcete skontrolovať, či sú správy cez satelit v tejto krajine alebo regióne k dispozícii, zapnite nastavenia polohy"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Znova nastavte odomknutie odtlačkom prsta"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> sa už nedari rozpoznať."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> sa už nedari rozpoznať."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index da9f1c189610..ca854340fc43 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Aplikaciji dovoli, da določi relativno oddaljenost med napravami UWB v bližini."</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"komunikacija z napravami Wi‑Fi v bližini"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Aplikaciji dovoljuje objavljanje in določanje relativnega položaja naprav Wi‑Fi v bližini ter povezovanje z njimi."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"določanje relativne oddaljenosti med napravami v bližini"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Aplikaciji dovoli, da določi relativno oddaljenost med napravami v bližini"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Podatki o prednostni storitvi za plačevanje prek povezave NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Aplikaciji omogoča pridobivanje podatkov o prednostni storitvi za plačevanje prek povezave NFC, kot so registrirani pripomočki in cilj preusmeritve."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"nadzor nad komunikacijo s tehnologijo bližnjega polja"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 1b8d0a0095f3..45cf31a9b0e8 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Lejo që aplikacioni të përcaktojë pozicionin e përafërt mes pajisjeve në afërsi me brezin ultra të gjerë"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"të ndërveprojë me pajisjet Wi-Fi në afërsi"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Lejon që aplikacioni të reklamojë, të lidhet dhe të përcaktojë pozicionin përkatës të pajisjeve Wi-Fi në afërsi"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"të përcaktojë pozicionin e përafërt mes pajisjeve në afërsi"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Lejo që aplikacioni të përcaktojë pozicionin e përafërt mes pajisjeve në afërsi"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informacionet për shërbimin e preferuar të pagesës me NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Lejon aplikacionin të marrë informacione për shërbimin e preferuar të pagesës me NFC si p.sh. ndihmat e regjistruara dhe destinacionin e itinerarit."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrollo \"Komunikimin e fushës në afërsi\" NFC"</string>
@@ -2186,7 +2184,7 @@
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth-i do të qëndrojë i aktivizuar gjatë modalitetit të aeroplanit"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Po ngarkohet"</string>
<string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # skedar}other{{file_name} + # skedarë}}"</string>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Nuk ka persona të rekomanduar për ta ndarë"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Nuk ka persona të rekomanduar për të ndarë"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista e aplikacioneve"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Këtij aplikacioni nuk i është dhënë leje për regjistrim, por mund të regjistrojë audio përmes kësaj pajisjeje USB."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Ekrani bazë"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Aktivizo"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Kthehu prapa"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Në pritje..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"\"SOS satelitor\" ofrohet tani"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Mund t\'u dërgosh mesazhe shërbimeve të urgjencës nëse nuk ka rrjet celular ose Wi-Fi. \"Mesazhet e Google\" duhet të jenë aplikacioni yt i parazgjedhur i mesazheve."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"\"SOS satelitor\" nuk mbështetet"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"\"SOS satelitor\" nuk mbështetet në këtë pajisje"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"\"SOS satelitor\" nuk është konfiguruar"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Sigurohu që të jesh lidhur me internetin dhe provo përsëri konfigurimin"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"\"SOS satelitor\" nuk ofrohet"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"\"SOS satelitor\" nuk ofrohet në këtë shtet ose rajon"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"\"SOS satelitor\" nuk është konfiguruar"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Për të shkëmbyer mesazhe nëpërmjet satelitit, cakto \"Mesazhet e Google\" si aplikacionin e parazgjedhur të mesazheve"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"\"SOS satelitor\" nuk ofrohet"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Për të kontrolluar nëse \"SOS satelitor\" ofrohet në këtë shtet ose rajon, aktivizo cilësimet e vendndodhjes"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Ofrohet shkëmbimi i mesazheve nëpërmjet satelitit"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Mund të shkëmbesh mesazhe nëpërmjet satelitit nëse nuk ka rrjet celular ose Wi-Fi. \"Mesazhet e Google\" duhet të jenë aplikacioni yt i parazgjedhur i mesazheve."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Shkëmbimi i mesazheve nëpërmjet satelitit nuk mbështetet"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Shkëmbimi i mesazheve nëpërmjet satelitit nuk mbështetet në këtë pajisje"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Shkëmbimi i mesazheve nëpërmjet satelitit nuk është konfiguruar"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Sigurohu që të jesh lidhur me internetin dhe provo përsëri konfigurimin"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Shkëmbimi i mesazheve nëpërmjet satelitit nuk ofrohet"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Shkëmbimi i mesazheve nëpërmjet satelitit nuk ofrohet në këtë shtet ose rajon"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Shkëmbimi i mesazheve nëpërmjet satelitit nuk është konfiguruar"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Për të shkëmbyer mesazhe nëpërmjet satelitit, cakto \"Mesazhet e Google\" si aplikacionin e parazgjedhur të mesazheve"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Shkëmbimi i mesazheve nëpërmjet satelitit nuk ofrohet"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Për të kontrolluar nëse shkëmbimi i mesazheve nëpërmjet satelitit ofrohet në këtë shtet ose rajon, aktivizo cilësimet e vendndodhjes"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfiguro përsëri \"Shkyçjen me gjurmën e gishtit\""</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> nuk mund të njihet më."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dhe <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nuk mund të njihen më."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index bdf557173391..5a3bae0012bc 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -613,10 +613,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Дозвољава апликацији да одређује релативну раздаљину између уређаја ултра-широког појаса у близини"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"интеракција са WiFi уређајима у близини"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Дозвољава апликацији да се оглашава, повезује и утврђује релативну позицију WiFi уређаја у близини"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"одређивање раздаљине између уређаја у близини"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Дозволите апликацији да одређује релативну раздаљину између уређаја у близини"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Информације о жељеној NFC услузи за плаћање"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Дозвољава апликацији да преузима информације о жељеној NFC услузи за плаћање, попут регистрованих идентификатора апликација и одредишта преусмеравања."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"контрола комуникације у ужем пољу (Near Field Communication)"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8bef5ca8a842..fde90235e6ee 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Tillåt att appen fastställer den relativa positionen mellan Ultra Wideband-enheter i närheten"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagera med wifi-enheter i närheten"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Tillåter appen att sända ut till, ansluta till och fastställa relativ position för wifi-enheter i närheten"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"fastställa relativ position för enheter i närheten"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Tillåt att appen fastställer den relativa positionen mellan enheter i närheten"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Information kopplad till standardtjänsten för NFC-betalning"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Tillåter att appen hämtar information kopplad till standardtjänsten för NFC-betalning, till exempel registrerade hjälpmedel och ruttdestinationer."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrollera närfältskommunikationen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 010415eaf313..2a62c87d16d9 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Ruhusu programu ibainishe nafasi kati ya vifaa vyenye Bendi Pana Zaidi vilivyo karibu"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"tumia vifaa vya Wi‑Fi vilivyo karibu"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Huruhusu programu kutangaza, kuunganisha na kubaini mahali palipokadiriwa vilipo vifaa vya Wi-Fi vilivyo karibu"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"kubainisha nafasi kati ya vifaa vilivyo karibu"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Ruhusu programu ibainishe nafasi kati ya vifaa vilivyo karibu"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Maelezo ya Huduma Inayopendelewa ya Malipo ya NFC"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Huruhusu programu kupata maelezo ya huduma inayopendelewa ya malipo ya nfc kama vile huduma zilizosajiliwa na njia."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kudhibiti Mawasiliano ya Vifaa Vilivyokaribu (NFC)"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Washa"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Rudi nyuma"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Inashughulikiwa..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Kipengele cha Msaada kupitia Setilaiti sasa kinapatikana"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Unaweza kutumia huduma za dharura ujumbe iwapo hakuna mtandao wa simu au wa Wi-Fi. Ni sharti uweke Google Messages iwe programu yako chaguomsingi ya kutuma ujumbe."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Kipengele cha Msaada kupitia Setilaiti hakiwezi kutumika"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Kipengele cha Msaada kupitia Setilaiti hakiwezi kutumika kwenye kifaa hiki"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Mipangilio ya kipengele cha Msaada kupitia Setilaiti haijawekwa"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Hakikisha kuwa umeunganisha kifaa chako kwenye intaneti kisha ujaribu kuweka mipangilio tena"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Kipengele cha Msaada kupitia Setilaiti hakipatikani"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Kipengele cha Msaada kupitia Setilaiti hakipatikani katika nchi au eneo hili"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Mipangilio ya kipengele cha Msaada kupitia Setilaiti haijawekwa"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Ili utume ujumbe kupitia setilaiti, weka Google Messages iwe programu yako chaguomsingi ya kutuma ujumbe"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Kipengele cha Msaada kupitia Setilaiti hakipatikani"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Ili uangalie iwapo kipengele cha Msaada kupitia Setilaiti kinapatikana katika nchi au eneo hili, washa mipangilio ya mahali"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Kipengele cha kutuma ujumbe kupitia setilaiti kinapatikana"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Unaweza kutuma ujumbe kupitia setilaiti iwapo hakuna mtandao wa simu au wa Wi-Fi. Ni sharti uweke Google Messages iwe programu yako chaguomsingi ya kutuma ujumbe."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Kipengele cha kutuma ujumbe kupitia setilaiti hakiwezi kutumika"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Kipengele cha kutuma ujumbe kupitia setilaiti hakiwezi kutumika kwenye kifaa hiki"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Mipangilio ya kutuma ujumbe kupitia setilaiti haijawekwa"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Hakikisha kuwa umeunganisha kifaa chako kwenye intaneti kisha ujaribu kuweka mipangilio tena"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Kipengele cha kutuma ujumbe kupitia setilaiti hakipatikani"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Kipengele cha kutuma ujumbe kupitia setilaiti hakipatikani katika nchi au eneo hili"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Mipangilio ya kutuma ujumbe kupitia setilaiti haijawekwa"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Ili utume ujumbe kupitia setilaiti, weka Google Messages iwe programu yako chaguomsingi ya kutuma ujumbe"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Kipengele cha kutuma ujumbe kupitia setilaiti hakipatikani"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Ili uangalie iwapo kipengele cha kutuma ujumbe kupitia setilaiti kinapatikana katika nchi au eneo hili, washa mipangilio ya mahali"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Weka tena mipangilio ya Kufungua kwa Alama ya Kidole"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> haitambuliki tena."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> na <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> havitambuliki tena."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 1915f2982611..6ff96c00ea8d 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"அருகிலுள்ள அல்ட்ரா-வைடுபேண்ட் சாதனங்களுக்கிடையிலான தூரத்தைத் தீர்மானிக்க ஆப்ஸை அனுமதிக்கும்"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"அருகிலுள்ள வைஃபை சாதனங்களுடன் தொடர்பு கொள்ளுதல்"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"அருகிலுள்ள வைஃபை சாதனங்களைத் தெரியப்படுத்தவும் இணைக்கவும் இருப்பிடத்தைத் தீர்மானிக்கவும் இது ஆப்ஸை அனுமதிக்கும்"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"அருகிலுள்ள சாதனங்களுக்கான தூரத்தைத் தீர்மானித்தல்"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"அருகிலுள்ள சாதனங்களுக்கு இடையிலான தூரத்தைத் தீர்மானிக்க ஆப்ஸை அனுமதிக்கும்"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"விருப்பமான NFC பேமெண்ட் சேவை தொடர்பான தகவல்கள்"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"பதிவுசெய்யப்பட்ட கருவிகள், சேருமிடத்திற்கான வழி போன்ற விருப்பமான NFC பேமெண்ட் சேவை தொடர்பான தகவல்களைப் பெற ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"குறுகிய இடைவெளி தகவல்பரிமாற்றத்தைக் கட்டுப்படுத்துதல்"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"இயக்கு"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"பின்செல்"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"நிலுவையிலுள்ளது..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"சாட்டிலைட் SOS அம்சம் இப்போது கிடைக்கிறது"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"மொபைல்/வைஃபை நெட்வொர்க் இல்லையென்றால், அவசரகால சேவைகளுக்கு மெசேஜ் அனுப்பலாம். Google Messages உங்கள் இயல்புநிலை மெசேஜிங் ஆப்ஸாக இருக்க வேண்டும்."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"சாட்டிலைட் SOS ஆதரிக்கப்படவில்லை"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"இந்தச் சாதனத்தில் சாட்டிலைட் SOS ஆதரிக்கப்படவில்லை"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"சாட்டிலைட் SOS அமைக்கப்படவில்லை"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"இணையத்துடன் இணைக்கப்பட்டிருப்பதை உறுதிசெய்துகொண்டு மீண்டும் அமைக்க முயலுங்கள்"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"சாட்டிலைட் SOS கிடைக்கவில்லை"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"இந்த நாடு/பிராந்தியத்தில் சாட்டிலைட் SOS கிடைக்கவில்லை"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"சாட்டிலைட் SOS அமைக்கப்படவில்லை"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"சாட்டிலைட் மூலம் மெசேஜ் செய்ய, Google Messages ஆப்ஸை உங்கள் இயல்புநிலை மெசேஜிங் ஆப்ஸாக அமையுங்கள்"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"சாட்டிலைட் SOS கிடைக்கவில்லை"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"இந்த நாட்டிலோ பிராந்தியத்திலோ சாட்டிலைட் SOS கிடைக்கிறதா எனப் பார்க்க இருப்பிட அமைப்புகளை இயக்குங்கள்"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"சாட்டிலைட் மெசேஜிங் கிடைக்கிறது"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"மொபைல்/வைஃபை நெட்வொர்க் இல்லையென்றால் சாட்டிலைட் மூலம் மெசேஜ் அனுப்பலாம். Google Messages உங்கள் இயல்புநிலை மெசேஜிங் ஆப்ஸாக இருக்க வேண்டும்."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"சாட்டிலைட் மெசேஜிங் ஆதரிக்கப்படவில்லை"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"இந்தச் சாதனத்தில் சாட்டிலைட் மெசேஜிங் ஆதரிக்கப்படவில்லை"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"சாட்டிலைட் மெசேஜிங் அமைக்கப்படவில்லை"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"இணையத்துடன் இணைக்கப்பட்டிருப்பதை உறுதிசெய்துகொண்டு மீண்டும் அமைக்க முயலுங்கள்"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"சாட்டிலைட் மெசேஜிங் கிடைக்கவில்லை"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"இந்த நாடு/பிராந்தியத்தில் சாட்டிலைட் மெசேஜிங் கிடைக்கவில்லை"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"சாட்டிலைட் மெசேஜிங் அமைக்கப்படவில்லை"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"சாட்டிலைட் மூலம் மெசேஜ் செய்ய, Google Messages ஆப்ஸை உங்கள் இயல்புநிலை மெசேஜிங் ஆப்ஸாக அமையுங்கள்"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"சாட்டிலைட் மெசேஜிங் கிடைக்கவில்லை"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"இந்த நாட்டிலோ பிராந்தியத்திலோ சாட்டிலைட் மெசேஜிங் கிடைக்கிறதா எனப் பார்க்க இருப்பிட அமைப்புகளை இயக்குங்கள்"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"கைரேகை அன்லாக் அம்சத்தை மீண்டும் அமையுங்கள்"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>ஐ இனி அடையாளம் காண முடியாது."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ஆகியவற்றை இனி அடையாளம் காண முடியாது."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6ac81642d41f..68fce1f8175a 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -354,7 +354,7 @@
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"మీరు టైప్ చేస్తున్న వచనాన్ని పరిశీలిస్తుంది"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"క్రెడిట్ కార్డు నంబర్‌లు మరియు పాస్‌వర్డ్‌ల వంటి వ్యక్తిగత డేటాను కలిగి ఉంటుంది."</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"డిస్‌ప్లే మ్యాగ్నిఫికేషన్‌ను నియంత్రించండి"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"డిస్‌ప్లే జూమ్ స్థాయి మరియు స్థానాన్ని నియంత్రిస్తుంది."</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"డిస్‌ప్లే జూమ్ స్థాయి మరియు లొకేషన్‌ని నియంత్రిస్తుంది."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"సంజ్ఞలను చేయడం"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"నొక్కగలరు, స్వైప్ చేయగలరు, స్క్రీన్‌పై రెండు వేళ్లను ఉంచి ఆ వేళ్లను దగ్గరకు లేదా దూరానికి లాగగలరు మరియు ఇతర సంజ్ఞలను చేయగలరు."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"వేలిముద్ర సంజ్ఞలు"</string>
@@ -608,14 +608,12 @@
<string name="permdesc_bluetooth_connect" product="default" msgid="4546016548795544617">"పెయిర్ చేసిన బ్లూటూత్ పరికరాలకు కనెక్ట్ అవ్వడానికి యాప్‌ను అనుమతిస్తుంది"</string>
<string name="permlab_bluetooth_advertise" msgid="2781147747928853177">"సమీపంలోని బ్లూటూత్ పరికరాలలో అడ్వర్టయిజ్ చేయండి"</string>
<string name="permdesc_bluetooth_advertise" product="default" msgid="6085174451034210183">"సమీపంలోని బ్లూటూత్ పరికరాలలో అడ్వర్టయిజ్ చేయడానికి యాప్‌కు అనుమతిని ఇస్తుంది"</string>
- <string name="permlab_uwb_ranging" msgid="8141915781475770665">"సమీపంలోని అల్ట్రా-వైడ్‌బ్యాండ్ పరికరాల మధ్య సాపేక్ష స్థానాన్ని నిర్ణయించండి"</string>
- <string name="permdesc_uwb_ranging" msgid="2519723069604307055">"సమీపంలోని అల్ట్రా-వైడ్‌బ్యాండ్ పరికరాల మధ్య సాపేక్ష స్థానాన్ని నిర్ణయించడానికి యాప్‌ను అనుమతించండి"</string>
+ <string name="permlab_uwb_ranging" msgid="8141915781475770665">"సమీపంలోని అల్ట్రా-వైడ్‌బ్యాండ్ పరికరాల మధ్య సంబంధిత పొజిషన్‌ను నిర్ణయించండి"</string>
+ <string name="permdesc_uwb_ranging" msgid="2519723069604307055">"సమీపంలోని అల్ట్రా-వైడ్‌బ్యాండ్ పరికరాల మధ్య సంబంధిత పొజిషన్‌ను నిర్ణయించడానికి యాప్‌ను అనుమతించండి"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"సమీపంలోని Wi-Fi పరికరాలతో ఇంటరాక్ట్ చేస్తుంది"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"అడ్వర్టయిజ్, కనెక్ట్ చేయడానికి, సమీపంలోని Wi-Fi పరికరాల సంబంధిత పొజిషన్‌ను నిర్ణయించడానికి యాప్‌ను అనుమతిస్తుంది"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"సమీపంలో పరికరాల మధ్య సాపేక్ష స్థానాన్ని నిర్ణయించండి"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"సమీపంలోని పరికరాల మధ్య సాపేక్ష స్థానాన్ని నిర్ణయించడానికి యాప్‌ను అనుమతించండి"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ప్రాధాన్యత ఇవ్వబడిన NFC చెల్లింపు సేవల సమాచారం"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"ప్రాధాన్యత ఇవ్వబడిన NFC చెల్లింపు సేవల సమాచారాన్ని, అంటే రిజిస్టర్ చేయబడిన సహాయక సాధనాలు, మార్గం, గమ్యస్థానం వంటి వాటిని పొందేందుకు యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"సమీప క్షేత్ర కమ్యూనికేషన్‌ను నియంత్రించడం"</string>
@@ -724,7 +722,7 @@
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"బాగా కదుపుతున్నారు. ఫోన్‌ను స్థిరంగా పట్టుకోండి"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"దయచేసి మీ ముఖాన్ని మళ్లీ నమోదు చేయండి."</string>
<string name="face_acquired_too_different" msgid="4505278456634706967">"ముఖం గుర్తించబడలేదు. మళ్లీ ట్రై చేయండి."</string>
- <string name="face_acquired_too_similar" msgid="8882920552674125694">"మీ తల స్థానాన్ని కొద్దిగా మార్చండి"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"మీ తల లొకేషన్‌ను కొద్దిగా మార్చండి"</string>
<string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string>
<string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string>
<string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"ఆన్ చేయండి"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"వెనుకకు వెళ్లండి"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"పెండింగ్‌లో ఉంది..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"ఎమర్జెన్సీ శాటిలైట్ సహాయం ఇప్పుడు అందుబాటులో ఉంది"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"మొబైల్ లేదా Wi-Fi నెట్‌వర్క్ ఏదీ లేనట్లయితే మీరు ఎమర్జెన్సీ సర్వీసులకు మెసేజ్ చేయవచ్చు. Google Messages అనేది తప్పనిసరిగా మీ ఆటోమేటిక్ మెసేజింగ్ యాప్‌గా సెట్ చేసి ఉండాలి."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"ఎమర్జెన్సీ శాటిలైట్ సహాయం సపోర్ట్ చేయదు"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"ఈ పరికరంలో ఎమర్జెన్సీ శాటిలైట్ సహాయం సపోర్ట్ చేయదు"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"ఎమర్జెన్సీ శాటిలైట్ సహాయం సెటప్ కాలేదు"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"మీరు ఇంటర్నెట్‌కు కనెక్ట్ అయి ఉన్నారని నిర్ధారించుకుని, మళ్లీ సెటప్‌ను ట్రై చేయండి"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో లేదు"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"ఈ దేశంలో లేదా ప్రాంతంలో ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో లేదు"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"ఎమర్జెన్సీ శాటిలైట్ సహాయం సెటప్ చేయలేదు"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"శాటిలైట్ ద్వారా మెసేజ్ చేయడానికి, Google Messagesను మీ ఆటోమేటిక్ సెట్టింగ్ మెసేజింగ్ యాప్‌గా సెట్ చేయండి"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో లేదు"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"ఈ దేశంలో లేదా ప్రాంతంలో ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో ఉందో లేదో చెక్ చేయడానికి, లొకేషన్ సెట్టింగ్‌లను ఆన్ చేయండి"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"శాటిలైట్ మెసేజింగ్ అందుబాటులో ఉంది"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"మొబైల్ లేదా Wi-Fi నెట్‌వర్క్ లేకుంటే మీరు శాటిలైట్ ద్వారా మెసేజ్‌ను పంపవచ్చు. Google Messages అనేది తప్పనిసరిగా మీ ఆటోమేటిక్ మెసేజింగ్ యాప్‌గా సెట్ చేసి ఉండాలి."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"శాటిలైట్ మెసేజింగ్ సపోర్ట్ చేయదు"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"ఈ పరికరంలో శాటిలైట్ మెసేజింగ్ సపోర్ట్ చేయదు"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"శాటిలైట్ మెసేజింగ్‌ను సెటప్ చేయలేదు"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"మీరు ఇంటర్నెట్‌కు కనెక్ట్ అయి ఉన్నారని నిర్ధారించుకుని, మళ్లీ సెటప్‌ను ట్రై చేయండి"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"శాటిలైట్ మెసేజింగ్ అందుబాటులో లేదు"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"ఈ దేశంలో లేదా ప్రాంతంలో శాటిలైట్ మెసేజింగ్ అందుబాటులో లేదు"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"శాటిలైట్ మెసేజింగ్‌ను సెటప్ చేయలేదు"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"శాటిలైట్ ద్వారా మెసేజ్ చేయడానికి, Google Messagesను మీ ఆటోమేటిక్ సెట్టింగ్ మెసేజింగ్ యాప్‌గా సెట్ చేయండి"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"శాటిలైట్ మెసేజింగ్ అందుబాటులో లేదు"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"ఈ దేశంలో లేదా ప్రాంతంలో శాటిలైట్ మెసేజింగ్ అందుబాటులో ఉందో లేదో చెక్ చేయడానికి, లొకేషన్ సెట్టింగ్‌లను ఆన్ చేయండి"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"వేలిముద్ర అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>‌ను ఇకపై గుర్తించడం సాధ్యం కాదు."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>‌లను ఇకపై గుర్తించడం సాధ్యం కాదు."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 763eb6266198..178a76d3a404 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"อนุญาตให้แอประบุตำแหน่งสัมพันธ์ระหว่างอุปกรณ์ที่ใช้แถบความถี่กว้างยิ่งยวดซึ่งอยู่ใกล้เคียง"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"โต้ตอบกับอุปกรณ์ Wi-Fi ที่อยู่ใกล้เคียง"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"อนุญาตให้แอปแสดงข้อมูล เชื่อมต่อ และระบุตำแหน่งซึ่งสัมพันธ์กับอุปกรณ์ Wi-Fi ที่อยู่ใกล้เคียง"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"ระบุตำแหน่งสัมพันธ์ระหว่างอุปกรณ์ที่อยู่ใกล้เคียง"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"อนุญาตให้แอประบุตำแหน่งสัมพันธ์ระหว่างอุปกรณ์ที่อยู่ใกล้เคียง"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"ข้อมูลบริการชำระเงิน NFC ที่ต้องการ"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"อนุญาตให้แอปรับข้อมูลบริการชำระเงิน NFC ที่ต้องการ เช่น รหัสแอป (AID) ที่ลงทะเบียนและปลายทางของเส้นทาง"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"ควบคุม Near Field Communication"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b44faae4e84f..8e3c5e7433a7 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Payagan ang app na tukuyin ang relatibong posisyon sa pagitan ng mga kalapit na Ultra-Wideband device"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"makipag-ugnayan sa mga kalapit na Wi‑Fi device"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Nagbibigay-daan sa app na i-advertise ang, kumonekta sa, at tukuyin ang nauugnay na posisyon ng mga kalapit na Wi‑Fi device"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"alamin ang relative position sa kalapit na device"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Payagan ang app na alamin ang relatibong posisyon sa pagitan ng mga kalapit na device"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Impormasyon sa Gustong NFC na Serbisyo sa Pagbabayad"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Pinapayagan ang app na makakuha ng impormasyon sa gustong nfc na serbisyo sa pagbabayad tulad ng mga nakarehistrong application ID at destinasyon ng ruta."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kontrolin ang Near Field Communication"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e54b8999a1dc..98b1dd3ef245 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Uygulamanın, yakındaki Ultra Geniş Bant cihazların birbirine göre konumunu belirlemesine izin verin"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"yakındaki kablosuz cihazlarla etkileşim kur"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Uygulamanın reklam sunmasına, bağlanmasına ve yakındaki kablosuz cihazların göreli konumunu belirlemesine izin verir"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"yakındaki cihazların göreli konumunu belirleme"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Uygulamanın, yakındaki cihazların birbirine göre konumunu belirlemesine izin verin"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Tercih Edilen NFC Ödeme Hizmeti Bilgileri"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Uygulamaya, kayıtlı yardımlar ve rota hedefi gibi tercih edilen NFC ödeme hizmeti bilgilerini alma izni verir."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"Yakın Alan İletişimini denetle"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Etkinleştir"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Geri dön"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Bekliyor..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Acil Uydu Bağlantısı kullanıma sunuldu"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Mobil veya kablosuz ağ bağlantısı yoksa acil durum hizmetleriyle mesajlaşabilirsiniz. Google Mesajlar varsayılan mesajlaşma uygulamanız olmalıdır."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Acil Uydu Bağlantısı desteklenmiyor"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Acil Uydu Bağlantısı bu cihazda desteklenmiyor"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Acil Uydu Bağlantısı özelliği ayarlanmamış"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"İnternete bağlı olup olmadığınızı kontrol edip tekrar ayarlamayı deneyin"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Acil Uydu Bağlantısı kullanılamıyor"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Acil Uydu Bağlantısı özelliği bu ülkede veya bölgede kullanıma sunulmamıştır"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Acil Uydu Bağlantısı özelliği ayarlanmamış"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Uydu üzerinden mesajlaşmak için Google Mesajlar\'ı varsayılan mesajlaşma uygulamanız olarak ayarlayın"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Acil Uydu Bağlantısı kullanılamıyor"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Acil Uydu Bağlantısı özelliğinin bu ülkede veya bölgede kullanılıp kullanılamadığını kontrol etmek için konum ayarlarını açın"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Uydu üzerinden mesajlaşma özelliği kullanılabilir"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Mobil veya kablosuz ağ bağlantısı yoksa uydu üzerinden mesaj gönderebilirsiniz. Google Mesajlar varsayılan mesajlaşma uygulamanız olmalıdır."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Uydu üzerinden mesajlaşma desteklenmiyor"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Uydu üzerinden mesajlaşma bu cihazda desteklenmiyor"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Uydu üzerinden mesajlaşma özelliği ayarlanmamış"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"İnternete bağlı olup olmadığınızı kontrol edip tekrar ayarlamayı deneyin"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Uydu üzerinden mesajlaşma özelliği kullanılamıyor"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Uydu üzerinden mesajlaşma özelliği bu ülkede veya bölgede kullanılamıyor"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Uydu üzerinden mesajlaşma özelliği ayarlanmamış"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Uydu üzerinden mesajlaşmak için Google Mesajlar\'ı varsayılan mesajlaşma uygulamanız olarak ayarlayın"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Uydu üzerinden mesajlaşma özelliği kullanılamıyor"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Uydu üzerinden mesajlaşma özelliğinin bu ülkede veya bölgede kullanılıp kullanılamadığını kontrol etmek için konum ayarlarını açın"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Parmak İzi Kilidi\'ni tekrar kurun"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> artık tanınamayacak."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ve <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> artık tanınamayacak."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 344cb28afcb2..d5e6bd81ffcc 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -614,10 +614,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"З цим дозволом додаток може визначати відстань між розташованими поблизу пристроями з надширокосмуговим зв’язком"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"взаємодіяти з пристроями Wi‑Fi поблизу"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Додаток може виявляти пристрої Wi‑Fi поблизу, підключатися до них і визначати їх відносне розташування"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"визначати відстань між пристроями поблизу"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Із цим дозволом додаток може визначати відстань між розташованими поблизу пристроями"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Використання інформації з платіжного NFC-сервісу"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Дозволяє додатку отримувати доступ до інформації потрібного платіжного NFC-сервісу (наприклад, пов\'язаних ідентифікаторів чи даних про маршрутизацію трансакцій)."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"контрол. Near Field Communication"</string>
@@ -2437,54 +2435,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Увімкнути"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Назад"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Обробка…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Супутниковий сигнал SOS тепер доступний"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Ви можете надсилати повідомлення службам екстреної допомоги, якщо немає з’єднання з Wi-Fi або мобільною мережею. Потрібно зробити Google Повідомлення додатком для обміну повідомленнями за умовчанням."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Супутниковий сигнал SOS не підтримується"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Супутниковий сигнал SOS не підтримується на цьому пристрої"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Супутниковий сигнал SOS не налаштовано"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Переконайтеся, що пристрій підключено до Інтернету, і повторіть спробу налаштування"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Супутниковий сигнал SOS недоступний"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Супутниковий сигнал SOS недоступний у цій країні або регіоні"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Супутниковий сигнал SOS не налаштовано"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Щоб обмінюватися повідомленнями через супутник, потрібно зробити Google Повідомлення додатком для обміну повідомленнями за умовчанням"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Супутниковий сигнал SOS недоступний"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Щоб дізнатися, чи доступний супутниковий сигнал SOS у цій країні або регіоні, увімкніть доступ до геоданих"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Доступний супутниковий обмін повідомленнями"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Ви можете надсилати й отримувати повідомлення через супутник, якщо немає з’єднання з Wi-Fi або мобільною мережею. Потрібно зробити Google Повідомлення додатком для обміну повідомленнями за умовчанням."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Супутниковий обмін повідомленнями не підтримується"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Супутниковий обмін повідомленнями не підтримується на цьому пристрої"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Супутниковий обмін повідомленнями не налаштовано"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Переконайтеся, що пристрій підключено до Інтернету, і повторіть спробу налаштування"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Супутниковий обмін повідомленнями недоступний"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Супутниковий обмін повідомленнями недоступний у цій країні або регіоні"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Супутниковий обмін повідомленнями не налаштовано"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Щоб обмінюватися повідомленнями через супутник, потрібно зробити Google Повідомлення додатком для обміну повідомленнями за умовчанням"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Супутниковий обмін повідомленнями недоступний"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Щоб дізнатися, чи доступний супутниковий обмін повідомленнями в цій країні або регіоні, увімкніть доступ до геоданих"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Налаштуйте розблокування відбитком пальця повторно"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Відбиток пальця <xliff:g id="FINGERPRINT">%s</xliff:g> більше не розпізнається."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Відбитки пальців <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> і <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> більше не розпізнаються."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 45e1a2347dbb..b26b1c102abc 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"ایپ کو قریبی الٹرا وائڈ بینڈ آلات کے مابین متعلقہ پوزیشن کا تعین کرنے کی اجازت دیں"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"‏قریبی Wi-Fi آلات کے ساتھ تعامل کریں"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"‏ایپ کو اشتہار دینے، منسلک کرنے اور قریبی Wi-Fi آلات کی متعلقہ پوزیشن کا تعین کرنے کی اجازت دیتا ہے"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"قریبی آلات کے مابین متعلقہ پوزیشن کا تعین کریں"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"ایپ کو قریبی آلات کے مابین متعلقہ پوزیشن کا تعین کرنے کی اجازت دیں"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"‏ترجیح شدہ NFC ادائیگی کی سروس کی معلومات"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"‏ایپ کو رجسٹرشدہ ایڈز اور روٹ ڈسٹنیشن جیسی ترجیح شدہ nfc ادائیگی سروس کی معلومات حاصل کرنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"‏Near Field کمیونیکیشن کنٹرول کریں"</string>
@@ -2409,7 +2407,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"کی بورڈ لے آؤٹ <xliff:g id="LAYOUT_1">%1$s</xliff:g>، <xliff:g id="LAYOUT_2">%2$s</xliff:g>، <xliff:g id="LAYOUT_3">%3$s</xliff:g> پر سیٹ ہے… تبدیل کرنے کے لیے تھپتھپائیں۔"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"فزیکل کی بورڈز کنفیگر کئے گئے"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"کی بورڈز دیکھنے کے لیے تھپتھپائیں"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"نجی"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"پرائیویٹ"</string>
<string name="profile_label_clone" msgid="769106052210954285">"کلون"</string>
<string name="profile_label_work" msgid="3495359133038584618">"دفتری پروفائل"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"دوسری دفتری پروفائل"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index f123bea572b1..97e044887d7e 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Ilovaga yaqin atrofdagi ultra keng polosali qurilmalarining nisbiy joylashishini aniqlashga ruxsat beradi"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"Yaqin-atrofdagi Wi-Fi qurilmalar bilan ishlash"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Ilovaga yaqin-atrofdagi Wi-Fi qurilmalarga reklama yuborish, ulanish va ularning taxminiy joylashuvini aniqlash imkonini beradi."</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"atrofdagi qurilmalarning nisbiy joylashuvini aniqlash"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Ilova atrofdagi qurilmalarning nisbiy joylashuvini aniqlashi mumkin"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Asosiy NFC toʻlov xizmati haqidagi axborot"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Bu ilovaga asosiy NFC toʻlov xizmati haqidagi axborotni olish imkonini beradi (masalan, qayd qilingan AID identifikatorlari va marshrutning yakuniy manzili)."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"NFC modulini boshqarish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ef50a9badc4c..1ebff32f7d20 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Cho phép ứng dụng xác định khoảng cách tương đối giữa các thiết bị ở gần dùng Băng tần siêu rộng"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"tương tác với các thiết bị Wi‑Fi lân cận"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Cho phép ứng dụng này thông báo, kết nối và xác định vị trí tương đối của các thiết bị Wi‑Fi lân cận"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"xác định vị trí tương đối giữa các thiết bị ở gần"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Cho phép ứng dụng xác định vị trí tương đối giữa các thiết bị ở gần"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Thông tin về dịch vụ thanh toán qua công nghệ giao tiếp tầm gần (NFC) được ưu tiên"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Cho phép ứng dụng nhận thông tin về dịch vụ thanh toán qua công nghệ giao tiếp tầm gần mà bạn ưu tiên, chẳng hạn như các hình thức hỗ trợ đã đăng ký và điểm đến trong hành trình."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"kiểm soát Liên lạc trường gần"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Bật"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Quay lại"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Đang chờ xử lý..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Tính năng Liên lạc khẩn cấp qua vệ tinh đang hoạt động"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Bạn có thể nhắn tin cho dịch vụ khẩn cấp khi không có mạng di động hay mạng Wi-Fi. Google Tin nhắn phải là ứng dụng nhắn tin mặc định của bạn."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Chưa hỗ trợ tính năng Liên lạc khẩn cấp qua vệ tinh"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Thiết bị này chưa hỗ trợ tính năng Liên lạc khẩn cấp qua vệ tinh"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Chưa thiết lập tính năng Liên lạc khẩn cấp qua vệ tinh"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Hãy kiểm tra để chắc chắn rằng bạn đã kết nối Internet, rồi thử thiết lập lại"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Tính năng Liên lạc khẩn cấp qua vệ tinh chưa hoạt động"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Tính năng Liên lạc khẩn cấp qua vệ tinh chưa hoạt động ở quốc gia hoặc khu vực này"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Chưa thiết lập tính năng Liên lạc khẩn cấp qua vệ tinh"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Để nhắn tin qua vệ tinh, hãy đặt Google Tin nhắn làm ứng dụng nhắn tin mặc định của bạn"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Tính năng Liên lạc khẩn cấp qua vệ tinh chưa hoạt động"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Để kiểm tra xem tính năng Liên lạc khẩn cấp qua vệ tinh có hoạt động ở quốc gia hoặc khu vực này không, hãy bật chế độ cài đặt vị trí"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Tính năng nhắn tin qua vệ tinh đang hoạt động"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Bạn có thể nhắn tin qua vệ tinh khi không có mạng di động hay mạng Wi-Fi. Google Tin nhắn phải là ứng dụng nhắn tin mặc định của bạn."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Chưa hỗ trợ tính năng nhắn tin qua vệ tinh"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Thiết bị này chưa hỗ trợ tính năng nhắn tin qua vệ tinh"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Chưa thiết lập tính năng nhắn tin qua vệ tinh"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Hãy kiểm tra để chắc chắn rằng bạn đã kết nối Internet, rồi thử thiết lập lại"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Tính năng nhắn tin qua vệ tinh chưa hoạt động"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Tính năng nhắn tin qua vệ tinh chưa hoạt động ở quốc gia hoặc khu vực này"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Chưa thiết lập tính năng nhắn tin qua vệ tinh"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Để nhắn tin qua vệ tinh, hãy đặt Google Tin nhắn làm ứng dụng nhắn tin mặc định của bạn"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Tính năng nhắn tin qua vệ tinh chưa hoạt động"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Để kiểm tra xem tính năng nhắn tin qua vệ tinh có hoạt động ở quốc gia hoặc khu vực này không, hãy bật chế độ cài đặt vị trí"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Thiết lập lại tính năng Mở khoá bằng vân tay"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Không nhận dạng được <xliff:g id="FINGERPRINT">%s</xliff:g> nữa."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Không nhận dạng được <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> và <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nữa."</string>
diff --git a/core/res/res/values-watch-v36/config.xml b/core/res/res/values-watch-v36/config.xml
index bb9da177e4fd..1143ae30fe9d 100644
--- a/core/res/res/values-watch-v36/config.xml
+++ b/core/res/res/values-watch-v36/config.xml
@@ -15,7 +15,6 @@
-->
<resources>
- <!-- Overrides system value -->
- <dimen name="config_buttonCornerRadius">26dp</dimen>
+ <dimen name="config_wearMaterial3_buttonCornerRadius">26dp</dimen>
<dimen name="config_bottomDialogCornerRadius">18dp</dimen>
</resources>
diff --git a/core/res/res/values-watch-v36/styles_material.xml b/core/res/res/values-watch-v36/styles_material.xml
index b2760e7c10a7..00f3f092b768 100644
--- a/core/res/res/values-watch-v36/styles_material.xml
+++ b/core/res/res/values-watch-v36/styles_material.xml
@@ -18,13 +18,13 @@
<resources>
<!-- Button Styles -->
<!-- Material Button - Filled -->
- <style name="Widget.DeviceDefault.Button.Filled" parent="Widget.DeviceDefault.Button">
+ <style name="Widget.DeviceDefault.Button.Filled" parent="Widget.DeviceDefault.Button.WearMaterial3">
<item name="android:background">@drawable/btn_background_material_filled</item>
<item name="textAppearance">@style/TextAppearance.Widget.Button.Material.Filled</item>
</style>
<!-- Material Button - Filled Tonal(Override system default button styles) -->
- <style name="Widget.DeviceDefault.Button">
+ <style name="Widget.DeviceDefault.Button.WearMaterial3">
<item name="background">@drawable/btn_background_material_filled_tonal</item>
<item name="textAppearance">@style/TextAppearance.Widget.Button.Material</item>
<item name="minHeight">@dimen/btn_material_height</item>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 4d2085bbe0c7..7ac17595a278 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -238,16 +238,16 @@ a similar way.
<item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
<item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
<item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_on_surface_light</item>
<item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
<item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
<item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
<item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
+ <item name="materialColorInversePrimary">@color/system_primary_light</item>
<item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
+ <item name="materialColorInverseSurface">@color/system_surface_light</item>
<item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
<item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index e2f66fc93c08..64c2f70be73e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"允许应用确定附近超宽带设备之间的相对位置"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"与附近的 WLAN 设备互动"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"允许该应用向附近的 WLAN 设备进行广播、连接到这些设备以及确定这些设备的相对位置"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"确定附近的设备之间的相对位置"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"允许应用确定附近的设备之间的相对位置"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"首选 NFC 付款服务信息"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允许应用获取首选 NFC 付款服务信息,例如注册的应用标识符和路线目的地。"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"控制近距离通信"</string>
@@ -659,7 +657,7 @@
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用屏幕锁定凭据"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"输入您的屏幕锁定凭据才能继续"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"请用力按住传感器"</string>
- <string name="fingerprint_acquired_insufficient" msgid="2410176550915730974">"无法识别指纹。请重试。"</string>
+ <string name="fingerprint_acquired_insufficient" msgid="2410176550915730974">"无法识别指纹,请重试。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"请清洁指纹传感器,然后重试"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"请清洁传感器,然后重试"</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"请用力按住传感器"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a2d32805df76..53c5d155cd27 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"允許應用程式判斷附近超寬頻裝置之間的相對位置"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"與附近的 Wi‑Fi 裝置互動"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"允許應用程式向附近的 Wi-Fi 裝置顯示此裝置、連接這些裝置並判斷其相對位置"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"判斷附近裝置之間的相對位置"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"允許應用程式判斷附近裝置之間的相對位置"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"由用戶允許授權的 NFC 付款服務資訊"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允許應用程式取得由用戶允許授權的 NFC 付款服務資訊 (如已註冊的付款輔助功能和最終付款對象)。"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"控制近距離無線通訊"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"開啟"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"返回"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"「緊急衛星連接」現已推出"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"在沒有流動網絡或 Wi-Fi 網絡的情況下,你可向緊急服務收發訊息,但你必須將「Google 訊息」設定為預設訊息應用程式。"</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"不支援「緊急衛星連接」"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"此裝置不支援「緊急衛星連接」"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"未設定「緊急衛星連接」"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"請確保已連接互聯網,然後再試一次"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"無法使用「緊急衛星連接」"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"此國家或地區不支援「緊急衛星連接」"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"未設定「緊急衛星連接」"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"你必須將「Google 訊息」設定為預設訊息應用程式,才能透過衛星收發訊息"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"無法使用「緊急衛星連接」"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"如要查看此國家或地區是否可以使用緊急衛星連接功能,請開啟位置設定"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"可以使用衛星訊息功能"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"在沒有流動網絡或 Wi-Fi 網絡的情況下,你可透過衛星收發訊息,但你必須將「Google 訊息」設定為預設訊息應用程式。"</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"無法使用衛星訊息功能"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"此裝置不支援衛星訊息功能"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"未設定衛星訊息功能"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"請確保已連接互聯網,然後再試一次"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"無法使用衛星訊息功能"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"此國家或地區不支援衛星訊息功能"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"未設定衛星訊息功能"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"你必須將「Google 訊息」設定為預設訊息應用程式,才能透過衛星收發訊息"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"無法使用衛星訊息功能"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"如要查看此國家或地區是否支援衛星訊息功能,請開啟位置設定"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新設定「指紋解鎖」功能"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"無法再辨識<xliff:g id="FINGERPRINT">%s</xliff:g>。"</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"無法再辨識<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>和<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d1f8b5a289ed..cbd6bd2fb48f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"允許應用程式判斷附近超寬頻裝置間的相對位置"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"與鄰近的 Wi-Fi 裝置互動"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"允許應用程式顯示鄰近的 Wi-Fi 裝置的資料、與其連線並判斷相對位置"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"判斷鄰近裝置間的相對位置"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"允許應用程式判斷鄰近裝置間的相對位置"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"首選 NFC 付費服務資訊"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允許應用程式取得首選 NFC 付費服務資訊,例如已註冊的輔助工具和路線目的地。"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"控制近距離無線通訊"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"開啟"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"返回"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"現在可使用「緊急衛星連線」"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"如果沒有行動網路或 Wi-Fi 網路,也可以傳訊息給緊急救援服務。Google 訊息必須是預設訊息應用程式,你才能使用這項功能。"</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"不支援「緊急衛星連線」"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"這部裝置不支援「緊急衛星連線」"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"未設定「緊急衛星連線」"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"請確定已連上網際網路,然後再重新嘗試設定"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"「緊急衛星連線」無法使用"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"無法在這個國家/地區使用「緊急衛星連線」"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"未設定「緊急衛星連線」"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"如要透過衛星傳送訊息,請將 Google 訊息設為預設訊息應用程式"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"「緊急衛星連線」無法使用"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"如要確認「緊急衛星連線」能否在這個國家/地區使用,請開啟位置資訊設定"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"現在可使用「衛星訊息」"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"如果沒有行動網路或 Wi-Fi 網路,可以透過衛星傳送訊息。Google 訊息必須是預設訊息應用程式,你才能使用這項功能。"</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"不支援「衛星訊息」"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"這部裝置不支援「衛星訊息」"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"未設定「衛星訊息」"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"請確定已連上網際網路,然後再重新嘗試設定"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"「衛星訊息」無法使用"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"無法在這個國家/地區使用「衛星訊息」"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"未設定「衛星訊息」"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"如要透過衛星傳送訊息,請將 Google 訊息設為預設訊息應用程式"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"「衛星訊息」無法使用"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"如要確認「衛星訊息」能否在這個國家/地區使用,請開啟位置資訊設定"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新設定指紋解鎖"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"系統無法再辨識「<xliff:g id="FINGERPRINT">%s</xliff:g>」。"</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"系統無法再辨識「<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>」和「<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>」。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index d1b7e510168e..f498fe24267c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -612,10 +612,8 @@
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Vumela i-app inqume indawo ehambelanayo phakathi kwamadivayisi e-Ultra-Wideband aseduze"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"xhumana namadivayisi we-Wi‑Fi aseduze"</string>
<string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Ivumela i-app ikhangise, ixhume, futhi inqume isimo esihambisanayo samadivayisi we-Wi-Fi aseduze"</string>
- <!-- no translation found for permlab_ranging (2854543350668593390) -->
- <skip />
- <!-- no translation found for permdesc_ranging (6703905535621521710) -->
- <skip />
+ <string name="permlab_ranging" msgid="2854543350668593390">"nquma indawo ehlobene phakathi kwamadivayisi aseduze"</string>
+ <string name="permdesc_ranging" msgid="6703905535621521710">"Vumela i-app inqume indawo ehambelanayo phakathi kwamadivayisi aseduze"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Ulwazi Lwesevisi Yenkokhelo Ye-NFC Okhethwayo"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Ivuemela uhlelo lokusebenza ukuthola ulwazi lesevisi yenkokhelo ye-nfc njengezinsiza zokubhalisa nezindawo zomzila."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"lawula Uxhumano Lwenkambu Eseduze"</string>
@@ -2435,54 +2433,30 @@
<string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Vula"</string>
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Iya emuva"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ilindile..."</string>
- <!-- no translation found for satellite_sos_available_notification_title (5396708154268096124) -->
- <skip />
- <!-- no translation found for satellite_sos_available_notification_summary (1727088812951848330) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_title (2659100983227637285) -->
- <skip />
- <!-- no translation found for satellite_sos_not_supported_notification_summary (1071762454665310549) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_title (8564738683795406715) -->
- <skip />
- <!-- no translation found for satellite_sos_not_provisioned_notification_summary (3127320958911180629) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_title (3164093193467075926) -->
- <skip />
- <!-- no translation found for satellite_sos_not_in_allowed_region_notification_summary (7686947667515679672) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_title (292528603128702080) -->
- <skip />
- <!-- no translation found for satellite_sos_unsupported_default_sms_app_notification_summary (3165168393504548437) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_title (5427987916850950591) -->
- <skip />
- <!-- no translation found for satellite_sos_location_disabled_notification_summary (1544937460641058567) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_title (3366657987618784706) -->
- <skip />
- <!-- no translation found for satellite_messaging_available_notification_summary (7573949038500243670) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_title (8202139632766878610) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_supported_notification_summary (61629858627638545) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_title (961909101918169727) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_provisioned_notification_summary (1060961852174442155) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_title (2035303593479031655) -->
- <skip />
- <!-- no translation found for satellite_messaging_not_in_allowed_region_notification_summary (5270294879531815854) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_title (1004808759472360189) -->
- <skip />
- <!-- no translation found for satellite_messaging_unsupported_default_sms_app_notification_summary (17084124893763593) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_title (7270641894250928494) -->
- <skip />
- <!-- no translation found for satellite_messaging_location_disabled_notification_summary (1450824950686221810) -->
- <skip />
+ <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Isethelayithi yokuxhumana ngezimo eziphuthumayo isiyatholakala manje"</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Ungathumela imiyalezo kumasevisi ezimo eziphuthumayo uma ingekho inethiwekhi yeselula noma ye-Wi-Fi. IGoogle Messages kumelwe kube iyona app yakho yemiyalezo ezenzekelayo."</string>
+ <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Isethelayithi yokuxhumana ngezimo eziphuthumayo ayisekelwe"</string>
+ <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Isethelayithi yokuxhumana ngezimo eziphuthumayo ayisekelwe kule divayisi"</string>
+ <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Isethelayithi yokuxhumana ngezimo eziphuthumayo ayisethiwe"</string>
+ <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Qiniseka ukuthi uxhumeke ku-inthanethi bese uzama ukusetha futhi"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Isethelayithi yokuxhumana ngezimo eziphuthumayo ayitholakali"</string>
+ <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Isethelayithi yokuxhumana ngezimo eziphuthumayo ayitholakali kuleli zwe noma kulesi sifunda"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Isethelayithi yokuxhumana ngezimo eziphuthumayo ayisethiwe"</string>
+ <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Ukuze uthumele umlayezo ngesathelayithi, setha iGoogle Messages ngenge-app yakho yemilayezo ezenzakalelayo"</string>
+ <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Isethelayithi yokuxhumana ngezimo eziphuthumayo ayitholakali"</string>
+ <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Ukuze uhlole ukuthi isethelayithi yokuxhumana ngezimo eziphuthumayo iyatholakala yini kuleli zwe noma kulesi sifunda, vula amasethingi endawo"</string>
+ <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Ukuthumela umyalezo ngesethelayithi kuyatholakala"</string>
+ <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Ungathumela umlayezo ngesathelayithi uma ingekho inethiwekhi yeselula noma ye-Wi-Fi. IGoogle Messages kumelwe kube iyona app yakho yemiyalezo ezenzekelayo."</string>
+ <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Ukuthumela umyalezo ngesethelayithi akusekelwe"</string>
+ <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Ukuthumela umyalezo ngesethelayithi akusekelwe kule divayisi"</string>
+ <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Ukuthumela umyalezo ngesethelayithi akusethiwe"</string>
+ <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Qiniseka ukuthi uxhumeke ku-inthanethi bese uzama ukusetha futhi"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Ukuthumela umyalezo ngesethelayithi akutholakali"</string>
+ <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Ukuthumela umyalezo ngesethelayithi akutholakali kuleli zwe noma kulesi sifunda"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Ukuthumela umyalezo ngesethelayithi akusethiwe"</string>
+ <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Ukuze uthumele umlayezo ngesathelayithi, setha iGoogle Messages ngenge-app yakho yemilayezo ezenzakalelayo"</string>
+ <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Ukuthumela umyalezo ngesethelayithi akutholakali"</string>
+ <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Ukuze uhlole ukuthi ukuthumela umyalezo ngesethelayithi kuyatholakala yini kuleli zwe noma kulesi sifunda, vula amasethingi endawo"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Setha Ukuvula ngesigxivizo somunwe futhi"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"I-<xliff:g id="FINGERPRINT">%s</xliff:g> angeke isaziwa."</string>
<string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"I-<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> kanye ne-<xliff:g id="FINGERPRINT_1">%2$s</xliff:g> angeke isaziwa."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e6dedce8feaf..8c46ccc84f39 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1218,155 +1218,132 @@
it prevent any 'false' in any of its children. -->
<attr name="forceDarkAllowed" format="boolean" />
- <!-- A lower-emphasized variant of the color on the fixed secondary branding color. @hide
- -->
- <attr name="materialColorOnSecondaryFixedVariant" format="color"/>
- <!-- A lower-emphasized variant of the color on the fixed tertiary branding color. @hide
- -->
- <attr name="materialColorOnTertiaryFixedVariant" format="color"/>
- <!-- The container color of surface the most lowered. @hide -->
- <attr name="materialColorSurfaceContainerLowest" format="color"/>
- <!-- A lower-emphasized variant of the color on the fixed primary branding color. @hide -->
- <attr name="materialColorOnPrimaryFixedVariant" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- the secondary container color. @hide -->
- <attr name="materialColorOnSecondaryContainer" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- the tertiary container color. @hide -->
- <attr name="materialColorOnTertiaryContainer" format="color"/>
- <!-- The container color of surface slightly lowered, which replaces the previous surface
- at elevation level 1. @hide -->
- <attr name="materialColorSurfaceContainerLow" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- the primary container color. @hide -->
- <attr name="materialColorOnPrimaryContainer" format="color"/>
- <!-- A stronger, more emphasized variant of the fixed secondary branding color. @hide -->
- <attr name="materialColorSecondaryFixedDim" format="color"/>
- <!-- A tonal variation of the on error color that passes accessibility guidelines for
- text/iconography when drawn on top of error container. @hide -->
- <attr name="materialColorOnErrorContainer" format="color"/>
- <!-- The color text/iconography when drawn on top of the fixed secondary branding color.
- @hide -->
- <attr name="materialColorOnSecondaryFixed" format="color"/>
- <!-- The "on surface" inverse color, useful for inverted backgrounds. @hide -->
- <attr name="materialColorOnSurfaceInverse" format="color"/>
- <!-- A stronger, more emphasized variant of the fixed tertiary branding color. @hide -->
- <attr name="materialColorTertiaryFixedDim" format="color"/>
- <!-- The color text/iconography when drawn on top of the fixed tertiary branding color.
- @hide -->
- <attr name="materialColorOnTertiaryFixed" format="color"/>
- <!-- A stronger, more emphasized variant of the fixed primary branding color. @hide -->
- <attr name="materialColorPrimaryFixedDim" format="color"/>
- <!-- A tonal variation of the secondary color suitable for background color of container
- views. @hide -->
- <attr name="materialColorSecondaryContainer" format="color"/>
- <!-- A tonal variation of the error color suitable for background color of container views.
- @hide -->
+ <!-- Dynamic Tokens -->
+
+ <!-- @hide -->
+ <attr name="materialColorBackground" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorControlActivated" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorControlHighlight" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorControlNormal" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorError" format="color"/>
+ <!-- @hide -->
<attr name="materialColorErrorContainer" format="color"/>
- <!-- The color text/iconography when drawn on top of the fixed primary branding color.
- @hide -->
- <attr name="materialColorOnPrimaryFixed" format="color"/>
- <!-- The inverse color of colorPrimary. @hide -->
- <attr name="materialColorPrimaryInverse" format="color"/>
- <!-- A secondary branding color for the app, which stays the same between light and dark
- themes. @hide -->
- <attr name="materialColorSecondaryFixed" format="color"/>
- <!-- The surface inverse color, useful for inverted backgrounds. @hide -->
- <attr name="materialColorSurfaceInverse" format="color"/>
- <!-- A tonal variation of the surface color. @hide -->
- <attr name="materialColorSurfaceVariant" format="color"/>
- <!-- A tonal variation of the tertiary color suitable for background color of container
- views. @hide -->
- <attr name="materialColorTertiaryContainer" format="color"/>
- <!-- A tertiary branding color for the app, which stays the same between light and dark
- themes. @hide -->
- <attr name="materialColorTertiaryFixed" format="color"/>
- <!-- A tonal variation of the primary color suitable for background color of container
- views. @hide -->
- <attr name="materialColorPrimaryContainer" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- background. @hide -->
+ <!-- @hide -->
+ <attr name="materialColorInverseOnSurface" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorInversePrimary" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorInverseSurface" format="color"/>
+ <!-- @hide -->
<attr name="materialColorOnBackground" format="color"/>
- <!-- A primary branding color for the app, which stays the same between light and dark
- themes. @hide -->
- <attr name="materialColorPrimaryFixed" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- secondary. @hide -->
- <attr name="materialColorOnSecondary" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- tertiary. @hide -->
- <attr name="materialColorOnTertiary" format="color"/>
- <!-- The surface color which always stay the dimmest in either dark or light theme. @hide
- -->
- <attr name="materialColorSurfaceDim" format="color"/>
- <!-- The surface color which always stay the brightest in either dark or light theme. @hide
- -->
- <attr name="materialColorSurfaceBright" format="color"/>
- <!-- The secondary branding color for the app, usually a bright complement to the primary
- branding color. @hide -->
- <attr name="materialColorSecondary" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- error. @hide -->
+ <!-- @hide -->
<attr name="materialColorOnError" format="color"/>
- <!-- The color of surfaces such as cards, sheets, menus. @hide -->
- <attr name="materialColorSurface" format="color"/>
- <!-- The container color of surface slightly elevated, which replaces the previous surface
- at elevation level 3. @hide -->
- <attr name="materialColorSurfaceContainerHigh" format="color"/>
- <!-- The tertiary branding color for the app, usually a bright complement to the primary
- branding color. @hide -->
- <attr name="materialColorTertiary" format="color"/>
- <!-- The container color of surface the most elevated, which replaces the previous surface
- variant. @hide -->
- <attr name="materialColorSurfaceContainerHighest" format="color"/>
- <!-- A tonal variation of the on surface color that passes accessibility guidelines for
- text/iconography when drawn on top of surface variant. @hide -->
+ <!-- @hide -->
+ <attr name="materialColorOnErrorContainer" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnPrimary" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnPrimaryContainer" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnSecondary" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnSecondaryContainer" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnSurface" format="color"/>
+ <!-- @hide -->
<attr name="materialColorOnSurfaceVariant" format="color"/>
- <!-- A color meant to be used in element outlines. @hide -->
+ <!-- @hide -->
+ <attr name="materialColorOnTertiary" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnTertiaryContainer" format="color"/>
+ <!-- @hide -->
<attr name="materialColorOutline" format="color"/>
- <!-- A color meant to be used in element outlines on the surface-variant color. @hide -->
+ <!-- @hide -->
<attr name="materialColorOutlineVariant" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- primary. @hide -->
- <attr name="materialColorOnPrimary" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
- surface. @hide -->
- <attr name="materialColorOnSurface" format="color"/>
- <!-- The container color of surface, which replaces the previous surface at elevation level
- 2. @hide -->
- <attr name="materialColorSurfaceContainer" format="color"/>
- <!-- The container color of surface, which replaces the previous surface at elevation level
- 2. @hide -->
- <attr name="materialColorSurfaceContainer" format="color"/>
- <!-- The primary branding color for the app. By default, this is the color applied to the
- action bar background. @hide -->
+ <!-- @hide -->
+ <attr name="materialColorPaletteKeyColorNeutral" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorPaletteKeyColorNeutralVariant" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorPaletteKeyColorPrimary" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorPaletteKeyColorSecondary" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorPaletteKeyColorTertiary" format="color"/>
+ <!-- @hide -->
<attr name="materialColorPrimary" format="color"/>
- <!-- The secondary branding color for the app, usually a bright complement to the primary
- branding color. @hide -->
+ <!-- @hide -->
+ <attr name="materialColorPrimaryContainer" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorScrim" format="color"/>
+ <!-- @hide -->
<attr name="materialColorSecondary" format="color"/>
- <!-- A color that passes accessibility guidelines for text/iconography when drawn on top
- of tertiary. @hide -->
+ <!-- @hide -->
+ <attr name="materialColorSecondaryContainer" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorShadow" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurface" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceBright" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceContainer" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceContainerHigh" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceContainerHighest" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceContainerLow" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceContainerLowest" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceDim" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceTint" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSurfaceVariant" format="color"/>
+ <!-- @hide -->
<attr name="materialColorTertiary" format="color"/>
- <!-- The error color for the app, intended to draw attention to error conditions. @hide -->
- <attr name="materialColorError" format="color"/>
-
- <!-- System Custom Tokens-->
<!-- @hide -->
- <attr name="customColorWidgetBackground" format="color"/>
+ <attr name="materialColorTertiaryContainer" format="color"/>
<!-- @hide -->
- <attr name="customColorClockHour" format="color"/>
+ <attr name="materialColorTextHintInverse" format="color"/>
<!-- @hide -->
- <attr name="customColorClockMinute" format="color"/>
+ <attr name="materialColorTextPrimaryInverse" format="color"/>
<!-- @hide -->
- <attr name="customColorClockSecond" format="color"/>
+ <attr name="materialColorTextPrimaryInverseDisableOnly" format="color"/>
<!-- @hide -->
- <attr name="customColorThemeApp" format="color"/>
+ <attr name="materialColorTextSecondaryAndTertiaryInverse" format="color"/>
<!-- @hide -->
- <attr name="customColorOnThemeApp" format="color"/>
+ <attr name="materialColorTextSecondaryAndTertiaryInverseDisabled" format="color"/>
<!-- @hide -->
- <attr name="customColorThemeAppRing" format="color"/>
+ <attr name="materialColorOnPrimaryFixed" format="color"/>
<!-- @hide -->
- <attr name="customColorThemeNotif" format="color"/>
+ <attr name="materialColorOnPrimaryFixedVariant" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnSecondaryFixed" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnSecondaryFixedVariant" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnTertiaryFixed" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorOnTertiaryFixedVariant" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorPrimaryFixed" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorPrimaryFixedDim" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSecondaryFixed" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorSecondaryFixedDim" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorTertiaryFixed" format="color"/>
+ <!-- @hide -->
+ <attr name="materialColorTertiaryFixedDim" format="color"/>
<!-- @hide -->
<attr name="customColorBrandA" format="color"/>
<!-- @hide -->
@@ -1376,23 +1353,41 @@
<!-- @hide -->
<attr name="customColorBrandD" format="color"/>
<!-- @hide -->
- <attr name="customColorUnderSurface" format="color"/>
+ <attr name="customColorClockHour" format="color"/>
<!-- @hide -->
- <attr name="customColorShadeActive" format="color"/>
+ <attr name="customColorClockMinute" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorClockSecond" format="color"/>
<!-- @hide -->
<attr name="customColorOnShadeActive" format="color"/>
<!-- @hide -->
<attr name="customColorOnShadeActiveVariant" format="color"/>
<!-- @hide -->
- <attr name="customColorShadeInactive" format="color"/>
- <!-- @hide -->
<attr name="customColorOnShadeInactive" format="color"/>
<!-- @hide -->
<attr name="customColorOnShadeInactiveVariant" format="color"/>
<!-- @hide -->
- <attr name="customColorShadeDisabled" format="color"/>
+ <attr name="customColorOnThemeApp" format="color"/>
<!-- @hide -->
<attr name="customColorOverviewBackground" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorShadeActive" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorShadeDisabled" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorShadeInactive" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorThemeApp" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorThemeAppRing" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorThemeNotif" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorUnderSurface" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorWeatherTemp" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorWidgetBackground" format="color"/>
</declare-styleable>
@@ -4813,6 +4808,12 @@
<!-- Whether the device should default to observe mode when this service is
default or in the foreground. -->
<attr name="shouldDefaultToObserveMode" format="boolean"/>
+ <!-- Whether this service should share the same AID routing priority as the role
+ owner. This package and the role owner must have the same signature, and the
+ role owner must opt into this behavior by using the property named by
+ {@link android.nfc.cardemulation.CardEmulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY }
+ in the <code>&lt;application&rt;</code> tag. -->
+ <attr name="shareRolePriority" format="boolean"/>
</declare-styleable>
<!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -4840,6 +4841,7 @@
<!-- Whether the device should default to observe mode when this service is
default or in the foreground. -->
<attr name="shouldDefaultToObserveMode"/>
+ <attr name="shareRolePriority"/>
</declare-styleable>
<!-- Specify one or more <code>aid-group</code> elements inside a
@@ -7753,14 +7755,14 @@
<!-- Used to config the segments of a NotificationProgressDrawable. -->
<!-- @hide internal use only -->
<declare-styleable name="NotificationProgressDrawableSegments">
- <!-- Width of the stroke. -->
- <attr name="width" />
- <!-- Default color of the stroke. -->
+ <!-- Height of the solid segments -->
+ <attr name="height" />
+ <!-- Height of the faded segments -->
+ <attr name="fadedHeight" format="dimension"/>
+ <!-- Corner radius of the segment rect. -->
+ <attr name="cornerRadius" format="dimension" />
+ <!-- Default color of the segment. -->
<attr name="color" />
- <!-- Length of a dash in the stroke for the dashed segments. -->
- <attr name="dashWidth" />
- <!-- Gap between dashes in the stroke for the dashed segments. -->
- <attr name="dashGap" />
</declare-styleable>
<!-- Used to config the points of a NotificationProgressDrawable. -->
@@ -7771,7 +7773,7 @@
<!-- Inset of the point icon or rect. -->
<attr name="inset" />
<!-- Corner radius of the point rect. -->
- <attr name="cornerRadius" format="dimension" />
+ <attr name="cornerRadius"/>
<!-- Default color of the point rect. -->
<attr name="color" />
</declare-styleable>
@@ -10285,22 +10287,25 @@
</declare-styleable>
<!-- @hide -->
+ <attr name="modifierState">
+ <flag name="META" value="0x10000" />
+ <flag name="CTRL" value="0x1000" />
+ <flag name="ALT" value="0x02" />
+ <flag name="SHIFT" value="0x1" />
+ <flag name="SYM" value="0x4" />
+ <flag name="FUNCTION" value="0x8" />
+ <flag name="CAPS_LOCK" value="0x100000" />
+ <flag name="NUM_LOCK" value="0x200000" />
+ <flag name="SCROLL_LOCK" value="0x400000" />
+ </attr>
+
+ <!-- @hide -->
<declare-styleable name="HardwareDefinedShortcut">
<attr name="keycode" />
<!-- The values are taken from public constants for modifier state defined in
{@see KeyEvent.java}. Here we allow multiple modifier flags as value, since this
represents the modifier state -->
- <attr name="modifierState">
- <flag name="META" value="0x10000" />
- <flag name="CTRL" value="0x1000" />
- <flag name="ALT" value="0x02" />
- <flag name="SHIFT" value="0x1" />
- <flag name="SYM" value="0x4" />
- <flag name="FUNCTION" value="0x8" />
- <flag name="CAPS_LOCK" value="0x100000" />
- <flag name="NUM_LOCK" value="0x200000" />
- <flag name="SCROLL_LOCK" value="0x400000" />
- </attr>
+ <attr name="modifierState" />
<attr name="outKeycode" />
</declare-styleable>
@@ -10309,6 +10314,11 @@
<attr name="keycode" />
</declare-styleable>
+ <declare-styleable name="Bookmark">
+ <attr name="keycode" />
+ <attr name="modifierState" />
+ </declare-styleable>
+
<declare-styleable name="MediaRouteButton">
<!-- This drawable is a state list where the "activated" state
indicates active media routing. Non-activated indicates
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 41dec3776b5c..7ef539492aa4 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1855,13 +1855,23 @@
{@link android.R.styleable#AndroidManifestProcess process} tag, or to an
{@link android.R.styleable#AndroidManifestApplication application} tag (to supply
a default setting for all application components). -->
- <attr name="memtagMode">
+ <attr name="memtagMode">
<enum name="default" value="-1" />
<enum name="off" value="0" />
<enum name="async" value="1" />
<enum name="sync" value="2" />
</attr>
+ <!-- This attribute will be used to override app compatibility mode on 16 KB devices.
+ If set to enabled, Natives lib will be extracted from APK if they are not page aligned on
+ 16 KB device. 4 KB natives libs will be loaded app-compat mode if they are eligible.
+ @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
+ <attr name="pageSizeCompat">
+ <enum name="enabled" value="5" />
+ <enum name="disabled" value="6" />
+ </attr>
+
+
<!-- Attribution tag to be used for permission sub-attribution if a
permission is checked in {@link android.content.Context#sendBroadcast(Intent, String)}.
Multiple tags can be specified separated by '|'.
@@ -2212,6 +2222,9 @@
<attr name="memtagMode" />
+ <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
+ <attr name="pageSizeCompat" />
+
<!-- If {@code true} enables automatic zero initialization of all native heap
allocations. -->
<attr name="nativeHeapZeroInitialized" format="boolean" />
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index f5bb554b0b32..13dd4a35564c 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -238,393 +238,319 @@
<color name="conversation_important_highlight">#F9AB00</color>
- <!--Lightest shade of the Primary color used by the system. White.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Lightest shade of the Primary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_0">#FFFFFF</color>
- <!--Shade of the Primary system color at 99% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_10">#FEFBFF</color>
- <!--Shade of the Primary system color at 95% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_50">#EEF0FF</color>
- <!--Shade of the Primary system color at 90% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_100">#D9E2FF</color>
- <!--Shade of the Primary system color at 80% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_200">#B0C6FF</color>
- <!--Shade of the Primary system color at 70% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_300">#94AAE4</color>
- <!--Shade of the Primary system color at 60% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_400">#7A90C8</color>
- <!--Shade of the Primary system color at 50% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_500">#6076AC</color>
- <!--Shade of the Primary system color at 40% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_600">#475D92</color>
- <!--Shade of the Primary system color at 30% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_700">#2F4578</color>
- <!--Shade of the Primary system color at 20% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_800">#152E60</color>
- <!--Shade of the Primary system color at 10% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Primary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_900">#001945</color>
- <!--Darkest shade of the Primary color used by the system. Black.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Darkest shade of the Primary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent1_1000">#000000</color>
-
- <!--Lightest shade of the Secondary color used by the system. White.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Lightest shade of the Secondary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_0">#FFFFFF</color>
- <!--Shade of the Secondary system color at 99% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_10">#FEFBFF</color>
- <!--Shade of the Secondary system color at 95% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_50">#EEF0FF</color>
- <!--Shade of the Secondary system color at 90% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_100">#DCE2F9</color>
- <!--Shade of the Secondary system color at 80% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_200">#C0C6DC</color>
- <!--Shade of the Secondary system color at 70% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_300">#A4ABC1</color>
- <!--Shade of the Secondary system color at 60% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_400">#8A90A5</color>
- <!--Shade of the Secondary system color at 50% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_500">#70778B</color>
- <!--Shade of the Secondary system color at 40% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_600">#575E71</color>
- <!--Shade of the Secondary system color at 30% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_700">#404659</color>
- <!--Shade of the Secondary system color at 20% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_800">#2A3042</color>
- <!--Shade of the Secondary system color at 10% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_900">#151B2C</color>
- <!--Darkest shade of the Secondary color used by the system. Black.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Darkest shade of the Secondary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent2_1000">#000000</color>
-
- <!--Lightest shade of the Tertiary color used by the system. White.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Lightest shade of the Tertiary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_0">#FFFFFF</color>
- <!--Shade of the Tertiary system color at 99% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_10">#FFFBFF</color>
- <!--Shade of the Tertiary system color at 95% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_50">#FFEBFA</color>
- <!--Shade of the Tertiary system color at 90% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_100">#FDD7FA</color>
- <!--Shade of the Tertiary system color at 80% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_200">#E0BBDD</color>
- <!--Shade of the Tertiary system color at 70% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_300">#C3A0C1</color>
- <!--Shade of the Tertiary system color at 60% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_400">#A886A6</color>
- <!--Shade of the Tertiary system color at 50% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_500">#8C6D8C</color>
- <!--Shade of the Tertiary system color at 40% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_600">#725572</color>
- <!--Shade of the Tertiary system color at 30% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_700">#593D59</color>
- <!--Shade of the Tertiary system color at 20% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_800">#412742</color>
- <!--Shade of the Tertiary system color at 10% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Tertiary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_900">#2A122C</color>
- <!--Darkest shade of the Tertiary color used by the system. Black.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Darkest shade of the Tertiary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_accent3_1000">#000000</color>
-
- <!--Lightest shade of the Neutral color used by the system. White.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Lightest shade of the Neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_0">#FFFFFF</color>
- <!--Shade of the Neutral system color at 99% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_10">#FEFBFF</color>
- <!--Shade of the Neutral system color at 95% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_50">#F1F0F7</color>
- <!--Shade of the Neutral system color at 90% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_100">#E2E2E9</color>
- <!--Shade of the Neutral system color at 80% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_200">#C6C6CD</color>
- <!--Shade of the Neutral system color at 70% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_300">#ABABB1</color>
- <!--Shade of the Neutral system color at 60% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_400">#909097</color>
- <!--Shade of the Neutral system color at 50% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_500">#76777D</color>
- <!--Shade of the Neutral system color at 40% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_600">#5D5E64</color>
- <!--Shade of the Neutral system color at 30% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_700">#45464C</color>
- <!--Shade of the Neutral system color at 20% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_800">#2F3036</color>
- <!--Shade of the Neutral system color at 10% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_900">#1A1B20</color>
- <!--Darkest shade of the Neutral color used by the system. Black.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Darkest shade of the Neutral color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral1_1000">#000000</color>
-
- <!--Lightest shade of the Secondary Neutral color used by the system. White.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Lightest shade of the Secondary Neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_0">#FFFFFF</color>
- <!--Shade of the Secondary Neutral system color at 99% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_10">#FEFBFF</color>
- <!--Shade of the Secondary Neutral system color at 95% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_50">#F0F0FA</color>
- <!--Shade of the Secondary Neutral system color at 90% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_100">#E1E2EC</color>
- <!--Shade of the Secondary Neutral system color at 80% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_200">#C5C6D0</color>
- <!--Shade of the Secondary Neutral system color at 70% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_300">#A9ABB4</color>
- <!--Shade of the Secondary Neutral system color at 60% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_400">#8F9099</color>
- <!--Shade of the Secondary Neutral system color at 50% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_500">#757780</color>
- <!--Shade of the Secondary Neutral system color at 40% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_600">#5C5E67</color>
- <!--Shade of the Secondary Neutral system color at 30% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_700">#44464F</color>
- <!--Shade of the Secondary Neutral system color at 20% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_800">#2E3038</color>
- <!--Shade of the Secondary Neutral system color at 10% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Shade of the Secondary Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_900">#191B23</color>
- <!--Darkest shade of the Secondary Neutral color used by the system. Black.
- This value can be overlaid at runtime by OverlayManager RROs.-->
+ <!--Darkest shade of the Secondary Neutral color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_neutral2_1000">#000000</color>
-
- <!-- Lightest shade of the error color used by the system. White.
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_0">#ffffff</color>
- <!-- Shade of the error system color at 99% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_10">#FFFBF9</color>
- <!-- Shade of the error system color at 95% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_50">#FCEEEE</color>
- <!-- Shade of the error system color at 90% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_100">#F9DEDC</color>
- <!-- Shade of the error system color at 80% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_200">#F2B8B5</color>
- <!-- Shade of the error system color at 70% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_300">#EC928E</color>
- <!-- Shade of the error system color at 60% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_400">#E46962</color>
- <!-- Shade of the error system color at 49% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_500">#DC362E</color>
- <!-- Shade of the error system color at 40% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_600">#B3261E</color>
- <!-- Shade of the error system color at 30% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_700">#8C1D18</color>
- <!-- Shade of the error system color at 20% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_800">#601410</color>
- <!-- Shade of the error system color at 10% perceptual luminance (L* in L*a*b* color space).
- This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_error_900">#410E0B</color>
- <!-- Darkest shade of the error color used by the system. Black.
- This value can be overlaid at runtime by OverlayManager RROs. -->
+ <!--Lightest shade of the Error color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_0">#FFFFFF</color>
+ <!--Shade of the Error system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_10">#FFFBFF</color>
+ <!--Shade of the Error system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_50">#FFEDEA</color>
+ <!--Shade of the Error system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_100">#FFDAD6</color>
+ <!--Shade of the Error system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_200">#FFB4AB</color>
+ <!--Shade of the Error system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_300">#FF897D</color>
+ <!--Shade of the Error system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_400">#FF5449</color>
+ <!--Shade of the Error system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_500">#DE3730</color>
+ <!--Shade of the Error system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_600">#BA1A1A</color>
+ <!--Shade of the Error system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_700">#93000A</color>
+ <!--Shade of the Error system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_800">#690005</color>
+ <!--Shade of the Error system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+ <color name="system_error_900">#410002</color>
+ <!--Darkest shade of the Error color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
<color name="system_error_1000">#000000</color>
- <!-- Colors used in Android system, from design system.
- These values can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_primary_container_light">#D9E2FF</color>
- <color name="system_on_primary_container_light">#001945</color>
- <color name="system_primary_light">#475D92</color>
+ <!--Colors used in Android system, from design system. These values can be overlaid at runtime by OverlayManager RROs.--><color name="system_background_light">#FAF8FF</color>
+ <color name="system_control_activated_light">#D9E2FF</color>
+ <color name="system_control_highlight_light">#000000</color>
+ <color name="system_control_normal_light">#44464F</color>
+ <color name="system_error_light">#BA1A1A</color>
+ <color name="system_error_container_light">#FFDAD6</color>
+ <color name="system_inverse_on_surface_light">#F1F0F7</color>
+ <color name="system_inverse_primary_light">#B0C6FF</color>
+ <color name="system_inverse_surface_light">#2F3036</color>
+ <color name="system_on_background_light">#1A1B20</color>
+ <color name="system_on_error_light">#FFFFFF</color>
+ <color name="system_on_error_container_light">#93000A</color>
<color name="system_on_primary_light">#FFFFFF</color>
- <color name="system_secondary_container_light">#DCE2F9</color>
- <color name="system_on_secondary_container_light">#151B2C</color>
- <color name="system_secondary_light">#575E71</color>
+ <color name="system_on_primary_container_light">#2F4578</color>
<color name="system_on_secondary_light">#FFFFFF</color>
- <color name="system_tertiary_container_light">#FDD7FA</color>
- <color name="system_on_tertiary_container_light">#2A122C</color>
- <color name="system_tertiary_light">#725572</color>
+ <color name="system_on_secondary_container_light">#404659</color>
+ <color name="system_on_surface_light">#1A1B20</color>
+ <color name="system_on_surface_variant_light">#44464F</color>
<color name="system_on_tertiary_light">#FFFFFF</color>
- <color name="system_background_light">#FAF8FF</color>
- <color name="system_on_background_light">#1A1B20</color>
+ <color name="system_on_tertiary_container_light">#593D59</color>
+ <color name="system_outline_light">#757780</color>
+ <color name="system_outline_variant_light">#C5C6D0</color>
+ <color name="system_palette_key_color_neutral_light">#76777D</color>
+ <color name="system_palette_key_color_neutral_variant_light">#757780</color>
+ <color name="system_palette_key_color_primary_light">#6076AC</color>
+ <color name="system_palette_key_color_secondary_light">#70778B</color>
+ <color name="system_palette_key_color_tertiary_light">#8C6D8C</color>
+ <color name="system_primary_light">#475D92</color>
+ <color name="system_primary_container_light">#D9E2FF</color>
+ <color name="system_scrim_light">#000000</color>
+ <color name="system_secondary_light">#575E71</color>
+ <color name="system_secondary_container_light">#DCE2F9</color>
+ <color name="system_shadow_light">#000000</color>
<color name="system_surface_light">#FAF8FF</color>
- <color name="system_on_surface_light">#1A1B20</color>
- <color name="system_surface_container_low_light">#F4F3FA</color>
- <color name="system_surface_container_lowest_light">#FFFFFF</color>
+ <color name="system_surface_bright_light">#FAF8FF</color>
<color name="system_surface_container_light">#EEEDF4</color>
<color name="system_surface_container_high_light">#E8E7EF</color>
<color name="system_surface_container_highest_light">#E2E2E9</color>
- <color name="system_surface_bright_light">#FAF8FF</color>
+ <color name="system_surface_container_low_light">#F4F3FA</color>
+ <color name="system_surface_container_lowest_light">#FFFFFF</color>
<color name="system_surface_dim_light">#DAD9E0</color>
+ <color name="system_surface_tint_light">#475D92</color>
<color name="system_surface_variant_light">#E1E2EC</color>
- <color name="system_on_surface_variant_light">#44464F</color>
- <color name="system_outline_light">#757780</color>
- <color name="system_outline_variant_light">#C5C6D0</color>
- <color name="system_error_light">#BA1A1A</color>
- <color name="system_on_error_light">#FFFFFF</color>
- <color name="system_error_container_light">#FFDAD6</color>
- <color name="system_on_error_container_light">#410002</color>
- <color name="system_control_activated_light">#D9E2FF</color>
- <color name="system_control_normal_light">#44464F</color>
- <color name="system_control_highlight_light">#000000</color>
-<color name="system_text_primary_inverse_light">#E2E2E9</color>
- <color name="system_text_secondary_and_tertiary_inverse_light">#C5C6D0</color>
+ <color name="system_tertiary_light">#725572</color>
+ <color name="system_tertiary_container_light">#FDD7FA</color>
+ <color name="system_text_hint_inverse_light">#E2E2E9</color>
+ <color name="system_text_primary_inverse_light">#E2E2E9</color>
<color name="system_text_primary_inverse_disable_only_light">#E2E2E9</color>
+ <color name="system_text_secondary_and_tertiary_inverse_light">#C5C6D0</color>
<color name="system_text_secondary_and_tertiary_inverse_disabled_light">#E2E2E9</color>
- <color name="system_text_hint_inverse_light">#E2E2E9</color>
- <color name="system_palette_key_color_primary_light">#6076AC</color>
- <color name="system_palette_key_color_secondary_light">#70778B</color>
- <color name="system_palette_key_color_tertiary_light">#8C6D8C</color>
- <color name="system_palette_key_color_neutral_light">#76777D</color>
- <color name="system_palette_key_color_neutral_variant_light">#757780</color>
- <color name="system_primary_container_dark">#2F4578</color>
- <color name="system_on_primary_container_dark">#D9E2FF</color>
- <color name="system_primary_dark">#B0C6FF</color>
+ <color name="system_background_dark">#121318</color>
+ <color name="system_control_activated_dark">#2F4578</color>
+ <color name="system_control_highlight_dark">#FFFFFF</color>
+ <color name="system_control_normal_dark">#C5C6D0</color>
+ <color name="system_error_dark">#FFB4AB</color>
+ <color name="system_error_container_dark">#93000A</color>
+ <color name="system_inverse_on_surface_dark">#2F3036</color>
+ <color name="system_inverse_primary_dark">#475D92</color>
+ <color name="system_inverse_surface_dark">#E2E2E9</color>
+ <color name="system_on_background_dark">#E2E2E9</color>
+ <color name="system_on_error_dark">#690005</color>
+ <color name="system_on_error_container_dark">#FFDAD6</color>
<color name="system_on_primary_dark">#152E60</color>
- <color name="system_secondary_container_dark">#404659</color>
- <color name="system_on_secondary_container_dark">#DCE2F9</color>
- <color name="system_secondary_dark">#C0C6DC</color>
+ <color name="system_on_primary_container_dark">#D9E2FF</color>
<color name="system_on_secondary_dark">#2A3042</color>
- <color name="system_tertiary_container_dark">#593D59</color>
- <color name="system_on_tertiary_container_dark">#FDD7FA</color>
- <color name="system_tertiary_dark">#E0BBDD</color>
+ <color name="system_on_secondary_container_dark">#DCE2F9</color>
+ <color name="system_on_surface_dark">#E2E2E9</color>
+ <color name="system_on_surface_variant_dark">#C5C6D0</color>
<color name="system_on_tertiary_dark">#412742</color>
- <color name="system_background_dark">#121318</color>
- <color name="system_on_background_dark">#E2E2E9</color>
+ <color name="system_on_tertiary_container_dark">#FDD7FA</color>
+ <color name="system_outline_dark">#8F9099</color>
+ <color name="system_outline_variant_dark">#44464F</color>
+ <color name="system_palette_key_color_neutral_dark">#76777D</color>
+ <color name="system_palette_key_color_neutral_variant_dark">#757780</color>
+ <color name="system_palette_key_color_primary_dark">#6076AC</color>
+ <color name="system_palette_key_color_secondary_dark">#70778B</color>
+ <color name="system_palette_key_color_tertiary_dark">#8C6D8C</color>
+ <color name="system_primary_dark">#B0C6FF</color>
+ <color name="system_primary_container_dark">#2F4578</color>
+ <color name="system_scrim_dark">#000000</color>
+ <color name="system_secondary_dark">#C0C6DC</color>
+ <color name="system_secondary_container_dark">#404659</color>
+ <color name="system_shadow_dark">#000000</color>
<color name="system_surface_dark">#121318</color>
- <color name="system_on_surface_dark">#E2E2E9</color>
- <color name="system_surface_container_low_dark">#1A1B20</color>
- <color name="system_surface_container_lowest_dark">#0C0E13</color>
+ <color name="system_surface_bright_dark">#38393F</color>
<color name="system_surface_container_dark">#1E1F25</color>
<color name="system_surface_container_high_dark">#282A2F</color>
<color name="system_surface_container_highest_dark">#33343A</color>
- <color name="system_surface_bright_dark">#38393F</color>
+ <color name="system_surface_container_low_dark">#1A1B20</color>
+ <color name="system_surface_container_lowest_dark">#0C0E13</color>
<color name="system_surface_dim_dark">#121318</color>
+ <color name="system_surface_tint_dark">#B0C6FF</color>
<color name="system_surface_variant_dark">#44464F</color>
- <color name="system_on_surface_variant_dark">#C5C6D0</color>
- <color name="system_outline_dark">#8F9099</color>
- <color name="system_outline_variant_dark">#44464F</color>
- <color name="system_error_dark">#FFB4AB</color>
- <color name="system_on_error_dark">#690005</color>
- <color name="system_error_container_dark">#93000A</color>
- <color name="system_on_error_container_dark">#FFDAD6</color>
- <color name="system_control_activated_dark">#2F4578</color>
- <color name="system_control_normal_dark">#C5C6D0</color>
- <color name="system_control_highlight_dark">#FFFFFF</color>
+ <color name="system_tertiary_dark">#E0BBDD</color>
+ <color name="system_tertiary_container_dark">#593D59</color>
+ <color name="system_text_hint_inverse_dark">#1A1B20</color>
<color name="system_text_primary_inverse_dark">#1A1B20</color>
- <color name="system_text_secondary_and_tertiary_inverse_dark">#44464F</color>
<color name="system_text_primary_inverse_disable_only_dark">#1A1B20</color>
+ <color name="system_text_secondary_and_tertiary_inverse_dark">#44464F</color>
<color name="system_text_secondary_and_tertiary_inverse_disabled_dark">#1A1B20</color>
- <color name="system_text_hint_inverse_dark">#1A1B20</color>
- <color name="system_palette_key_color_primary_dark">#6076AC</color>
- <color name="system_palette_key_color_secondary_dark">#70778B</color>
- <color name="system_palette_key_color_tertiary_dark">#8C6D8C</color>
- <color name="system_palette_key_color_neutral_dark">#76777D</color>
- <color name="system_palette_key_color_neutral_variant_dark">#757780</color>
- <color name="system_primary_fixed">#D9E2FF</color>
- <color name="system_primary_fixed_dim">#B0C6FF</color>
<color name="system_on_primary_fixed">#001945</color>
<color name="system_on_primary_fixed_variant">#2F4578</color>
- <color name="system_secondary_fixed">#DCE2F9</color>
- <color name="system_secondary_fixed_dim">#C0C6DC</color>
<color name="system_on_secondary_fixed">#151B2C</color>
<color name="system_on_secondary_fixed_variant">#404659</color>
- <color name="system_tertiary_fixed">#FDD7FA</color>
- <color name="system_tertiary_fixed_dim">#E0BBDD</color>
<color name="system_on_tertiary_fixed">#2A122C</color>
<color name="system_on_tertiary_fixed_variant">#593D59</color>
-
- <!--Colors used in Android system, from design system. These values can be overlaid at runtime
- by OverlayManager RROs.-->
- <color name="system_widget_background_light">#EEF0FF</color>
- <color name="system_clock_hour_light">#373D50</color>
- <color name="system_clock_minute_light">#3D5487</color>
- <color name="system_clock_second_light">#4F659A</color>
- <color name="system_theme_app_light">#D9E2FF</color>
- <color name="system_on_theme_app_light">#475D92</color>
- <color name="system_theme_app_ring_light">#94AAE4</color>
- <color name="system_theme_notif_light">#E0BBDD</color>
+ <color name="system_primary_fixed">#D9E2FF</color>
+ <color name="system_primary_fixed_dim">#B0C6FF</color>
+ <color name="system_secondary_fixed">#DCE2F9</color>
+ <color name="system_secondary_fixed_dim">#C0C6DC</color>
+ <color name="system_tertiary_fixed">#FDD7FA</color>
+ <color name="system_tertiary_fixed_dim">#E0BBDD</color>
<color name="system_brand_a_light">#475D92</color>
<color name="system_brand_b_light">#6E7488</color>
<color name="system_brand_c_light">#5E73A9</color>
<color name="system_brand_d_light">#8A6A89</color>
- <color name="system_under_surface_light">#000000</color>
-<color name="system_shade_active_light">#D9E2FF</color>
+ <color name="system_clock_hour_light">#373D50</color>
+ <color name="system_clock_minute_light">#3D5487</color>
+ <color name="system_clock_second_light">#725572</color>
<color name="system_on_shade_active_light">#152E60</color>
<color name="system_on_shade_active_variant_light">#2F4578</color>
- <color name="system_shade_inactive_light">#2F3036</color>
<color name="system_on_shade_inactive_light">#E1E2EC</color>
<color name="system_on_shade_inactive_variant_light">#C5C6D0</color>
- <color name="system_shade_disabled_light">#0C0E13</color>
+ <color name="system_on_theme_app_light">#475D92</color>
<color name="system_overview_background_light">#C5C6D0</color>
- <color name="system_widget_background_dark">#152E60</color>
- <color name="system_clock_hour_dark">#8A90A5</color>
- <color name="system_clock_minute_dark">#D9E2FF</color>
- <color name="system_clock_second_dark">#B0C6FF</color>
- <color name="system_theme_app_dark">#2F4578</color>
- <color name="system_on_theme_app_dark">#B0C6FF</color>
- <color name="system_theme_app_ring_dark">#94AAE4</color>
- <color name="system_theme_notif_dark">#FDD7FA</color>
+ <color name="system_shade_active_light">#D9E2FF</color>
+ <color name="system_shade_disabled_light">#0C0E13</color>
+ <color name="system_shade_inactive_light">#2F3036</color>
+ <color name="system_theme_app_light">#D9E2FF</color>
+ <color name="system_theme_app_ring_light">#94AAE4</color>
+ <color name="system_theme_notif_light">#E0BBDD</color>
+ <color name="system_under_surface_light">#000000</color>
+ <color name="system_weather_temp_light">#4F659A</color>
+ <color name="system_widget_background_light">#EEF0FF</color>
<color name="system_brand_a_dark">#B0C6FF</color>
<color name="system_brand_b_dark">#DCE2F9</color>
<color name="system_brand_c_dark">#7A90C8</color>
<color name="system_brand_d_dark">#FDD7FA</color>
- <color name="system_under_surface_dark">#000000</color>
-<color name="system_shade_active_dark">#D9E2FF</color>
+ <color name="system_clock_hour_dark">#8A90A5</color>
+ <color name="system_clock_minute_dark">#D9E2FF</color>
+ <color name="system_clock_second_dark">#FDD7FA</color>
<color name="system_on_shade_active_dark">#001945</color>
<color name="system_on_shade_active_variant_dark">#2F4578</color>
- <color name="system_shade_inactive_dark">#2F3036</color>
<color name="system_on_shade_inactive_dark">#E1E2EC</color>
<color name="system_on_shade_inactive_variant_dark">#C5C6D0</color>
- <color name="system_shade_disabled_dark">#0C0E13</color>
+ <color name="system_on_theme_app_dark">#B0C6FF</color>
<color name="system_overview_background_dark">#50525A</color>
+ <color name="system_shade_active_dark">#D9E2FF</color>
+ <color name="system_shade_disabled_dark">#0C0E13</color>
+ <color name="system_shade_inactive_dark">#2F3036</color>
+ <color name="system_theme_app_dark">#2F4578</color>
+ <color name="system_theme_app_ring_dark">#94AAE4</color>
+ <color name="system_theme_notif_dark">#FDD7FA</color>
+ <color name="system_under_surface_dark">#000000</color>
+ <color name="system_weather_temp_dark">#B0C6FF</color>
+ <color name="system_widget_background_dark">#152E60</color>
<!-- Accessibility shortcut icon background color -->
<color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 -->
diff --git a/core/res/res/values/colors_dynamic.xml b/core/res/res/values/colors_dynamic.xml
new file mode 100644
index 000000000000..ab283eb3c6c8
--- /dev/null
+++ b/core/res/res/values/colors_dynamic.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- Colors specific to Material themes. -->
+<resources>
+ <color name="materialColorBackground">@color/system_background_light</color>
+ <color name="materialColorControlActivated">@color/system_control_activated_light</color>
+ <color name="materialColorControlHighlight">@color/system_control_highlight_light</color>
+ <color name="materialColorControlNormal">@color/system_control_normal_light</color>
+ <color name="materialColorError">@color/system_error_light</color>
+ <color name="materialColorErrorContainer">@color/system_error_container_light</color>
+ <color name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</color>
+ <color name="materialColorInversePrimary">@color/system_inverse_primary_light</color>
+ <color name="materialColorInverseSurface">@color/system_inverse_surface_light</color>
+ <color name="materialColorOnBackground">@color/system_on_background_light</color>
+ <color name="materialColorOnError">@color/system_on_error_light</color>
+ <color name="materialColorOnErrorContainer">@color/system_on_error_container_light</color>
+ <color name="materialColorOnPrimary">@color/system_on_primary_light</color>
+ <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</color>
+ <color name="materialColorOnSecondary">@color/system_on_secondary_light</color>
+ <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</color>
+ <color name="materialColorOnSurface">@color/system_on_surface_light</color>
+ <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</color>
+ <color name="materialColorOnTertiary">@color/system_on_tertiary_light</color>
+ <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</color>
+ <color name="materialColorOutline">@color/system_outline_light</color>
+ <color name="materialColorOutlineVariant">@color/system_outline_variant_light</color>
+ <color name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</color>
+ <color name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</color>
+ <color name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</color>
+ <color name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</color>
+ <color name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</color>
+ <color name="materialColorPrimary">@color/system_primary_light</color>
+ <color name="materialColorPrimaryContainer">@color/system_primary_container_light</color>
+ <color name="materialColorScrim">@color/system_scrim_light</color>
+ <color name="materialColorSecondary">@color/system_secondary_light</color>
+ <color name="materialColorSecondaryContainer">@color/system_secondary_container_light</color>
+ <color name="materialColorShadow">@color/system_shadow_light</color>
+ <color name="materialColorSurface">@color/system_surface_light</color>
+ <color name="materialColorSurfaceBright">@color/system_surface_bright_light</color>
+ <color name="materialColorSurfaceContainer">@color/system_surface_container_light</color>
+ <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</color>
+ <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</color>
+ <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</color>
+ <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</color>
+ <color name="materialColorSurfaceDim">@color/system_surface_dim_light</color>
+ <color name="materialColorSurfaceTint">@color/system_surface_tint_light</color>
+ <color name="materialColorSurfaceVariant">@color/system_surface_variant_light</color>
+ <color name="materialColorTertiary">@color/system_tertiary_light</color>
+ <color name="materialColorTertiaryContainer">@color/system_tertiary_container_light</color>
+ <color name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</color>
+ <color name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</color>
+ <color name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</color>
+ <color name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</color>
+ <color name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</color>
+ <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color>
+ <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color>
+ <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color>
+ <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color>
+ <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color>
+ <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color>
+ <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color>
+ <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color>
+ <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color>
+ <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color>
+ <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color>
+ <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color>
+ <color name="customColorBrandA">@color/system_brand_a_light</color>
+ <color name="customColorBrandB">@color/system_brand_b_light</color>
+ <color name="customColorBrandC">@color/system_brand_c_light</color>
+ <color name="customColorBrandD">@color/system_brand_d_light</color>
+ <color name="customColorClockHour">@color/system_clock_hour_light</color>
+ <color name="customColorClockMinute">@color/system_clock_minute_light</color>
+ <color name="customColorClockSecond">@color/system_clock_second_light</color>
+ <color name="customColorOnShadeActive">@color/system_on_shade_active_light</color>
+ <color name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</color>
+ <color name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</color>
+ <color name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</color>
+ <color name="customColorOnThemeApp">@color/system_on_theme_app_light</color>
+ <color name="customColorOverviewBackground">@color/system_overview_background_light</color>
+ <color name="customColorShadeActive">@color/system_shade_active_light</color>
+ <color name="customColorShadeDisabled">@color/system_shade_disabled_light</color>
+ <color name="customColorShadeInactive">@color/system_shade_inactive_light</color>
+ <color name="customColorThemeApp">@color/system_theme_app_light</color>
+ <color name="customColorThemeAppRing">@color/system_theme_app_ring_light</color>
+ <color name="customColorThemeNotif">@color/system_theme_notif_light</color>
+ <color name="customColorUnderSurface">@color/system_under_surface_light</color>
+ <color name="customColorWeatherTemp">@color/system_weather_temp_light</color>
+ <color name="customColorWidgetBackground">@color/system_widget_background_light</color>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dc054a4a48ea..38ebda733270 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1849,6 +1849,10 @@
<item>-1</item>
</integer-array>
+ <!-- Specifies the delay in milliseconds after the last user input before turning off the
+ keyboard backlight.
+ -->
+ <integer name="config_keyboardBacklightTimeoutMs">30000</integer>
<!-- An array describing the screen's backlight values corresponding to the brightness
values in the config_screenBrightnessNits array.
@@ -2727,6 +2731,8 @@
</string-array>
<!-- The list of supported dream complications -->
<integer-array name="config_supportedDreamComplications">
+ <!-- COMPLICATION_TYPE_TIME -->
+ <item>1</item>
</integer-array>
<!-- Are we allowed to dream while not plugged in? -->
@@ -4201,9 +4207,17 @@
must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
<string translatable="false" name="config_cameraLaunchGestureSensorStringType"></string>
+ <!-- Allow the gesture to double tap the power button to trigger a target action. -->
+ <bool name="config_doubleTapPowerGestureEnabled">true</bool>
<!-- Allow the gesture to double tap the power button twice to start the camera while the device
is non-interactive. -->
<bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
+ <!-- Allow the gesture to double tap the power button twice to launch the wallet. -->
+ <bool name="config_walletDoubleTapPowerGestureEnabled">true</bool>
+ <!-- Default target action for double tap of the power button gesture.
+ 0: Launch camera
+ 1: Launch wallet -->
+ <integer name="config_defaultDoubleTapPowerGestureAction">0</integer>
<!-- Allow the gesture to quick tap the power button multiple times to start the emergency sos
experience while the device is non-interactive. -->
@@ -5894,6 +5908,11 @@
<!-- <item>com.android.settings</item> -->
</string-array>
+ <!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner
+ SET_DEFAULT_ACCOUNT_FOR_CONTACTS permissions. The digest should be computed over the DER
+ encoding of the trusted certificate using the SHA-256 digest algorithm. -->
+ <string-array name="config_setContactsDefaultAccountKnownSigners">
+ </string-array>
<!-- Class name of the custom country detector to be used. -->
<string name="config_customCountryDetector" translatable="false">com.android.server.location.ComprehensiveCountryDetector</string>
@@ -6563,7 +6582,7 @@
</string-array>
<!-- the number of the max cached processes in the system. -->
- <integer name="config_customizedMaxCachedProcesses">32</integer>
+ <integer name="config_customizedMaxCachedProcesses">1024</integer>
<!-- Whether this device should support taking app snapshots on closure -->
<bool name="config_disableTaskSnapshots">false</bool>
@@ -7167,6 +7186,10 @@
screen. -->
<bool name="config_dragToMaximizeInDesktopMode">false</bool>
+ <!-- Whether showing the app handle is supported on this device.
+ If config_isDesktopModeSupported, then this has no effect -->
+ <bool name="config_enableAppHandle">false</bool>
+
<!-- Frame rate compatibility value for Wallpaper
FRAME_RATE_COMPATIBILITY_MIN (102) is used by default for lower power consumption -->
<integer name="config_wallpaperFrameRateCompatibility">102</integer>
@@ -7208,9 +7231,18 @@
<!-- Package for opening identity check settings page [CHAR LIMIT=NONE] [DO NOT TRANSLATE] -->
<string name="identity_check_settings_package_name">com\u002eandroid\u002esettings</string>
- <!-- The name of the service for forensic backup transport. -->
- <string name="config_forensicBackupTransport" translatable="false"></string>
+ <!-- The name of the service for intrusion detection event transport. -->
+ <string name="config_intrusionDetectionEventTransport" translatable="false"></string>
<!-- Whether to enable fp unlock when screen turns off on udfps devices -->
<bool name="config_screen_off_udfps_enabled">false</bool>
+
+ <!-- The name of the system package that will hold the dependency installer role. -->
+ <string name="config_systemDependencyInstaller" translatable="false" />
+
+ <!-- Whether allow normal brightness when doze policy can be requested. When this is false,
+ brightness follows the display state i.e. ON means bright, DOZE means dim. If true,
+ POLICY_DOZE can also dim the screen unless parameter useNormalBrightnessForDoze of
+ DreamService#setDozeScreenState requests an exception. -->
+ <bool name="config_allowNormalBrightnessForDozePolicy">false</bool>
</resources>
diff --git a/core/res/res/values/config_display.xml b/core/res/res/values/config_display.xml
index 2e66060926fd..c458d0e9a3c0 100644
--- a/core/res/res/values/config_display.xml
+++ b/core/res/res/values/config_display.xml
@@ -29,5 +29,7 @@
<!-- Whether even dimmer feature is enabled. -->
<bool name="config_evenDimmerEnabled">false</bool>
+ <!-- Jar file path to look for PluginProvider -->
+ <string name="config_pluginsProviderJarPath"/>
</resources>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 31e9913dd988..e8063a27d77b 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -318,6 +318,12 @@
<bool name="config_oem_enabled_satellite_access_allow">true</bool>
<java-symbol type="bool" name="config_oem_enabled_satellite_access_allow" />
+ <!-- Whether the satellite modem support concurrent TN scanning while device is in
+ NTN mode.
+ -->
+ <bool name="config_satellite_modem_support_concurrent_tn_scanning">true</bool>
+ <java-symbol type="bool" name="config_satellite_modem_support_concurrent_tn_scanning" />
+
<!-- The time duration in seconds which is used to decide whether the Location returned from
LocationManager#getLastKnownLocation is fresh.
@@ -460,6 +466,11 @@
<integer name="config_satellite_location_query_throttle_interval_minutes">10</integer>
<java-symbol type="integer" name="config_satellite_location_query_throttle_interval_minutes" />
+ <!-- The file contains satellite access configuration like supported frequencies, bands,
+ satellite positions, and so on -->
+ <string name="satellite_access_config_file" translatable="false"></string>
+ <java-symbol type="string" name="satellite_access_config_file" />
+
<!-- Boolean indicating whether to enable MT SMS polling for NB IOT NTN. -->
<bool name="config_enabled_mt_sms_polling">true</bool>
<java-symbol type="bool" name="config_enabled_mt_sms_polling" />
@@ -478,7 +489,7 @@
<!-- Whether to show the system notification to users whenever there is a change
in the satellite availability state at the current location. -->
- <bool name="config_satellite_should_notify_availability">false</bool>
+ <bool name="config_satellite_should_notify_availability">true</bool>
<java-symbol type="bool" name="config_satellite_should_notify_availability" />
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index db752065289e..c8df662eed6d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -247,9 +247,14 @@
<!-- Default padding for dialogs. -->
<dimen name="dialog_padding">16dp</dimen>
- <!-- The margin on the start of the content view (accommodates the icon) -->
+ <!-- The margin on the start of the content view (accommodates the icon)
+ This represents 16dp for the left margin + 24dp for the icon + 12dp for the right margin -->
<dimen name="notification_content_margin_start">52dp</dimen>
+ <!-- The margin on the start of the content view (accommodates the icon), 2025 redesign version
+ This represents 16dp for the left margin + 40dp for the icon + 16dp for the right margin -->
+ <dimen name="notification_2025_content_margin_start">72dp</dimen>
+
<!-- The margin on the end of most content views (ignores the expander) -->
<dimen name="notification_content_margin_end">16dp</dimen>
@@ -310,6 +315,9 @@
<!-- height of the notification header -->
<dimen name="notification_header_height">56dp</dimen>
+ <!-- height of the notification header (2025 redesign version) -->
+ <dimen name="notification_2025_header_height">72dp</dimen>
+
<!-- The height of the background for a notification header on a group -->
<dimen name="notification_header_background_height">49.5dp</dimen>
@@ -331,9 +339,17 @@
<!-- size (width and height) of the circle around the icon in the notification header -->
<dimen name="notification_icon_circle_size">24dp</dimen>
+ <!-- size (width and height) of the circular icon in the notification header
+ (2025 redesign version) -->
+ <dimen name="notification_2025_icon_circle_size">40dp</dimen>
+
<!-- padding between the notification icon and the circle containing it -->
<dimen name="notification_icon_circle_padding">4dp</dimen>
+ <!-- padding between the notification icon and the circle containing it
+ (2025 redesign version) -->
+ <dimen name="notification_2025_icon_circle_padding">8dp</dimen>
+
<!-- start margin of the icon circle in the notification view -->
<dimen name="notification_icon_circle_start">16dp</dimen>
@@ -803,6 +819,8 @@
<dimen name="notification_right_icon_big_margin_top">16dp</dimen>
<!-- The size of the left icon -->
<dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen>
+ <!-- The size of the left icon (2025 redesign version) -->
+ <dimen name="notification_2025_left_icon_size">@dimen/notification_2025_icon_circle_size</dimen>
<!-- The left padding of the left icon -->
<dimen name="notification_left_icon_start">@dimen/notification_icon_circle_start</dimen>
<!-- The alpha of a disabled notification button -->
@@ -820,13 +838,13 @@
<!-- The gap between segments in the notification progress bar -->
<dimen name="notification_progress_segSeg_gap">2dp</dimen>
<!-- The gap between a segment and a point in the notification progress bar -->
- <dimen name="notification_progress_segPoint_gap">8dp</dimen>
- <!-- The dash gap of the notification progress bar segments -->
- <dimen name="notification_progress_segments_dash_gap">8dp</dimen>
- <!-- The dash width of the notification progress bar segments -->
- <dimen name="notification_progress_segments_dash_width">3dp</dimen>
+ <dimen name="notification_progress_segPoint_gap">4dp</dimen>
<!-- The height of the notification progress bar segments -->
<dimen name="notification_progress_segments_height">6dp</dimen>
+ <!-- The height of the notification progress bar faded segments -->
+ <dimen name="notification_progress_segments_faded_height">2dp</dimen>
+ <!-- The corner radius of the notification progress bar segments -->
+ <dimen name="notification_progress_segments_corner_radius">16dp</dimen>
<!-- The radius of the notification progress bar points -->
<dimen name="notification_progress_points_radius">6dp</dimen>
<!-- The corner radius of the notification progress bar points drawn as rects -->
@@ -1037,12 +1055,12 @@
<dimen name="controls_thumbnail_image_max_width">280dp</dimen>
<!-- System-provided radius for the background view of app widgets. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_background_radius" android:featureFlag="!android.appwidget.flags.use_smaller_app_widget_radius">28dp</dimen>
- <dimen name="system_app_widget_background_radius" android:featureFlag="android.appwidget.flags.use_smaller_app_widget_radius">24dp</dimen>
+ <dimen name="system_app_widget_background_radius" android:featureFlag="!android.appwidget.flags.use_smaller_app_widget_system_radius">28dp</dimen>
+ <dimen name="system_app_widget_background_radius" android:featureFlag="android.appwidget.flags.use_smaller_app_widget_system_radius">24dp</dimen>
<!-- System-provided radius for inner views on app widgets that are positioned 8dp within the widget background view. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_inner_radius" android:featureFlag="!android.appwidget.flags.use_smaller_app_widget_radius">20dp</dimen>
+ <dimen name="system_app_widget_inner_radius" android:featureFlag="!android.appwidget.flags.use_smaller_app_widget_system_radius">20dp</dimen>
<!-- System-provided radius for inner views on app widgets that are positioned 8dp within the widget background view. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_inner_radius" android:featureFlag="android.appwidget.flags.use_smaller_app_widget_radius">16dp</dimen>
+ <dimen name="system_app_widget_inner_radius" android:featureFlag="android.appwidget.flags.use_smaller_app_widget_system_radius">16dp</dimen>
<!-- System-provided padding for inner views on app widgets. The resolved value of this resource may change at runtime. @removed -->
<dimen name="__removed_system_app_widget_internal_padding">16dp</dimen>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index e71277dc0414..3b39a65b6795 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -290,4 +290,7 @@
<!-- View tag associating a view with its overridden id, to ensure valid recycling only. -->
<item type="id" name="remote_views_override_id" />
+
+ <!-- View tag associating a view with its id for widget metrics. -->
+ <item type="id" name="remoteViewsMetricsId" />
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index b6436d0b30a5..e75371d6bf46 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -131,21 +131,54 @@
<public name="alternateLauncherIcons"/>
<!-- @FlaggedApi(android.content.pm.Flags.FLAG_CHANGE_LAUNCHER_BADGING) -->
<public name="alternateLauncherLabels"/>
+ <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
+ <public name="pageSizeCompat" />
+ <!-- @FlaggedApi(android.nfc.Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES) -->
+ <public name="shareRolePriority"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01b60000">
+ <!-- @FlaggedApi(android.appwidget.flags.Flags.FLAG_ENGAGEMENT_METRICS) -->
+ <public name="remoteViewsMetricsId"/>
</staging-public-group>
<staging-public-group type="style" first-id="0x01b50000">
</staging-public-group>
<staging-public-group type="string" first-id="0x01b40000">
+ <!-- @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+ @hide @SystemApi -->
+ <public name="config_systemDependencyInstaller" />
</staging-public-group>
<staging-public-group type="dimen" first-id="0x01b30000">
</staging-public-group>
<staging-public-group type="color" first-id="0x01b20000">
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_inverse_on_surface_light"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_inverse_primary_light"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_inverse_surface_light"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_scrim_light"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_shadow_light"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_surface_tint_light"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_inverse_on_surface_dark"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_inverse_primary_dark"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_inverse_surface_dark"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_scrim_dark"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_shadow_dark"/>
+ <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+ <public name="system_surface_tint_dark"/>
</staging-public-group>
<staging-public-group type="array" first-id="0x01b10000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c13fdb17dfe3..413f0c3e0c58 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5357,6 +5357,8 @@
<string name="zen_mode_trigger_summary_range_symbol_combination"><xliff:g id="start" example="Sun">%1$s</xliff:g> - <xliff:g id="end" example="Thu">%2$s</xliff:g></string>
<!-- [CHAR LIMIT=40] General template for a start - end range in a text summary, used for the trigger description of a Zen mode -->
<string name="zen_mode_trigger_summary_range_words"><xliff:g id="start" example="Sunday">%1$s</xliff:g> to <xliff:g id="end" example="Thursday">%2$s</xliff:g></string>
+ <!-- [CHAR LIMIT=NONE] General template for combining a days of week start-end range with a time-based start-end range, for example: "Sun-Thurs, 10:00 PM - 7:00 AM" -->
+ <string name="zen_mode_trigger_summary_combined"><xliff:g id="days" example="Sat-Thurs">%1$s</xliff:g>,\u0020<xliff:g id="times" example="10:00 PM - 7:00 AM">%2$s</xliff:g></string>
<!-- [CHAR LIMIT=40] Event-based rule calendar option value for any calendar, used for the trigger description of a Zen mode -->
<string name="zen_mode_trigger_event_calendar_any">Any calendar</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 3b2f24409a88..acc1ff8fb9db 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -43,6 +43,7 @@ easier.
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="textColor">@color/btn_colored_text_material</item>
</style>
+ <style name="Widget.DeviceDefault.Button.WearMaterial3"/>
<style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView" />
<style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
<style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 848ec069cb40..fc24f4599b25 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2098,6 +2098,7 @@
<java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/>
<java-symbol type="integer" name="config_autoBrightnessInitialLightSensorRate"/>
<java-symbol type="integer" name="config_autoBrightnessLightSensorRate"/>
+ <java-symbol type="integer" name="config_keyboardBacklightTimeoutMs" />
<java-symbol type="integer" name="config_carDockKeepsScreenOn" />
<java-symbol type="integer" name="config_criticalBatteryWarningLevel" />
<java-symbol type="integer" name="config_datause_notification_type" />
@@ -2388,6 +2389,10 @@
<java-symbol type="layout" name="notification_material_action" />
<java-symbol type="layout" name="notification_material_action_list" />
<java-symbol type="layout" name="notification_material_action_tombstone" />
+ <java-symbol type="layout" name="notification_2025_template_collapsed_base" />
+ <java-symbol type="layout" name="notification_2025_template_expanded_base" />
+ <java-symbol type="layout" name="notification_2025_template_heads_up_base" />
+ <java-symbol type="layout" name="notification_2025_template_header" />
<java-symbol type="layout" name="notification_template_material_base" />
<java-symbol type="layout" name="notification_template_material_heads_up_base" />
<java-symbol type="layout" name="notification_template_material_compact_heads_up_base" />
@@ -2662,6 +2667,7 @@
<java-symbol type="string" name="zen_mode_trigger_summary_divider_text" />
<java-symbol type="string" name="zen_mode_trigger_summary_range_symbol_combination" />
<java-symbol type="string" name="zen_mode_trigger_summary_range_words" />
+ <java-symbol type="string" name="zen_mode_trigger_summary_combined" />
<java-symbol type="string" name="zen_mode_trigger_event_calendar_any" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
@@ -3139,9 +3145,12 @@
<!-- Gesture -->
<java-symbol type="integer" name="config_cameraLaunchGestureSensorType" />
<java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" />
- <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
<java-symbol type="integer" name="config_cameraLiftTriggerSensorType" />
<java-symbol type="string" name="config_cameraLiftTriggerSensorStringType" />
+ <java-symbol type="bool" name="config_doubleTapPowerGestureEnabled" />
+ <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
+ <java-symbol type="bool" name="config_walletDoubleTapPowerGestureEnabled" />
+ <java-symbol type="integer" name="config_defaultDoubleTapPowerGestureAction" />
<java-symbol type="bool" name="config_emergencyGestureEnabled" />
<java-symbol type="bool" name="config_defaultEmergencyGestureEnabled" />
<java-symbol type="bool" name="config_defaultEmergencyGestureSoundEnabled" />
@@ -3875,9 +3884,9 @@
<java-symbol type="dimen" name="notification_progress_tracker_height" />
<java-symbol type="dimen" name="notification_progress_segSeg_gap" />
<java-symbol type="dimen" name="notification_progress_segPoint_gap" />
- <java-symbol type="dimen" name="notification_progress_segments_dash_gap" />
- <java-symbol type="dimen" name="notification_progress_segments_dash_width" />
<java-symbol type="dimen" name="notification_progress_segments_height" />
+ <java-symbol type="dimen" name="notification_progress_segments_faded_height" />
+ <java-symbol type="dimen" name="notification_progress_segments_corner_radius" />
<java-symbol type="dimen" name="notification_progress_points_radius" />
<java-symbol type="dimen" name="notification_progress_points_corner_radius" />
<java-symbol type="dimen" name="notification_progress_points_inset" />
@@ -5309,73 +5318,176 @@
<java-symbol type="integer" name="config_aggregatedPowerStatsSpanDuration" />
<java-symbol type="integer" name="config_accumulatedBatteryUsageStatsSpanSize" />
- <java-symbol name="materialColorOnSecondaryFixedVariant" type="attr"/>
- <java-symbol name="materialColorOnTertiaryFixedVariant" type="attr"/>
- <java-symbol name="materialColorSurfaceContainerLowest" type="attr"/>
- <java-symbol name="materialColorOnPrimaryFixedVariant" type="attr"/>
- <java-symbol name="materialColorOnSecondaryContainer" type="attr"/>
- <java-symbol name="materialColorOnTertiaryContainer" type="attr"/>
- <java-symbol name="materialColorSurfaceContainerLow" type="attr"/>
- <java-symbol name="materialColorOnPrimaryContainer" type="attr"/>
- <java-symbol name="materialColorSecondaryFixedDim" type="attr"/>
- <java-symbol name="materialColorOnErrorContainer" type="attr"/>
- <java-symbol name="materialColorOnSecondaryFixed" type="attr"/>
- <java-symbol name="materialColorOnSurfaceInverse" type="attr"/>
- <java-symbol name="materialColorTertiaryFixedDim" type="attr"/>
- <java-symbol name="materialColorOnTertiaryFixed" type="attr"/>
- <java-symbol name="materialColorPrimaryFixedDim" type="attr"/>
- <java-symbol name="materialColorSecondaryContainer" type="attr"/>
- <java-symbol name="materialColorErrorContainer" type="attr"/>
- <java-symbol name="materialColorOnPrimaryFixed" type="attr"/>
- <java-symbol name="materialColorPrimaryInverse" type="attr"/>
- <java-symbol name="materialColorSecondaryFixed" type="attr"/>
- <java-symbol name="materialColorSurfaceInverse" type="attr"/>
- <java-symbol name="materialColorSurfaceVariant" type="attr"/>
- <java-symbol name="materialColorTertiaryContainer" type="attr"/>
- <java-symbol name="materialColorTertiaryFixed" type="attr"/>
- <java-symbol name="materialColorPrimaryContainer" type="attr"/>
- <java-symbol name="materialColorOnBackground" type="attr"/>
- <java-symbol name="materialColorPrimaryFixed" type="attr"/>
- <java-symbol name="materialColorOnSecondary" type="attr"/>
- <java-symbol name="materialColorOnTertiary" type="attr"/>
- <java-symbol name="materialColorSurfaceDim" type="attr"/>
- <java-symbol name="materialColorSurfaceBright" type="attr"/>
- <java-symbol name="materialColorOnError" type="attr"/>
- <java-symbol name="materialColorSurface" type="attr"/>
- <java-symbol name="materialColorSurfaceContainerHigh" type="attr"/>
- <java-symbol name="materialColorSurfaceContainerHighest" type="attr"/>
- <java-symbol name="materialColorOnSurfaceVariant" type="attr"/>
- <java-symbol name="materialColorOutline" type="attr"/>
- <java-symbol name="materialColorOutlineVariant" type="attr"/>
- <java-symbol name="materialColorOnPrimary" type="attr"/>
- <java-symbol name="materialColorOnSurface" type="attr"/>
- <java-symbol name="materialColorSurfaceContainer" type="attr"/>
- <java-symbol name="materialColorPrimary" type="attr"/>
- <java-symbol name="materialColorSecondary" type="attr"/>
- <java-symbol name="materialColorTertiary" type="attr"/>
- <java-symbol name="materialColorError" type="attr"/>
-
- <java-symbol name="customColorWidgetBackground" type="attr"/>
- <java-symbol name="customColorClockHour" type="attr"/>
- <java-symbol name="customColorClockMinute" type="attr"/>
- <java-symbol name="customColorClockSecond" type="attr"/>
- <java-symbol name="customColorThemeApp" type="attr"/>
- <java-symbol name="customColorOnThemeApp" type="attr"/>
- <java-symbol name="customColorThemeAppRing" type="attr"/>
- <java-symbol name="customColorThemeNotif" type="attr"/>
- <java-symbol name="customColorBrandA" type="attr"/>
- <java-symbol name="customColorBrandB" type="attr"/>
- <java-symbol name="customColorBrandC" type="attr"/>
- <java-symbol name="customColorBrandD" type="attr"/>
- <java-symbol name="customColorUnderSurface" type="attr"/>
- <java-symbol name="customColorShadeActive" type="attr"/>
- <java-symbol name="customColorOnShadeActive" type="attr"/>
- <java-symbol name="customColorOnShadeActiveVariant" type="attr"/>
- <java-symbol name="customColorShadeInactive" type="attr"/>
- <java-symbol name="customColorOnShadeInactive" type="attr"/>
- <java-symbol name="customColorOnShadeInactiveVariant" type="attr"/>
- <java-symbol name="customColorShadeDisabled" type="attr"/>
- <java-symbol name="customColorOverviewBackground" type="attr"/>
+ <!--Dynamic Tokens-->
+ <java-symbol name="materialColorBackground" type="color"/>
+ <java-symbol name="materialColorControlActivated" type="color"/>
+ <java-symbol name="materialColorControlHighlight" type="color"/>
+ <java-symbol name="materialColorControlNormal" type="color"/>
+ <java-symbol name="materialColorError" type="color"/>
+ <java-symbol name="materialColorErrorContainer" type="color"/>
+ <java-symbol name="materialColorInverseOnSurface" type="color"/>
+ <java-symbol name="materialColorInversePrimary" type="color"/>
+ <java-symbol name="materialColorInverseSurface" type="color"/>
+ <java-symbol name="materialColorOnBackground" type="color"/>
+ <java-symbol name="materialColorOnError" type="color"/>
+ <java-symbol name="materialColorOnErrorContainer" type="color"/>
+ <java-symbol name="materialColorOnPrimary" type="color"/>
+ <java-symbol name="materialColorOnPrimaryContainer" type="color"/>
+ <java-symbol name="materialColorOnSecondary" type="color"/>
+ <java-symbol name="materialColorOnSecondaryContainer" type="color"/>
+ <java-symbol name="materialColorOnSurface" type="color"/>
+ <java-symbol name="materialColorOnSurfaceVariant" type="color"/>
+ <java-symbol name="materialColorOnTertiary" type="color"/>
+ <java-symbol name="materialColorOnTertiaryContainer" type="color"/>
+ <java-symbol name="materialColorOutline" type="color"/>
+ <java-symbol name="materialColorOutlineVariant" type="color"/>
+ <java-symbol name="materialColorPaletteKeyColorNeutral" type="color"/>
+ <java-symbol name="materialColorPaletteKeyColorNeutralVariant" type="color"/>
+ <java-symbol name="materialColorPaletteKeyColorPrimary" type="color"/>
+ <java-symbol name="materialColorPaletteKeyColorSecondary" type="color"/>
+ <java-symbol name="materialColorPaletteKeyColorTertiary" type="color"/>
+ <java-symbol name="materialColorPrimary" type="color"/>
+ <java-symbol name="materialColorPrimaryContainer" type="color"/>
+ <java-symbol name="materialColorScrim" type="color"/>
+ <java-symbol name="materialColorSecondary" type="color"/>
+ <java-symbol name="materialColorSecondaryContainer" type="color"/>
+ <java-symbol name="materialColorShadow" type="color"/>
+ <java-symbol name="materialColorSurface" type="color"/>
+ <java-symbol name="materialColorSurfaceBright" type="color"/>
+ <java-symbol name="materialColorSurfaceContainer" type="color"/>
+ <java-symbol name="materialColorSurfaceContainerHigh" type="color"/>
+ <java-symbol name="materialColorSurfaceContainerHighest" type="color"/>
+ <java-symbol name="materialColorSurfaceContainerLow" type="color"/>
+ <java-symbol name="materialColorSurfaceContainerLowest" type="color"/>
+ <java-symbol name="materialColorSurfaceDim" type="color"/>
+ <java-symbol name="materialColorSurfaceTint" type="color"/>
+ <java-symbol name="materialColorSurfaceVariant" type="color"/>
+ <java-symbol name="materialColorTertiary" type="color"/>
+ <java-symbol name="materialColorTertiaryContainer" type="color"/>
+ <java-symbol name="materialColorTextHintInverse" type="color"/>
+ <java-symbol name="materialColorTextPrimaryInverse" type="color"/>
+ <java-symbol name="materialColorTextPrimaryInverseDisableOnly" type="color"/>
+ <java-symbol name="materialColorTextSecondaryAndTertiaryInverse" type="color"/>
+ <java-symbol name="materialColorTextSecondaryAndTertiaryInverseDisabled" type="color"/>
+ <java-symbol name="materialColorOnPrimaryFixed" type="color"/>
+ <java-symbol name="materialColorOnPrimaryFixedVariant" type="color"/>
+ <java-symbol name="materialColorOnSecondaryFixed" type="color"/>
+ <java-symbol name="materialColorOnSecondaryFixedVariant" type="color"/>
+ <java-symbol name="materialColorOnTertiaryFixed" type="color"/>
+ <java-symbol name="materialColorOnTertiaryFixedVariant" type="color"/>
+ <java-symbol name="materialColorPrimaryFixed" type="color"/>
+ <java-symbol name="materialColorPrimaryFixedDim" type="color"/>
+ <java-symbol name="materialColorSecondaryFixed" type="color"/>
+ <java-symbol name="materialColorSecondaryFixedDim" type="color"/>
+ <java-symbol name="materialColorTertiaryFixed" type="color"/>
+ <java-symbol name="materialColorTertiaryFixedDim" type="color"/>
+ <java-symbol name="customColorBrandA" type="color"/>
+ <java-symbol name="customColorBrandB" type="color"/>
+ <java-symbol name="customColorBrandC" type="color"/>
+ <java-symbol name="customColorBrandD" type="color"/>
+ <java-symbol name="customColorClockHour" type="color"/>
+ <java-symbol name="customColorClockMinute" type="color"/>
+ <java-symbol name="customColorClockSecond" type="color"/>
+ <java-symbol name="customColorOnShadeActive" type="color"/>
+ <java-symbol name="customColorOnShadeActiveVariant" type="color"/>
+ <java-symbol name="customColorOnShadeInactive" type="color"/>
+ <java-symbol name="customColorOnShadeInactiveVariant" type="color"/>
+ <java-symbol name="customColorOnThemeApp" type="color"/>
+ <java-symbol name="customColorOverviewBackground" type="color"/>
+ <java-symbol name="customColorShadeActive" type="color"/>
+ <java-symbol name="customColorShadeDisabled" type="color"/>
+ <java-symbol name="customColorShadeInactive" type="color"/>
+ <java-symbol name="customColorThemeApp" type="color"/>
+ <java-symbol name="customColorThemeAppRing" type="color"/>
+ <java-symbol name="customColorThemeNotif" type="color"/>
+ <java-symbol name="customColorUnderSurface" type="color"/>
+ <java-symbol name="customColorWeatherTemp" type="color"/>
+ <java-symbol name="customColorWidgetBackground" type="color"/>
+
+ <java-symbol type="attr" name="materialColorBackground"/>
+ <java-symbol type="attr" name="materialColorControlActivated"/>
+ <java-symbol type="attr" name="materialColorControlHighlight"/>
+ <java-symbol type="attr" name="materialColorControlNormal"/>
+ <java-symbol type="attr" name="materialColorError"/>
+ <java-symbol type="attr" name="materialColorErrorContainer"/>
+ <java-symbol type="attr" name="materialColorInverseOnSurface"/>
+ <java-symbol type="attr" name="materialColorInversePrimary"/>
+ <java-symbol type="attr" name="materialColorInverseSurface"/>
+ <java-symbol type="attr" name="materialColorOnBackground"/>
+ <java-symbol type="attr" name="materialColorOnError"/>
+ <java-symbol type="attr" name="materialColorOnErrorContainer"/>
+ <java-symbol type="attr" name="materialColorOnPrimary"/>
+ <java-symbol type="attr" name="materialColorOnPrimaryContainer"/>
+ <java-symbol type="attr" name="materialColorOnSecondary"/>
+ <java-symbol type="attr" name="materialColorOnSecondaryContainer"/>
+ <java-symbol type="attr" name="materialColorOnSurface"/>
+ <java-symbol type="attr" name="materialColorOnSurfaceVariant"/>
+ <java-symbol type="attr" name="materialColorOnTertiary"/>
+ <java-symbol type="attr" name="materialColorOnTertiaryContainer"/>
+ <java-symbol type="attr" name="materialColorOutline"/>
+ <java-symbol type="attr" name="materialColorOutlineVariant"/>
+ <java-symbol type="attr" name="materialColorPaletteKeyColorNeutral"/>
+ <java-symbol type="attr" name="materialColorPaletteKeyColorNeutralVariant"/>
+ <java-symbol type="attr" name="materialColorPaletteKeyColorPrimary"/>
+ <java-symbol type="attr" name="materialColorPaletteKeyColorSecondary"/>
+ <java-symbol type="attr" name="materialColorPaletteKeyColorTertiary"/>
+ <java-symbol type="attr" name="materialColorPrimary"/>
+ <java-symbol type="attr" name="materialColorPrimaryContainer"/>
+ <java-symbol type="attr" name="materialColorScrim"/>
+ <java-symbol type="attr" name="materialColorSecondary"/>
+ <java-symbol type="attr" name="materialColorSecondaryContainer"/>
+ <java-symbol type="attr" name="materialColorShadow"/>
+ <java-symbol type="attr" name="materialColorSurface"/>
+ <java-symbol type="attr" name="materialColorSurfaceBright"/>
+ <java-symbol type="attr" name="materialColorSurfaceContainer"/>
+ <java-symbol type="attr" name="materialColorSurfaceContainerHigh"/>
+ <java-symbol type="attr" name="materialColorSurfaceContainerHighest"/>
+ <java-symbol type="attr" name="materialColorSurfaceContainerLow"/>
+ <java-symbol type="attr" name="materialColorSurfaceContainerLowest"/>
+ <java-symbol type="attr" name="materialColorSurfaceDim"/>
+ <java-symbol type="attr" name="materialColorSurfaceTint"/>
+ <java-symbol type="attr" name="materialColorSurfaceVariant"/>
+ <java-symbol type="attr" name="materialColorTertiary"/>
+ <java-symbol type="attr" name="materialColorTertiaryContainer"/>
+ <java-symbol type="attr" name="materialColorTextHintInverse"/>
+ <java-symbol type="attr" name="materialColorTextPrimaryInverse"/>
+ <java-symbol type="attr" name="materialColorTextPrimaryInverseDisableOnly"/>
+ <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverse"/>
+ <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverseDisabled"/>
+ <java-symbol type="attr" name="materialColorOnPrimaryFixed"/>
+ <java-symbol type="attr" name="materialColorOnPrimaryFixedVariant"/>
+ <java-symbol type="attr" name="materialColorOnSecondaryFixed"/>
+ <java-symbol type="attr" name="materialColorOnSecondaryFixedVariant"/>
+ <java-symbol type="attr" name="materialColorOnTertiaryFixed"/>
+ <java-symbol type="attr" name="materialColorOnTertiaryFixedVariant"/>
+ <java-symbol type="attr" name="materialColorPrimaryFixed"/>
+ <java-symbol type="attr" name="materialColorPrimaryFixedDim"/>
+ <java-symbol type="attr" name="materialColorSecondaryFixed"/>
+ <java-symbol type="attr" name="materialColorSecondaryFixedDim"/>
+ <java-symbol type="attr" name="materialColorTertiaryFixed"/>
+ <java-symbol type="attr" name="materialColorTertiaryFixedDim"/>
+ <java-symbol type="attr" name="customColorBrandA"/>
+ <java-symbol type="attr" name="customColorBrandB"/>
+ <java-symbol type="attr" name="customColorBrandC"/>
+ <java-symbol type="attr" name="customColorBrandD"/>
+ <java-symbol type="attr" name="customColorClockHour"/>
+ <java-symbol type="attr" name="customColorClockMinute"/>
+ <java-symbol type="attr" name="customColorClockSecond"/>
+ <java-symbol type="attr" name="customColorOnShadeActive"/>
+ <java-symbol type="attr" name="customColorOnShadeActiveVariant"/>
+ <java-symbol type="attr" name="customColorOnShadeInactive"/>
+ <java-symbol type="attr" name="customColorOnShadeInactiveVariant"/>
+ <java-symbol type="attr" name="customColorOnThemeApp"/>
+ <java-symbol type="attr" name="customColorOverviewBackground"/>
+ <java-symbol type="attr" name="customColorShadeActive"/>
+ <java-symbol type="attr" name="customColorShadeDisabled"/>
+ <java-symbol type="attr" name="customColorShadeInactive"/>
+ <java-symbol type="attr" name="customColorThemeApp"/>
+ <java-symbol type="attr" name="customColorThemeAppRing"/>
+ <java-symbol type="attr" name="customColorThemeNotif"/>
+ <java-symbol type="attr" name="customColorUnderSurface"/>
+ <java-symbol type="attr" name="customColorWeatherTemp"/>
+ <java-symbol type="attr" name="customColorWidgetBackground"/>
<java-symbol name="system_widget_background_light" type="color"/>
<java-symbol name="system_clock_hour_light" type="color"/>
@@ -5581,6 +5693,7 @@
<!-- DisplayManager configs. -->
<java-symbol type="bool" name="config_evenDimmerEnabled" />
+ <java-symbol type="string" name="config_pluginsProviderJarPath" />
<java-symbol type="bool" name="config_watchlistUseFileHashesCache" />
<java-symbol type="string" name="config_defaultContextualSearchPackageName" />
@@ -5609,6 +5722,9 @@
screen. -->
<java-symbol type="bool" name="config_dragToMaximizeInDesktopMode" />
+ <!-- Whether showing the app handle is supported on this device -->
+ <java-symbol type="bool" name="config_enableAppHandle" />
+
<!-- Frame rate compatibility value for Wallpaper -->
<java-symbol type="integer" name="config_wallpaperFrameRateCompatibility" />
@@ -5677,9 +5793,14 @@
<java-symbol type="string" name="identity_check_settings_action" />
<java-symbol type="string" name="identity_check_settings_package_name" />
- <!-- Forensic backup transport -->
- <java-symbol type="string" name="config_forensicBackupTransport" />
+ <!-- Intrusion detection event transport -->
+ <java-symbol type="string" name="config_intrusionDetectionEventTransport" />
<!-- Fingerprint screen off unlock config -->
<java-symbol type="bool" name="config_screen_off_udfps_enabled" />
+
+ <!-- Style for Wear Material3 Button. Will only be used for sdk 36 or above. -->
+ <java-symbol type="style" name="Widget.DeviceDefault.Button.WearMaterial3" />
+
+ <java-symbol type="bool" name="config_allowNormalBrightnessForDozePolicy" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 352c3904406c..d8346d87f624 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -239,73 +239,90 @@ easier.
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
@@ -357,73 +374,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
@@ -474,73 +508,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -593,73 +644,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -711,73 +779,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -837,73 +922,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -954,73 +1056,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -1070,73 +1189,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -1187,73 +1323,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -1320,73 +1473,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -1438,73 +1608,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -1554,73 +1741,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -1672,73 +1876,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1789,73 +2010,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1906,73 +2144,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -2023,73 +2278,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -2140,73 +2412,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
@@ -2257,73 +2546,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Theme for the dialog shown when an app crashes or ANRs. -->
@@ -2379,73 +2685,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -2494,73 +2817,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -2747,73 +3087,90 @@ easier.
<item name="colorPopupBackground">?attr/colorBackgroundFloating</item>
<item name="panelColorBackground">?attr/colorBackgroundFloating</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
@@ -2864,73 +3221,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -2980,73 +3354,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -3097,73 +3488,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -3216,73 +3624,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -3334,73 +3759,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -3458,73 +3900,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
@@ -3578,73 +4037,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -3697,73 +4173,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -3817,73 +4310,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -3918,73 +4428,90 @@ easier.
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
@@ -4019,73 +4546,90 @@ easier.
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
@@ -4139,73 +4683,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -4260,73 +4821,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -4379,73 +4957,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -4497,73 +5092,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -4614,73 +5226,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Light.Dialog.Alert" />
@@ -4731,73 +5360,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -4846,73 +5492,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
@@ -4968,74 +5631,90 @@ easier.
<item name="colorListDivider">@color/list_divider_color_light</item>
<item name="opacityListDivider">@color/list_divider_opacity_device_default_light</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.SystemUI" parent="Theme.DeviceDefault.Light">
@@ -5072,74 +5751,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.SystemUI.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -5168,74 +5863,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -5286,73 +5997,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog">
@@ -5387,73 +6115,90 @@ easier.
<!-- Dialog attributes -->
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase">
@@ -5528,73 +6273,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -5647,73 +6409,90 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
@@ -5792,73 +6571,90 @@ easier.
<item name="colorAccentSecondary">@color/system_secondary_dark</item>
<item name="colorAccentTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<style name="ThemeOverlay.DeviceDefault.Accent.Light">
@@ -5867,73 +6663,90 @@ easier.
<item name="colorAccentSecondary">@color/system_secondary_dark</item>
<item name="colorAccentTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. -->
@@ -5946,73 +6759,90 @@ easier.
<item name="colorAccentSecondary">@color/system_secondary_dark</item>
<item name="colorAccentTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen">
@@ -6021,73 +6851,90 @@ easier.
<item name="layout_gravity">center</item>
<item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorBackground">@color/system_background_light</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+ <item name="materialColorError">@color/system_error_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
<item name="materialColorOnBackground">@color/system_on_background_light</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
<item name="materialColorOnError">@color/system_on_error_light</item>
- <item name="materialColorSurface">@color/system_surface_light</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
<item name="materialColorOutline">@color/system_outline_light</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
- <item name="materialColorOnSurface">@color/system_on_surface_light</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
<item name="materialColorPrimary">@color/system_primary_light</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorScrim">@color/system_scrim_light</item>
<item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorShadow">@color/system_shadow_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
- <item name="materialColorError">@color/system_error_light</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
- <item name="customColorClockHour">@color/system_clock_hour_light</item>
- <item name="customColorClockMinute">@color/system_clock_minute_light</item>
- <item name="customColorClockSecond">@color/system_clock_second_light</item>
- <item name="customColorThemeApp">@color/system_theme_app_light</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_light</item>
<item name="customColorBrandB">@color/system_brand_b_light</item>
<item name="customColorBrandC">@color/system_brand_c_light</item>
<item name="customColorBrandD">@color/system_brand_d_light</item>
- <item name="customColorUnderSurface">@color/system_under_surface_light</item>
- <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
<item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
</style>
<style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification">
@@ -6107,73 +6954,90 @@ easier.
<item name="textColorPrimary">@color/system_neutral1_900</item>
<item name="textColorSecondary">@color/system_neutral2_700</item>
- <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
- <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
- <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
- <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
- <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
- <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
- <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
- <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorBackground">@color/system_background_dark</item>
+ <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+ <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+ <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+ <item name="materialColorError">@color/system_error_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
- <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
- <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
- <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+ <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+ <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
<item name="materialColorOnBackground">@color/system_on_background_dark</item>
- <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
<item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
<item name="materialColorOutline">@color/system_outline_dark</item>
<item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+ <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+ <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+ <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+ <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
<item name="materialColorPrimary">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+ <item name="materialColorScrim">@color/system_scrim_dark</item>
<item name="materialColorSecondary">@color/system_secondary_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+ <item name="materialColorShadow">@color/system_shadow_dark</item>
+ <item name="materialColorSurface">@color/system_surface_dark</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+ <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorError">@color/system_error_dark</item>
-
- <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
- <item name="customColorClockHour">@color/system_clock_hour_dark</item>
- <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
- <item name="customColorClockSecond">@color/system_clock_second_dark</item>
- <item name="customColorThemeApp">@color/system_theme_app_dark</item>
- <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
- <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
- <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+ <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+ <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+ <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+ <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+ <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+ <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+ <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+ <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+ <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+ <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+ <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+ <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+ <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+ <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="customColorBrandA">@color/system_brand_a_dark</item>
<item name="customColorBrandB">@color/system_brand_b_dark</item>
<item name="customColorBrandC">@color/system_brand_c_dark</item>
<item name="customColorBrandD">@color/system_brand_d_dark</item>
- <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
- <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
<item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
<item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
- <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
<item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
<item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
- <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
<item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
</style>
<style name="Theme.DeviceDefault.AutofillHalfScreenDialogList" parent="Theme.DeviceDefault.DayNight">
<item name="colorListDivider">@color/list_divider_opacity_device_default_light</item>
diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml
index 22d02262c388..e735784ee5bb 100644
--- a/core/res/res/xml/bookmarks.xml
+++ b/core/res/res/xml/bookmarks.xml
@@ -31,29 +31,37 @@
'u': Calculator
'y': YouTube
-->
-<bookmarks>
+<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<bookmark
role="android.app.role.BROWSER"
- shortcut="b" />
+ androidprv:keycode="KEYCODE_B"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CONTACTS"
- shortcut="c" />
+ androidprv:keycode="KEYCODE_C"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_EMAIL"
- shortcut="e" />
+ androidprv:keycode="KEYCODE_E"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CALENDAR"
- shortcut="k" />
+ androidprv:keycode="KEYCODE_K"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_MAPS"
- shortcut="m" />
+ androidprv:keycode="KEYCODE_M"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_MUSIC"
- shortcut="p" />
+ androidprv:keycode="KEYCODE_P"
+ androidprv:modifierState="META" />
<bookmark
role="android.app.role.SMS"
- shortcut="s" />
+ androidprv:keycode="KEYCODE_S"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CALCULATOR"
- shortcut="u" />
+ androidprv:keycode="KEYCODE_U"
+ androidprv:modifierState="META" />
</bookmarks>
diff --git a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
index 1721e1e2e935..f62d420510c3 100644
--- a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
+++ b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
@@ -79,7 +79,7 @@ public class EditorInfoTest {
TEST_EDITOR_INFO.label = "testLabel";
TEST_EDITOR_INFO.packageName = "android.view.inputmethod";
TEST_EDITOR_INFO.fieldId = 0;
- TEST_EDITOR_INFO.autofillId = AutofillId.NO_AUTOFILL_ID;
+ TEST_EDITOR_INFO.setAutofillId(AutofillId.NO_AUTOFILL_ID);
TEST_EDITOR_INFO.fieldName = "testField";
TEST_EDITOR_INFO.extras = new Bundle();
TEST_EDITOR_INFO.extras.putString("testKey", "testValue");
@@ -507,7 +507,8 @@ public class EditorInfoTest {
+ "prefix: supportedHandwritingGestureTypes=(none)\n"
+ "prefix: supportedHandwritingGesturePreviewTypes=(none)\n"
+ "prefix: isStylusHandwritingEnabled=false\n"
- + "prefix: contentMimeTypes=null\n");
+ + "prefix: contentMimeTypes=null\n"
+ + "prefix: writingToolsEnabled=true\n");
}
@Test
@@ -531,7 +532,7 @@ public class EditorInfoTest {
info.setStylusHandwritingEnabled(true);
}
info.packageName = "android.view.inputmethod";
- info.autofillId = new AutofillId(123);
+ info.setAutofillId(new AutofillId(123));
info.fieldId = 456;
info.fieldName = "testField";
info.extras = new Bundle();
@@ -539,6 +540,7 @@ public class EditorInfoTest {
info.hintLocales = LocaleList.forLanguageTags("en,es,zh");
info.contentMimeTypes = new String[] {"image/png"};
info.targetInputMethodUser = UserHandle.of(10);
+ info.setWritingToolsEnabled(false);
final StringBuilder sb = new StringBuilder();
info.dump(new StringBuilderPrinter(sb), "prefix2: ");
assertThat(sb.toString()).isEqualTo(
@@ -555,7 +557,8 @@ public class EditorInfoTest {
+ "prefix2: supportedHandwritingGesturePreviewTypes=SELECT\n"
+ "prefix2: isStylusHandwritingEnabled=" + isStylusHandwritingEnabled + "\n"
+ "prefix2: contentMimeTypes=[image/png]\n"
- + "prefix2: targetInputMethodUserId=10\n");
+ + "prefix2: targetInputMethodUserId=10\n"
+ + "prefix2: writingToolsEnabled=false\n");
}
@Test
@@ -576,7 +579,8 @@ public class EditorInfoTest {
+ "prefix: supportedHandwritingGestureTypes=(none)\n"
+ "prefix: supportedHandwritingGesturePreviewTypes=(none)\n"
+ "prefix: isStylusHandwritingEnabled=false\n"
- + "prefix: contentMimeTypes=null\n");
+ + "prefix: contentMimeTypes=null\n"
+ + "prefix: writingToolsEnabled=true\n");
}
@Test
@@ -597,7 +601,7 @@ public class EditorInfoTest {
@Test
public void testKindofEqualsComparesAutofillId() {
final EditorInfo infoCopy = TEST_EDITOR_INFO.createCopyInternal();
- infoCopy.autofillId = new AutofillId(42);
+ infoCopy.setAutofillId(new AutofillId(42));
assertFalse(TEST_EDITOR_INFO.kindofEquals(infoCopy));
}
@@ -621,4 +625,9 @@ public class EditorInfoTest {
infoCopy.extras.putString("testKey2", "testValue");
assertFalse(TEST_EDITOR_INFO.kindofEquals(infoCopy));
}
+
+ @Test
+ public void testWritingToolsEnabledbyDefault() {
+ assertTrue(TEST_EDITOR_INFO.isWritingToolsEnabled());
+ }
}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index f39508d6de15..49425572b256 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -152,6 +152,7 @@ android_test {
":HelloWorldUsingSdkMalformedNegativeVersion",
":CtsStaticSharedLibConsumerApp1",
":CtsStaticSharedLibConsumerApp3",
+ ":CtsStaticSharedLibProviderApp1",
],
}
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 5d8ff87eca24..bada7512a8e9 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -43,6 +43,8 @@
value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp1.apk"/>
<option name="push-file" key="CtsStaticSharedLibConsumerApp3.apk"
value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp3.apk"/>
+ <option name="push-file" key="CtsStaticSharedLibProviderApp1.apk"
+ value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibProviderApp1.apk"/>
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
index fe54aa8d87f0..945147db1ef5 100644
--- a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
+++ b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
@@ -18,6 +18,8 @@ package com.android.frameworks.coretests.bfscctestapp;
import android.app.Service;
import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.RemoteException;
@@ -36,6 +38,7 @@ public class BfsccTestAppCmdService extends Service {
@Override
public void listenTo(IBinder binder) throws RemoteException {
binder.addFrozenStateChangeCallback(
+ new HandlerExecutor(Handler.getMain()),
(IBinder who, int state) -> mNotifications.offer(state));
}
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 23a09857032c..63e678d9ee53 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -467,7 +467,6 @@ public class NotificationTest {
.setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
.setColor(Color.WHITE)
.setColorized(true)
- .setFlag(FLAG_CAN_COLORIZE, true)
.build();
assertThat(n.hasPromotableCharacteristics()).isTrue();
}
@@ -481,7 +480,6 @@ public class NotificationTest {
.setContentTitle("TITLE")
.setColor(Color.WHITE)
.setColorized(true)
- .setFlag(FLAG_CAN_COLORIZE, true)
.build();
assertThat(n.hasPromotableCharacteristics()).isFalse();
}
@@ -505,7 +503,20 @@ public class NotificationTest {
.setStyle(new Notification.BigTextStyle())
.setColor(Color.WHITE)
.setColorized(true)
- .setFlag(FLAG_CAN_COLORIZE, true)
+ .build();
+ assertThat(n.hasPromotableCharacteristics()).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
+ public void testHasPromotableCharacteristics_groupSummary() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
+ .setColor(Color.WHITE)
+ .setColorized(true)
+ .setGroup("someGroup")
+ .setGroupSummary(true)
.build();
assertThat(n.hasPromotableCharacteristics()).isFalse();
}
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index a2598f69e031..2fc72e1d3994 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -16,6 +16,7 @@
package android.app;
+import static android.app.Flags.FLAG_PIC_CACHE_NULLS;
import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID;
import static android.app.PropertyInvalidatedCache.NONCE_UNSET;
import static android.app.PropertyInvalidatedCache.MODULE_BLUETOOTH;
@@ -229,7 +230,12 @@ public class PropertyInvalidatedCacheTests {
@Override
public String apply(Integer qv) {
mRecomputeCount += 1;
- return "foo" + qv.toString();
+ // Special case for testing caches of nulls. Integers in the range 30-40 return null.
+ if (qv >= 30 && qv < 40) {
+ return null;
+ } else {
+ return "foo" + qv.toString();
+ }
}
int getRecomputeCount() {
@@ -643,4 +649,35 @@ public class PropertyInvalidatedCacheTests {
Binder.restoreCallingWorkSource(token);
}
}
+
+ @RequiresFlagsEnabled(FLAG_PIC_CACHE_NULLS)
+ @Test
+ public void testCachingNulls() {
+ TestCache cache = new TestCache(new Args(MODULE_TEST)
+ .maxEntries(4).api("testCachingNulls").cacheNulls(true),
+ new TestQuery());
+ cache.invalidateCache();
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+
+ cache = new TestCache(new Args(MODULE_TEST)
+ .maxEntries(4).api("testCachingNulls").cacheNulls(false),
+ new TestQuery());
+ cache.invalidateCache();
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ // The recompute is 4 because nulls were not cached.
+ assertEquals(4, cache.getRecomputeCount());
+ }
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java b/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java
index 232abe281e0f..7f069ad3cab8 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java
@@ -22,7 +22,7 @@ import android.content.Intent;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-public class ActivityTestsBase extends AndroidTestCase
+public class ActivityTestsBase extends AndroidTestCase
implements PerformanceTestCase, LaunchpadActivity.CallingTest {
public static final String PERMISSION_GRANTED =
"com.android.frameworks.coretests.permission.TEST_GRANTED";
@@ -111,7 +111,6 @@ public class ActivityTestsBase extends AndroidTestCase
public void finishWithResult(int resultCode, Intent data) {
RuntimeException where = new RuntimeException("Original error was here");
- where.fillInStackTrace();
finishWithResult(resultCode, data, where);
}
@@ -194,15 +193,15 @@ public class ActivityTestsBase extends AndroidTestCase
public int getResultCode() {
return mResultCode;
}
-
+
public Intent getResultData() {
return mData;
}
-
+
public RuntimeException getResultStack() {
return mResultStack;
}
-
+
public void onTimeout() {
String msg = mExpecting == null
? "Timeout" : ("Timeout while expecting " + mExpecting);
diff --git a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
index fda249f3c6ae..9b358e0a7954 100644
--- a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
+++ b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
@@ -461,7 +461,6 @@ public class LaunchpadActivity extends Activity {
mResultCode = resultCode;
mData = data;
mResultStack = new RuntimeException("Original error was here");
- mResultStack.fillInStackTrace();
}
private void registerMyReceiver(IntentFilter filter) {
diff --git a/core/tests/coretests/src/android/appwidget/AppWidgetEventsTest.kt b/core/tests/coretests/src/android/appwidget/AppWidgetEventsTest.kt
new file mode 100644
index 000000000000..ea1158c88055
--- /dev/null
+++ b/core/tests/coretests/src/android/appwidget/AppWidgetEventsTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 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.appwidget
+
+import android.graphics.Rect
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class AppWidgetEventsTest {
+ @Test
+ fun createWidgetInteractionEvent() {
+ val appWidgetId = 1
+ val durationMs = 1000L
+ val position = Rect(1, 2, 3, 4)
+ val clicked = intArrayOf(1, 2, 3)
+ val scrolled = intArrayOf(4, 5, 6)
+ val bundle = AppWidgetManager.createWidgetInteractionEvent(
+ appWidgetId,
+ durationMs,
+ position,
+ clicked,
+ scrolled
+ )
+
+ assertThat(bundle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID)).isEqualTo(appWidgetId)
+ assertThat(bundle.getLong(AppWidgetManager.EXTRA_EVENT_DURATION_MS)).isEqualTo(durationMs)
+ assertThat(bundle.getIntArray(AppWidgetManager.EXTRA_EVENT_POSITION_RECT))
+ .asList().containsExactly(position.left, position.top, position.right, position.bottom)
+ assertThat(bundle.getIntArray(AppWidgetManager.EXTRA_EVENT_CLICKED_VIEWS))
+ .asList().containsExactly(clicked[0], clicked[1], clicked[2])
+ assertThat(bundle.getIntArray(AppWidgetManager.EXTRA_EVENT_SCROLLED_VIEWS))
+ .asList().containsExactly(scrolled[0], scrolled[1], scrolled[2])
+ }
+}
diff --git a/core/tests/coretests/src/android/appwidget/OWNERS b/core/tests/coretests/src/android/appwidget/OWNERS
new file mode 100644
index 000000000000..d724cac4aa3e
--- /dev/null
+++ b/core/tests/coretests/src/android/appwidget/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/appwidget/OWNERS
diff --git a/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java b/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java
new file mode 100644
index 000000000000..df5cd4e95418
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 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.content.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@Presubmit
+@RunWith(JUnit4.class)
+public final class SharedLibraryInfoTest {
+
+ @Rule
+ public final CheckFlagsRule checkFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ private static final String LIBRARY_NAME = "name";
+ private static final long VERSION_MAJOR = 1L;
+ private static final List<String> CERT_DIGESTS = ImmutableList.of("digest1", "digest2");
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+ public void sharedLibraryInfo_serializedAndDeserialized_retainsCertDigestInfo() {
+ SharedLibraryInfo toParcel = new SharedLibraryInfo(LIBRARY_NAME, VERSION_MAJOR,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE, CERT_DIGESTS);
+
+ SharedLibraryInfo fromParcel = parcelAndUnparcel(toParcel);
+
+ assertThat(fromParcel.getCertDigests().size()).isEqualTo(toParcel.getCertDigests().size());
+ assertThat(fromParcel.getCertDigests().get(0)).isEqualTo(toParcel.getCertDigests().get(0));
+ assertThat(fromParcel.getCertDigests().get(1)).isEqualTo(toParcel.getCertDigests().get(1));
+ }
+
+ private SharedLibraryInfo parcelAndUnparcel(SharedLibraryInfo sharedLibraryInfo) {
+ Parcel parcel = Parcel.obtain();
+ parcel.setDataPosition(0);
+ sharedLibraryInfo.writeToParcel(parcel, /* flags= */0);
+
+ parcel.setDataPosition(0);
+ return SharedLibraryInfo.CREATOR.createFromParcel(parcel);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
index 0db49a72c51d..6d2dd5355ff0 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
+++ b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
@@ -33,6 +33,7 @@ import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.ArraySet;
import android.util.PackageUtils;
@@ -61,6 +62,7 @@ import java.util.List;
import java.util.Set;
@Presubmit
+@RequiresFlagsEnabled(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
public class ApkLiteParseUtilsTest {
@Rule
@@ -71,6 +73,7 @@ public class ApkLiteParseUtilsTest {
private static final String TEST_APP_USING_SDK1_AND_SDK1 = "HelloWorldUsingSdk1AndSdk1.apk";
private static final String TEST_APP_USING_SDK_MALFORMED_VERSION =
"HelloWorldUsingSdkMalformedNegativeVersion.apk";
+ private static final String TEST_STATIC_LIB_APP = "CtsStaticSharedLibProviderApp1.apk";
private static final String TEST_APP_USING_STATIC_LIB = "CtsStaticSharedLibConsumerApp1.apk";
private static final String TEST_APP_USING_STATIC_LIB_TWO_CERTS =
"CtsStaticSharedLibConsumerApp3.apk";
@@ -205,6 +208,17 @@ public class ApkLiteParseUtilsTest {
assertThat(liteCerts).isEqualTo(pkgCerts);
}
+ @Test
+ public void testParseApkLite_isIsStaticLibrary() throws Exception {
+ File apkFile = copyApkToTmpDir(TEST_STATIC_LIB_APP);
+ ParseResult<ApkLite> result = ApkLiteParseUtils
+ .parseApkLite(ParseTypeImpl.forDefaultParsing().reset(), apkFile, 0);
+ assertThat(result.isError()).isFalse();
+ ApkLite baseApk = result.getResult();
+
+ assertThat(baseApk.isIsStaticLibrary()).isTrue();
+ }
+
@SuppressLint("CheckResult")
@Test
public void testParseApkLite_malformedUsesSdkLibrary_duplicate() throws Exception {
diff --git a/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java b/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java
deleted file mode 100644
index f1e1df5ae3fb..000000000000
--- a/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2024 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.content.pm.verify;
-
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningInfo;
-import android.content.pm.VersionedPackage;
-import android.content.pm.verify.pkg.IVerificationSessionInterface;
-import android.content.pm.verify.pkg.VerificationSession;
-import android.content.pm.verify.pkg.VerificationStatus;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.PersistableBundle;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VerificationSessionTest {
- private static final int TEST_ID = 100;
- private static final int TEST_INSTALL_SESSION_ID = 33;
- private static final String TEST_PACKAGE_NAME = "com.foo";
- private static final Uri TEST_PACKAGE_URI = Uri.parse("test://test");
- private static final SigningInfo TEST_SIGNING_INFO = new SigningInfo();
- private static final SharedLibraryInfo TEST_SHARED_LIBRARY_INFO1 =
- new SharedLibraryInfo("sharedLibPath1", TEST_PACKAGE_NAME,
- Collections.singletonList("path1"), "sharedLib1", 101,
- SharedLibraryInfo.TYPE_DYNAMIC, new VersionedPackage(TEST_PACKAGE_NAME, 1),
- null, null, false);
- private static final SharedLibraryInfo TEST_SHARED_LIBRARY_INFO2 =
- new SharedLibraryInfo("sharedLibPath2", TEST_PACKAGE_NAME,
- Collections.singletonList("path2"), "sharedLib2", 102,
- SharedLibraryInfo.TYPE_DYNAMIC,
- new VersionedPackage(TEST_PACKAGE_NAME, 2), null, null, false);
- private static final long TEST_TIMEOUT_TIME = System.currentTimeMillis();
- private static final long TEST_EXTEND_TIME = 2000L;
- private static final String TEST_KEY = "test key";
- private static final String TEST_VALUE = "test value";
- private static final int TEST_POLICY = VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
-
- private final ArrayList<SharedLibraryInfo> mTestDeclaredLibraries = new ArrayList<>();
- private final PersistableBundle mTestExtensionParams = new PersistableBundle();
- @Mock
- private IVerificationSessionInterface mTestSessionInterface;
- private VerificationSession mTestSession;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mTestDeclaredLibraries.add(TEST_SHARED_LIBRARY_INFO1);
- mTestDeclaredLibraries.add(TEST_SHARED_LIBRARY_INFO2);
- mTestExtensionParams.putString(TEST_KEY, TEST_VALUE);
- mTestSession = new VerificationSession(TEST_ID, TEST_INSTALL_SESSION_ID,
- TEST_PACKAGE_NAME, TEST_PACKAGE_URI, TEST_SIGNING_INFO, mTestDeclaredLibraries,
- mTestExtensionParams, TEST_POLICY, mTestSessionInterface);
- }
-
- @Test
- public void testParcel() {
- Parcel parcel = Parcel.obtain();
- mTestSession.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- VerificationSession sessionFromParcel =
- VerificationSession.CREATOR.createFromParcel(parcel);
- assertThat(sessionFromParcel.getId()).isEqualTo(TEST_ID);
- assertThat(sessionFromParcel.getInstallSessionId()).isEqualTo(TEST_INSTALL_SESSION_ID);
- assertThat(sessionFromParcel.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
- assertThat(sessionFromParcel.getStagedPackageUri()).isEqualTo(TEST_PACKAGE_URI);
- assertThat(sessionFromParcel.getSigningInfo().getSigningDetails())
- .isEqualTo(TEST_SIGNING_INFO.getSigningDetails());
- List<SharedLibraryInfo> declaredLibrariesFromParcel =
- sessionFromParcel.getDeclaredLibraries();
- assertThat(declaredLibrariesFromParcel).hasSize(2);
- // SharedLibraryInfo doesn't have a "equals" method, so we have to check it indirectly
- assertThat(declaredLibrariesFromParcel.getFirst().toString())
- .isEqualTo(TEST_SHARED_LIBRARY_INFO1.toString());
- assertThat(declaredLibrariesFromParcel.get(1).toString())
- .isEqualTo(TEST_SHARED_LIBRARY_INFO2.toString());
- // We can't directly test with PersistableBundle.equals() because the parceled bundle's
- // structure is different, but all the key/value pairs should be preserved as before.
- assertThat(sessionFromParcel.getExtensionParams().getString(TEST_KEY))
- .isEqualTo(mTestExtensionParams.getString(TEST_KEY));
- assertThat(sessionFromParcel.getVerificationPolicy()).isEqualTo(TEST_POLICY);
- }
-
- @Test
- public void testInterface() throws Exception {
- when(mTestSessionInterface.getTimeoutTime(anyInt())).thenAnswer(i -> TEST_TIMEOUT_TIME);
- when(mTestSessionInterface.extendTimeRemaining(anyInt(), anyLong())).thenAnswer(
- i -> i.getArguments()[1]);
-
- assertThat(mTestSession.getTimeoutTime()).isEqualTo(TEST_TIMEOUT_TIME);
- verify(mTestSessionInterface, times(1)).getTimeoutTime(eq(TEST_ID));
- assertThat(mTestSession.extendTimeRemaining(TEST_EXTEND_TIME)).isEqualTo(TEST_EXTEND_TIME);
- verify(mTestSessionInterface, times(1)).extendTimeRemaining(
- eq(TEST_ID), eq(TEST_EXTEND_TIME));
-
- PersistableBundle response = new PersistableBundle();
- response.putString("test key", "test value");
- final VerificationStatus status =
- new VerificationStatus.Builder().setVerified(true).build();
- mTestSession.reportVerificationComplete(status);
- verify(mTestSessionInterface, times(1)).reportVerificationComplete(
- eq(TEST_ID), eq(status), eq(null));
- mTestSession.reportVerificationComplete(status, response);
- verify(mTestSessionInterface, times(1))
- .reportVerificationComplete(
- eq(TEST_ID), eq(status), eq(response));
-
- final int reason = VerificationSession.VERIFICATION_INCOMPLETE_UNKNOWN;
- mTestSession.reportVerificationIncomplete(reason);
- verify(mTestSessionInterface, times(1)).reportVerificationIncomplete(
- eq(TEST_ID), eq(reason));
- }
-
- @Test
- public void testPolicyNoOverride() {
- assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY);
- // This "set" is a no-op
- assertThat(mTestSession.setVerificationPolicy(TEST_POLICY)).isTrue();
- assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY);
- verifyZeroInteractions(mTestSessionInterface);
- }
-
- @Test
- public void testPolicyOverrideFail() throws Exception {
- final int newPolicy = VERIFICATION_POLICY_BLOCK_FAIL_WARN;
- when(mTestSessionInterface.setVerificationPolicy(anyInt(), anyInt())).thenReturn(false);
- assertThat(mTestSession.setVerificationPolicy(newPolicy)).isFalse();
- verify(mTestSessionInterface, times(1))
- .setVerificationPolicy(eq(TEST_ID), eq(newPolicy));
- // Next "get" should not trigger binder call because the previous "set" has failed
- assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY);
- verifyNoMoreInteractions(mTestSessionInterface);
- }
-
- @Test
- public void testPolicyOverrideSuccess() throws Exception {
- final int newPolicy = VERIFICATION_POLICY_BLOCK_FAIL_WARN;
- when(mTestSessionInterface.setVerificationPolicy(anyInt(), anyInt())).thenReturn(true);
- assertThat(mTestSession.setVerificationPolicy(newPolicy)).isTrue();
- verify(mTestSessionInterface, times(1))
- .setVerificationPolicy(eq(TEST_ID), eq(newPolicy));
- assertThat(mTestSession.getVerificationPolicy()).isEqualTo(newPolicy);
- assertThat(mTestSession.getVerificationPolicy()).isEqualTo(newPolicy);
-
- // Setting back to the original policy should still trigger binder calls
- assertThat(mTestSession.setVerificationPolicy(TEST_POLICY)).isTrue();
- verify(mTestSessionInterface, times(1))
- .setVerificationPolicy(eq(TEST_ID), eq(TEST_POLICY));
- assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/verify/VerificationStatusTest.java b/core/tests/coretests/src/android/content/pm/verify/VerificationStatusTest.java
deleted file mode 100644
index 67d407a72925..000000000000
--- a/core/tests/coretests/src/android/content/pm/verify/VerificationStatusTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2024 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.content.pm.verify;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.pm.verify.pkg.VerificationStatus;
-import android.os.Parcel;
-import android.os.PersistableBundle;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VerificationStatusTest {
- private static final boolean TEST_VERIFIED = true;
- private static final int TEST_ASL_STATUS = VerificationStatus.VERIFIER_STATUS_ASL_GOOD;
- private static final String TEST_FAILURE_MESSAGE = "test test";
- private static final String TEST_KEY = "test key";
- private static final String TEST_VALUE = "test value";
- private final PersistableBundle mTestExtras = new PersistableBundle();
- private VerificationStatus mStatus;
-
- @Before
- public void setUpWithBuilder() {
- mTestExtras.putString(TEST_KEY, TEST_VALUE);
- mStatus = new VerificationStatus.Builder()
- .setAslStatus(TEST_ASL_STATUS)
- .setFailureMessage(TEST_FAILURE_MESSAGE)
- .setVerified(TEST_VERIFIED)
- .build();
- }
-
- @Test
- public void testGetters() {
- assertThat(mStatus.isVerified()).isEqualTo(TEST_VERIFIED);
- assertThat(mStatus.getAslStatus()).isEqualTo(TEST_ASL_STATUS);
- assertThat(mStatus.getFailureMessage()).isEqualTo(TEST_FAILURE_MESSAGE);
- }
-
- @Test
- public void testParcel() {
- Parcel parcel = Parcel.obtain();
- mStatus.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- VerificationStatus statusFromParcel = VerificationStatus.CREATOR.createFromParcel(parcel);
- assertThat(statusFromParcel.isVerified()).isEqualTo(TEST_VERIFIED);
- assertThat(statusFromParcel.getAslStatus()).isEqualTo(TEST_ASL_STATUS);
- assertThat(statusFromParcel.getFailureMessage()).isEqualTo(TEST_FAILURE_MESSAGE);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java b/core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java
deleted file mode 100644
index 56fc66a286c3..000000000000
--- a/core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2024 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.content.pm.verify;
-
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.SigningInfo;
-import android.content.pm.verify.pkg.IVerificationSessionInterface;
-import android.content.pm.verify.pkg.IVerifierService;
-import android.content.pm.verify.pkg.VerificationSession;
-import android.content.pm.verify.pkg.VerifierService;
-import android.net.Uri;
-import android.os.PersistableBundle;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mockito;
-
-import java.util.ArrayList;
-
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VerifierServiceTest {
- private static final int TEST_ID = 100;
- private static final int TEST_INSTALL_SESSION_ID = 33;
- private static final String TEST_PACKAGE_NAME = "com.foo";
- private static final Uri TEST_PACKAGE_URI = Uri.parse("test://test");
- private static final SigningInfo TEST_SIGNING_INFO = new SigningInfo();
- private static final int TEST_POLICY = VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
- private VerifierService mService;
- private VerificationSession mSession;
-
- @Before
- public void setUp() {
- mService = Mockito.mock(VerifierService.class, Answers.CALLS_REAL_METHODS);
- mSession = new VerificationSession(TEST_ID, TEST_INSTALL_SESSION_ID,
- TEST_PACKAGE_NAME, TEST_PACKAGE_URI, TEST_SIGNING_INFO,
- new ArrayList<>(), new PersistableBundle(), TEST_POLICY, Mockito.mock(
- IVerificationSessionInterface.class));
- }
-
- @Test
- public void testBind() throws Exception {
- Intent intent = Mockito.mock(Intent.class);
- when(intent.getAction()).thenReturn(PackageManager.ACTION_VERIFY_PACKAGE);
- IVerifierService binder =
- (IVerifierService) mService.onBind(intent);
- assertThat(binder).isNotNull();
- binder.onPackageNameAvailable(TEST_PACKAGE_NAME);
- verify(mService).onPackageNameAvailable(eq(TEST_PACKAGE_NAME));
- binder.onVerificationCancelled(TEST_PACKAGE_NAME);
- verify(mService).onVerificationCancelled(eq(TEST_PACKAGE_NAME));
- binder.onVerificationRequired(mSession);
- verify(mService).onVerificationRequired(eq(mSession));
- binder.onVerificationRetry(mSession);
- verify(mService).onVerificationRetry(eq(mSession));
- binder.onVerificationTimeout(TEST_ID);
- verify(mService).onVerificationTimeout(eq(TEST_ID));
- }
-
- @Test
- public void testBindFailsWithWrongIntent() {
- Intent intent = Mockito.mock(Intent.class);
- when(intent.getAction()).thenReturn(Intent.ACTION_SEND);
- assertThat(mService.onBind(intent)).isNull();
- }
-}
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
index 9552c887443b..6a5224d4524b 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -16,6 +16,11 @@
package android.hardware.display;
+import static android.hardware.display.DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED;
+import static android.hardware.display.DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
+import static android.hardware.display.DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE;
+
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
@@ -28,13 +33,19 @@ import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.DisplayInfo;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.server.display.feature.flags.Flags;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -55,6 +66,10 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class DisplayManagerGlobalTest {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+
private static final long ALL_DISPLAY_EVENTS =
DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED
| DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED
@@ -117,6 +132,33 @@ public class DisplayManagerGlobalTest {
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+ public void testDisplayListenerIsCalled_WhenDisplayPropertyChangeEventOccurs()
+ throws RemoteException {
+ mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
+ INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE
+ | INTERNAL_EVENT_FLAG_DISPLAY_STATE,
+ null);
+ Mockito.verify(mDisplayManager)
+ .registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong());
+ IDisplayManagerCallback callback = mCallbackCaptor.getValue();
+
+ int displayId = 1;
+
+ Mockito.reset(mListener);
+ callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED);
+ waitForHandler();
+ Mockito.verify(mListener).onDisplayChanged(eq(displayId));
+ Mockito.verifyNoMoreInteractions(mListener);
+
+ Mockito.reset(mListener);
+ callback.onDisplayEvent(displayId, EVENT_DISPLAY_STATE_CHANGED);
+ waitForHandler();
+ Mockito.verify(mListener).onDisplayChanged(eq(displayId));
+ Mockito.verifyNoMoreInteractions(mListener);
+ }
+
+ @Test
public void testDisplayListenerIsNotCalled_WhenClientIsNotSubscribed() throws RemoteException {
// First we subscribe to all events in order to test that the subsequent calls to
// registerDisplayListener will update the event mask.
@@ -231,6 +273,53 @@ public class DisplayManagerGlobalTest {
verify(mListener2, never()).onDisplayChanged(anyInt());
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+ public void testMapFlagsToInternalEventFlag() {
+ // Test public flags mapping
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_ADDED, 0));
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, 0));
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, 0));
+ assertEquals(INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(
+ DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE,
+ 0));
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(
+ DisplayManager.EVENT_FLAG_DISPLAY_STATE,
+ 0));
+
+ // test private flags mapping
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED));
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED));
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+ // Test both public and private flags mapping
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED
+ | INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
+ mDisplayManagerGlobal
+ .mapFlagsToInternalEventFlag(
+ DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE,
+ DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ }
+
private void waitForHandler() {
mHandler.runWithScissors(() -> {
}, 0);
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
index a6de611cc077..8969b2b72e77 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
+++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
@@ -16,7 +16,10 @@
package android.hardware.display
+import android.graphics.PointF
+import android.graphics.RectF
import android.hardware.display.DisplayTopology.TreeNode.POSITION_BOTTOM
+import android.hardware.display.DisplayTopology.TreeNode.POSITION_LEFT
import android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP
import android.hardware.display.DisplayTopology.TreeNode.POSITION_RIGHT
import android.view.Display
@@ -469,4 +472,205 @@ class DisplayTopologyTest {
assertThat(actualDisplay4.offset).isEqualTo(-400f)
assertThat(actualDisplay4.children).isEmpty()
}
-} \ No newline at end of file
+
+ @Test
+ fun rearrange_twoDisplays() {
+ val nodes = rearrangeRects(
+ // Arrange in staggered manner, connected vertically.
+ RectF(100f, 100f, 250f, 200f),
+ RectF(150f, 200f, 300f, 300f),
+ )
+
+ assertThat(nodes[0].children).containsExactly(nodes[1])
+ assertThat(nodes[1].children).isEmpty()
+ assertPositioning(nodes, Pair(POSITION_BOTTOM, 50f))
+ }
+
+ @Test
+ fun rearrange_reverseOrderOfSeveralDisplays() {
+ val nodes = rearrangeRects(
+ RectF(0f, 0f, 150f, 100f),
+ RectF(-150f, 0f, 0f, 100f),
+ RectF(-300f, 0f, -150f, 100f),
+ RectF(-450f, 0f, -300f, 100f),
+ )
+
+ assertPositioning(
+ nodes,
+ Pair(POSITION_LEFT, 0f),
+ Pair(POSITION_LEFT, 0f),
+ Pair(POSITION_LEFT, 0f),
+ )
+
+ assertThat(nodes[0].children).containsExactly(nodes[1])
+ assertThat(nodes[1].children).containsExactly(nodes[2])
+ assertThat(nodes[2].children).containsExactly(nodes[3])
+ assertThat(nodes[3].children).isEmpty()
+ }
+
+ @Test
+ fun rearrange_crossWithRootInCenter() {
+ val nodes = rearrangeRects(
+ RectF(0f, 0f, 150f, 100f),
+ RectF(-150f, 0f, 0f, 100f),
+ RectF(0f,-100f, 150f, 0f),
+ RectF(150f, 0f, 300f, 100f),
+ RectF(0f, 100f, 150f, 200f),
+ )
+
+ assertPositioning(
+ nodes,
+ Pair(POSITION_LEFT, 0f),
+ Pair(POSITION_TOP, 0f),
+ Pair(POSITION_RIGHT, 0f),
+ Pair(POSITION_BOTTOM, 0f),
+ )
+
+ assertThat(nodes[0].children)
+ .containsExactly(nodes[1], nodes[2], nodes[3], nodes[4])
+ }
+
+ @Test
+ fun rearrange_elbowArrangementDoesNotUseCornerAdjacency1() {
+ val nodes = rearrangeRects(
+ // 2
+ // |
+ // 0 - 1
+
+ RectF(0f, 0f, 100f, 100f),
+ RectF(100f, 0f, 200f, 100f),
+ RectF(100f, -100f, 200f, 0f),
+ )
+
+ assertThat(nodes[0].children).containsExactly(nodes[1])
+ assertThat(nodes[1].children).containsExactly(nodes[2])
+ assertThat(nodes[2].children).isEmpty()
+
+ assertPositioning(
+ nodes,
+ Pair(POSITION_RIGHT, 0f),
+ Pair(POSITION_TOP, 0f),
+ )
+ }
+
+ @Test
+ fun rearrange_elbowArrangementDoesNotUseCornerAdjacency2() {
+ val nodes = rearrangeRects(
+ // 0
+ // |
+ // 1
+ // |
+ // 3 - 2
+
+ RectF(0f, 0f, 100f, 100f),
+ RectF(0f, 100f, 100f, 200f),
+ RectF(0f, 200f, 100f, 300f),
+ RectF(-100f, 200f, 0f, 300f),
+ )
+
+ assertThat(nodes[0].children).containsExactly(nodes[1])
+ assertThat(nodes[1].children).containsExactly(nodes[2])
+ assertThat(nodes[2].children).containsExactly(nodes[3])
+ assertThat(nodes[3].children).isEmpty()
+
+ assertPositioning(
+ nodes,
+ Pair(POSITION_BOTTOM, 0f),
+ Pair(POSITION_BOTTOM, 0f),
+ Pair(POSITION_LEFT, 0f),
+ )
+ }
+
+ @Test
+ fun rearrange_useLargerEdge() {
+ val nodes = rearrangeRects(
+ //444111
+ //444111
+ //444111
+ // 000222
+ // 000222
+ // 000222
+ // 333
+ // 333
+ // 333
+ RectF(20f, 30f, 50f, 60f),
+ RectF(30f, 0f, 60f, 30f),
+ RectF(50f, 30f, 80f, 60f),
+ RectF(40f, 60f, 70f, 90f),
+ RectF(0f, 0f, 30f, 30f),
+ )
+
+ assertPositioning(
+ nodes,
+ Pair(POSITION_TOP, 10f),
+ Pair(POSITION_RIGHT, 0f),
+ Pair(POSITION_BOTTOM, -10f),
+ Pair(POSITION_LEFT, 0f),
+ )
+
+ assertThat(nodes[0].children).containsExactly(nodes[1], nodes[2])
+ assertThat(nodes[1].children).containsExactly(nodes[4])
+ assertThat(nodes[2].children).containsExactly(nodes[3])
+ (3..4).forEach { assertThat(nodes[it].children).isEmpty() }
+ }
+
+ @Test
+ fun rearrange_closeGaps() {
+ val nodes = rearrangeRects(
+ //000
+ //000 111
+ //000 111
+ // 111
+ //
+ // 222
+ // 222
+ // 222
+ RectF(0f, 0f, 30f, 30f),
+ RectF(40f, 10f, 70f, 40f),
+ RectF(80.5f, 50f, 110f, 80f), // left+=0.5 to cause a preference for TOP/BOTTOM attach
+ )
+
+ assertPositioning(
+ nodes,
+ // In the case of corner adjacency, we prefer a left/right attachment.
+ Pair(POSITION_RIGHT, 10f),
+ Pair(POSITION_BOTTOM, 40.5f), // TODO: fix implementation to remove this gap
+ )
+
+ assertThat(nodes[0].children).containsExactly(nodes[1])
+ assertThat(nodes[1].children).containsExactly(nodes[2])
+ assertThat(nodes[2].children).isEmpty()
+ }
+
+ /**
+ * Runs the rearrange algorithm and returns the resulting tree as a list of nodes, with the
+ * root at index 0. The number of nodes is inferred from the number of positions passed.
+ */
+ private fun rearrangeRects(vararg pos : RectF) : List<DisplayTopology.TreeNode> {
+ // Generates a linear sequence of nodes in order in the List from root to leaf,
+ // left-to-right. IDs are ascending from 0 to count - 1.
+
+ val nodes = pos.indices.map {
+ DisplayTopology.TreeNode(it, pos[it].width(), pos[it].height(), POSITION_RIGHT, 0f)
+ }
+
+ nodes.forEachIndexed { id, node ->
+ if (id > 0) {
+ nodes[id - 1].addChild(node)
+ }
+ }
+
+ DisplayTopology(nodes[0], 0).rearrange(pos.indices.associateWith {
+ PointF(pos[it].left, pos[it].top)
+ })
+
+ return nodes
+ }
+
+ private fun assertPositioning(
+ nodes : List<DisplayTopology.TreeNode>, vararg positions : Pair<Int, Float>) {
+ assertThat(nodes.drop(1).map { Pair(it.position, it.offset )})
+ .containsExactly(*positions)
+ .inOrder()
+ }
+}
diff --git a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
index 195a18a5f521..523fe1a8aa5d 100644
--- a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
+++ b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
@@ -200,7 +200,7 @@ public class BinderFrozenStateChangeNotificationTest {
IBinder.FrozenStateChangeCallback callback =
(IBinder who, int state) -> results.offer(who);
try {
- binder.addFrozenStateChangeCallback(callback);
+ binder.addFrozenStateChangeCallback(new HandlerExecutor(Handler.getMain()), callback);
} catch (UnsupportedOperationException e) {
return;
}
@@ -227,7 +227,7 @@ public class BinderFrozenStateChangeNotificationTest {
final IBinder.FrozenStateChangeCallback callback =
(IBinder who, int state) ->
queue.offer(state == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
- binder.addFrozenStateChangeCallback(callback);
+ binder.addFrozenStateChangeCallback(new HandlerExecutor(Handler.getMain()), callback);
return callback;
} catch (UnsupportedOperationException e) {
return null;
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
index 6149382d0800..4620cb8d8148 100644
--- a/core/tests/coretests/src/android/os/OWNERS
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -12,3 +12,6 @@ per-file PerformanceHintManagerTest.java = file:/ADPF_OWNERS
# Caching
per-file IpcDataCache* = file:/PERFORMANCE_OWNERS
+
+# RemoteCallbackList
+per-file RemoteCallbackListTest.java = shayba@google.com
diff --git a/core/tests/coretests/src/android/view/HapticScrollFeedbackProviderTest.java b/core/tests/coretests/src/android/view/HapticScrollFeedbackProviderTest.java
index ac6c19e79fcb..66cf9c7ec832 100644
--- a/core/tests/coretests/src/android/view/HapticScrollFeedbackProviderTest.java
+++ b/core/tests/coretests/src/android/view/HapticScrollFeedbackProviderTest.java
@@ -17,6 +17,7 @@
package android.view;
import static android.os.vibrator.Flags.FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED;
+import static android.view.flags.Flags.FLAG_DYNAMIC_VIEW_ROTARY_HAPTICS_CONFIGURATION;
import static android.view.HapticFeedbackConstants.SCROLL_ITEM_FOCUS;
import static android.view.HapticFeedbackConstants.SCROLL_LIMIT;
import static android.view.HapticFeedbackConstants.SCROLL_TICK;
@@ -74,12 +75,13 @@ public final class HapticScrollFeedbackProviderTest {
mView = new TestView(InstrumentationRegistry.getContext());
mProvider = new HapticScrollFeedbackProvider(mView, mMockViewConfig,
- /* disabledIfViewPlaysScrollHaptics= */ true);
+ /* isFromView= */ false);
mSetFlagsRule.disableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
}
@Test
public void testRotaryEncoder_noFeedbackWhenViewBasedFeedbackIsEnabled() {
+ mSetFlagsRule.disableFlags(FLAG_DYNAMIC_VIEW_ROTARY_HAPTICS_CONFIGURATION);
when(mMockViewConfig.isViewBasedRotaryEncoderHapticScrollFeedbackEnabled())
.thenReturn(true);
setHapticScrollTickInterval(5);
@@ -97,7 +99,24 @@ public final class HapticScrollFeedbackProviderTest {
}
@Test
+ public void testRotaryEncoder_dynamicViewRotaryFeedback_enabledEvenWhenViewFeedbackIsEnabled() {
+ mSetFlagsRule.enableFlags(FLAG_DYNAMIC_VIEW_ROTARY_HAPTICS_CONFIGURATION);
+ when(mMockViewConfig.isViewBasedRotaryEncoderHapticScrollFeedbackEnabled())
+ .thenReturn(true);
+ setHapticScrollTickInterval(5);
+ mProvider = new HapticScrollFeedbackProvider(mView, mMockViewConfig,
+ /* isFromView= */ false);
+
+ mProvider.onScrollProgress(
+ INPUT_DEVICE_1, InputDevice.SOURCE_ROTARY_ENCODER, MotionEvent.AXIS_SCROLL,
+ /* deltaInPixels= */ 10);
+
+ assertFeedbackCount(mView, SCROLL_TICK, 1);
+ }
+
+ @Test
public void testRotaryEncoder_inputDeviceCustomized_noFeedbackWhenViewBasedFeedbackIsEnabled() {
+ mSetFlagsRule.disableFlags(FLAG_DYNAMIC_VIEW_ROTARY_HAPTICS_CONFIGURATION);
mSetFlagsRule.enableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
when(mMockViewConfig.isViewBasedRotaryEncoderHapticScrollFeedbackEnabled())
@@ -119,7 +138,7 @@ public final class HapticScrollFeedbackProviderTest {
@Test
public void testRotaryEncoder_feedbackWhenDisregardingViewBasedScrollHaptics() {
mProvider = new HapticScrollFeedbackProvider(mView, mMockViewConfig,
- /* disabledIfViewPlaysScrollHaptics= */ false);
+ /* isFromView= */ true);
when(mMockViewConfig.isViewBasedRotaryEncoderHapticScrollFeedbackEnabled())
.thenReturn(true);
setHapticScrollTickInterval(5);
@@ -144,7 +163,7 @@ public final class HapticScrollFeedbackProviderTest {
List<HapticFeedbackRequest> requests = new ArrayList<>();
mProvider = new HapticScrollFeedbackProvider(mView, mMockViewConfig,
- /* disabledIfViewPlaysScrollHaptics= */ false);
+ /* isFromView= */ true);
when(mMockViewConfig.isViewBasedRotaryEncoderHapticScrollFeedbackEnabled())
.thenReturn(true);
setHapticScrollTickInterval(5);
@@ -917,19 +936,20 @@ public final class HapticScrollFeedbackProviderTest {
@Test
public void testNonRotaryInputFeedbackNotBlockedByRotaryUnavailability() {
+ mSetFlagsRule.disableFlags(FLAG_DYNAMIC_VIEW_ROTARY_HAPTICS_CONFIGURATION);
when(mMockViewConfig.isViewBasedRotaryEncoderHapticScrollFeedbackEnabled())
.thenReturn(true);
setHapticScrollFeedbackEnabled(true);
setHapticScrollTickInterval(5);
mProvider = new HapticScrollFeedbackProvider(mView, mMockViewConfig,
- /* disabledIfViewPlaysScrollHaptics= */ true);
+ /* isFromView= */ false);
// Expect one feedback here. Touch input should provide feedback since scroll feedback has
// been enabled via `setHapticScrollFeedbackEnabled(true)`.
mProvider.onScrollProgress(
INPUT_DEVICE_1, InputDevice.SOURCE_TOUCHSCREEN, MotionEvent.AXIS_Y,
/* deltaInPixels= */ 10);
- // Because `isViewBasedRotaryEncoderHapticScrollFeedbackEnabled()` is false and
+ // Because `isViewBasedRotaryEncoderHapticScrollFeedbackEnabled()` is true and
// `disabledIfViewPlaysScrollHaptics` is true, the scroll progress from rotary encoders will
// produce no feedback.
mProvider.onScrollProgress(
diff --git a/core/tests/coretests/src/android/view/RotaryScrollHapticsTest.java b/core/tests/coretests/src/android/view/RotaryScrollHapticsTest.java
index 9a5c1c5112e6..b1a56373c9d6 100644
--- a/core/tests/coretests/src/android/view/RotaryScrollHapticsTest.java
+++ b/core/tests/coretests/src/android/view/RotaryScrollHapticsTest.java
@@ -30,8 +30,12 @@ import static org.mockito.Mockito.when;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.annotation.Nullable;
import android.content.Context;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.flags.Flags;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -39,6 +43,7 @@ import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -48,6 +53,8 @@ import org.mockito.Mock;
@RunWith(AndroidJUnit4.class)
@Presubmit
public final class RotaryScrollHapticsTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final int TEST_ROTARY_DEVICE_ID = 1;
private static final int TEST_RANDOM_DEVICE_ID = 2;
@@ -167,6 +174,26 @@ public final class RotaryScrollHapticsTest {
}
@Test
+ @EnableFlags(Flags.FLAG_DYNAMIC_VIEW_ROTARY_HAPTICS_CONFIGURATION)
+ public void testChildViewImplementationUsesScrollFeedbackProvider_doesNoScrollFeedback() {
+ mView.configureGenericMotion(/* result= */ false, /* scroll= */ true);
+ mView.mUsesCustomScrollFeedbackProvider = true;
+
+ // Send multiple generic motion events, to catch bugs where the behavior is WAI only for the
+ // first dispatch, but buggy for future calls.
+ mView.dispatchGenericMotionEvent(createRotaryEvent(20));
+ mView.dispatchGenericMotionEvent(createRotaryEvent(10));
+ mView.dispatchGenericMotionEvent(createRotaryEvent(30));
+
+ // Verify that the base View class's ScrollFeedbackProvider produces no scroll progress
+ // or limit events, because there's a custom ScrollFeedbackProvider used by the child
+ // View class implementation, which should hint the base View class to disable its own
+ // ScrollFeedbackProvider usage.
+ verifyNoScrollProgress();
+ verifyNoScrollLimit();
+ }
+
+ @Test
public void testScrollProgress_genericMotionEventCallbackReturningTrue_doesScrollProgress() {
mView.configureGenericMotion(/* result= */ true, /* scroll= */ true);
@@ -208,6 +235,9 @@ public final class RotaryScrollHapticsTest {
private static final class TestGenericMotionEventControllingView extends View {
private boolean mGenericMotionResult;
private boolean mScrollOnGenericMotion;
+ private boolean mUsesCustomScrollFeedbackProvider = false;
+
+ @Nullable private ScrollFeedbackProvider mCustomScrollFeedbackProvider;
TestGenericMotionEventControllingView(Context context) {
super(context);
@@ -222,6 +252,19 @@ public final class RotaryScrollHapticsTest {
public boolean onGenericMotionEvent(MotionEvent event) {
if (mScrollOnGenericMotion) {
scrollTo(100, 200); // scroll values random (not relevant for tests).
+ if (mUsesCustomScrollFeedbackProvider) {
+ // Mimic how a real child class of View would instantiate and use the
+ // ScrollFeedbackProvider API.
+ if (mCustomScrollFeedbackProvider == null) {
+ mCustomScrollFeedbackProvider = ScrollFeedbackProvider.createProvider(this);
+ }
+ float axisScrollValue = event.getAxisValue(AXIS_SCROLL);
+ mCustomScrollFeedbackProvider.onScrollProgress(
+ event.getDeviceId(),
+ event.getSource(),
+ MotionEvent.AXIS_SCROLL,
+ (int) (axisScrollValue * TEST_SCALED_VERTICAL_SCROLL_FACTOR));
+ }
}
return mGenericMotionResult;
}
diff --git a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
index a3725af04ba6..bb2fe1bcfc64 100644
--- a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
+++ b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
@@ -162,6 +162,22 @@ public class WindowTokenClientControllerTest {
}
@Test
+ public void testAttachToDisplayContent_keepTrackWithoutWMS() {
+ // WMS is not initialized
+ doReturn(null).when(mController).getWindowManagerService();
+
+ assertFalse(mController.attachToDisplayContent(mWindowTokenClient, DEFAULT_DISPLAY));
+
+ // Can report config change
+ mController.onWindowContextInfoChanged(mWindowTokenClient, mWindowContextInfo);
+
+ verify(mWindowTokenClient).onConfigurationChanged(mConfiguration, DEFAULT_DISPLAY);
+
+ // No crash to detach even if WMS is not initialized.
+ mController.detachIfNeeded(mWindowTokenClient);
+ }
+
+ @Test
public void testAttachToWindowToken() throws RemoteException {
doReturn(null).when(mWindowManagerService).attachWindowContextToWindowToken(
any(), any(), any());
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 67de25eede42..75118873dd75 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -42,6 +42,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.FileDescriptor;
+import java.util.concurrent.Executor;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -125,7 +126,7 @@ public class BinderDeathDispatcherTest {
}
@Override
- public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
+ public void addFrozenStateChangeCallback(Executor e, FrozenStateChangeCallback callback)
throws RemoteException {
}
diff --git a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
index 40d0bef2fb0f..28d6545c8a5b 100644
--- a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
+++ b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
@@ -210,21 +210,6 @@ public class OverlayManagerImplTest {
}
@Test
- public void registerOverlay_forAndroidPackage_shouldFail() {
- FabricatedOverlayInternal overlayInternal =
- createOverlayWithName(
- mOverlayName,
- SYSTEM_APP_OVERLAYABLE,
- "android",
- List.of(Pair.create("color/white", Pair.create(null, Color.BLACK))));
-
- assertThrows(
- "Wrong target package name",
- IllegalArgumentException.class,
- () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
- }
-
- @Test
public void getOverlayInfosForTarget_defaultShouldBeZero() {
List<OverlayInfo> overlayInfos =
mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 75aca1b8820c..7ce2ed823540 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -23,10 +23,11 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
+import org.junit.Rule;
import org.junit.Test;
import java.util.Objects;
@@ -39,8 +40,8 @@ public class SystemPropertiesTest {
private static final String PERSIST_KEY = "persist.sys.testkey";
private static final String NONEXIST_KEY = "doesnotexist_2341431";
- @RavenwoodConfig.Config
- public static final RavenwoodConfig mRavenwood = new RavenwoodConfig.Builder()
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
.setSystemPropertyMutable(KEY, null)
.setSystemPropertyMutable(UNSET_KEY, null)
.setSystemPropertyMutable(PERSIST_KEY, null)
diff --git a/core/tests/vibrator/src/android/os/VibrationEffectTest.java b/core/tests/vibrator/src/android/os/VibrationEffectTest.java
index 1cd1190c4080..5f3754b9933a 100644
--- a/core/tests/vibrator/src/android/os/VibrationEffectTest.java
+++ b/core/tests/vibrator/src/android/os/VibrationEffectTest.java
@@ -414,23 +414,49 @@ public class VibrationEffectTest {
@Test
@EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
- public void computeLegacyPattern_effectsViaStartWaveformEnvelope() {
- // Effects created via startWaveformEnvelope are not expected to be converted to long[]
+ public void computeLegacyPattern_effectsViaWaveformEnvelopeBuilder() {
+ // Effects created via waveformEnvelopeBuilder are not expected to be converted to long[]
// patterns, as they are not configured to always play with the default amplitude.
- VibrationEffect effect = VibrationEffect.startWaveformEnvelope()
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 40)
+ VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 50)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 80)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 40)
.build();
assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
- effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 60)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 40)
+ effect = new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 60)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 50)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 80)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 40)
+ .build();
+
+ assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void computeLegacyPattern_effectsViaBasicEnvelopeBuilder() {
+ // Effects created via BasicEnvelopeBuilder are not expected to be converted to long[]
+ // patterns, as they are not configured to always play with the default amplitude.
+ VibrationEffect effect = new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(/*intensity=*/ 0.1f, /*sharpness=*/ 0.2f, /*durationMillis=*/ 20)
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 50)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 80)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 40)
+ .build();
+
+ assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+
+ effect = new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.1f)
+ .addControlPoint(/*intensity=*/ 0.2f, /*sharpness=*/ 0.2f, /*durationMillis=*/ 20)
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 50)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 80)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 40)
.build();
assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
@@ -644,98 +670,227 @@ public class VibrationEffectTest {
@Test
@EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void testValidateWaveformEnvelopeBuilder() {
- VibrationEffect.startWaveformEnvelope()
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 40)
+ new VibrationEffect.WaveformEnvelopeBuilder()
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 50)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 80)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 40)
.build()
.validate();
- VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 40)
+ new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 50)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 80)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 40)
.build()
.validate();
VibrationEffect.createRepeatingEffect(
- /*preamble=*/ VibrationEffect.startWaveformEnvelope()
+ /*preamble=*/ new VibrationEffect.WaveformEnvelopeBuilder()
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f,
- /*timeMillis=*/ 50)
+ /*durationMillis=*/ 50)
.build(),
- /*repeatingEffect=*/ VibrationEffect.startWaveformEnvelope()
+ /*repeatingEffect=*/ new VibrationEffect.WaveformEnvelopeBuilder()
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f,
- /*timeMillis=*/ 100)
+ /*durationMillis=*/ 100)
.build()
).validate();
VibrationEffect.createRepeatingEffect(
- /*effect=*/ VibrationEffect.startWaveformEnvelope()
+ /*effect=*/ new VibrationEffect.WaveformEnvelopeBuilder()
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f,
- /*timeMillis=*/ 100)
+ /*durationMillis=*/ 100)
.build()
).validate();
assertThrows(IllegalStateException.class,
- () -> VibrationEffect.startWaveformEnvelope().build().validate());
+ () -> new VibrationEffect.WaveformEnvelopeBuilder().build().validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope()
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
.addControlPoint(/*amplitude=*/ -1.0f, /*frequencyHz=*/ 60f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.build()
.validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope()
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
.addControlPoint(/*amplitude=*/ 1.1f, /*frequencyHz=*/ 60f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.build()
.validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope()
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
.addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 0f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.build()
.validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope()
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
.addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f,
- /*timeMillis=*/ 0)
+ /*durationMillis=*/ 0)
.build()
.validate());
assertThrows(IllegalStateException.class,
- () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
.build().validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
.addControlPoint(/*amplitude=*/ -1.0f, /*frequencyHz=*/ 60f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.build()
.validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
.addControlPoint(/*amplitude=*/ 1.1f, /*frequencyHz=*/ 60f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.build()
.validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
.addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 0f,
- /*timeMillis=*/ 20)
+ /*durationMillis=*/ 20)
.build()
.validate());
assertThrows(IllegalArgumentException.class,
- () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
.addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f,
- /*timeMillis=*/ 0)
+ /*durationMillis=*/ 0)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 0)
+ .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f,
+ /*durationMillis=*/ 20)
+ .build().validate());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void testValidateBasicEnvelopeBuilder() {
+ new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(/*intensity=*/ 0.1f, /*sharpness=*/ 0.2f, /*durationMillis=*/ 20)
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 50)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 80)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 40)
+ .build()
+ .validate();
+
+ new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.1f)
+ .addControlPoint(/*intensity=*/ 0.2f, /*sharpness=*/ 0.2f, /*durationMillis=*/ 20)
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 50)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 80)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 40)
+ .build()
+ .validate();
+
+ VibrationEffect.createRepeatingEffect(
+ /*preamble=*/ new VibrationEffect.BasicEnvelopeBuilder()
+ // intensity, sharpness, durationMillis
+ .addControlPoint(0.3f, 0.5f, 60)
+ .addControlPoint(0.0f, 0.5f, 100)
+ .build(),
+ /*repeatingEffect=*/ new VibrationEffect.BasicEnvelopeBuilder()
+ // intensity, sharpness, durationMillis
+ .addControlPoint(0.5f, 0.8f, 60)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ ).validate();
+
+ VibrationEffect.createRepeatingEffect(
+ new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ // intensity, sharpness, durationMillis
+ .addControlPoint(0.5f, 0.8f, 60)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ ).validate();
+
+ assertThrows(IllegalStateException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder().build().validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(-1.0f, 0.5f, 20)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(1.1f, 0.5f, 20)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(0.8f, -0.1f, 20)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(0.8f, 0.5f, 0)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ // Waveform effects created using the basic builder must end with a zero intensity
+ // control point.
+ assertThrows(IllegalStateException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(0.8f, 0.5f, 100)
+ .build()
+ .validate());
+
+ assertThrows(IllegalStateException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/0.2f).build().validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ .addControlPoint(-1.0f, 0.5f, 20)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ .addControlPoint(1.1f, 0.5f, 20)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ .addControlPoint(0.8f, -0.1f, 20)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ .addControlPoint(0.8f, 0.5f, 0)
+ .addControlPoint(0.0f, 0.3f, 100)
+ .build()
+ .validate());
+ // Waveform effects created using the basic builder must end with a zero intensity
+ // control point.
+ assertThrows(IllegalStateException.class,
+ () -> new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ .addControlPoint(0.8f, 0.5f, 100)
.build()
.validate());
}
@@ -1381,18 +1536,37 @@ public class VibrationEffectTest {
@Test
@EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void testIsHapticFeedbackCandidate_longEnvelopeEffects_notCandidates() {
- assertFalse(VibrationEffect.startWaveformEnvelope()
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 800)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
+ assertFalse(new VibrationEffect.WaveformEnvelopeBuilder()
+ //amplitude, frequencyHz, durationMillis
+ .addControlPoint(0.0f, 60f, 200)
+ .addControlPoint(0.3f, 100f, 500)
+ .addControlPoint(0.4f, 120f, 800)
+ .addControlPoint(0.0f, 120f, 400)
.build()
.isHapticFeedbackCandidate());
- assertFalse(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 40)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 800)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
+ assertFalse(new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 40)
+ //amplitude, frequencyHz, durationMillis
+ .addControlPoint(0.0f, 60f, 200)
+ .addControlPoint(0.3f, 100f, 500)
+ .addControlPoint(0.4f, 120f, 800)
+ .addControlPoint(0.0f, 120f, 400)
+ .build()
+ .isHapticFeedbackCandidate());
+
+ assertFalse(new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(/*intensity=*/ 0.1f, /*sharpness=*/ 0.2f, /*durationMillis=*/ 200)
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 500)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 800)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 400)
+ .build()
+ .isHapticFeedbackCandidate());
+ assertFalse(new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ .addControlPoint(/*intensity=*/ 0.1f, /*sharpness=*/ 0.2f, /*durationMillis=*/ 200)
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 500)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 800)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 400)
.build()
.isHapticFeedbackCandidate());
}
@@ -1413,16 +1587,32 @@ public class VibrationEffectTest {
@Test
@EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void testIsHapticFeedbackCandidate_shortEnvelopeEffects_areCandidates() {
- assertTrue(VibrationEffect.startWaveformEnvelope()
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100)
+ assertTrue(new VibrationEffect.WaveformEnvelopeBuilder()
+ //amplitude, frequencyHz, durationMillis
+ .addControlPoint(0.3f, 100f, 500)
+ .addControlPoint(0.4f, 120f, 400)
+ .addControlPoint(0.0f, 120f, 100)
+ .build()
+ .isHapticFeedbackCandidate());
+ assertTrue(new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
+ .addControlPoint(0.3f, 100f, 500)
+ .addControlPoint(0.4f, 120f, 400)
+ .addControlPoint(0.0f, 120f, 100)
+ .build()
+ .isHapticFeedbackCandidate());
+
+ assertTrue(new VibrationEffect.BasicEnvelopeBuilder()
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 500)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 400)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 100)
.build()
.isHapticFeedbackCandidate());
- assertTrue(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100)
+ assertTrue(new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 0.2f)
+ .addControlPoint(/*intensity=*/ 0.3f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 500)
+ .addControlPoint(/*intensity=*/ 0.4f, /*sharpness=*/ 0.5f, /*durationMillis=*/ 400)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 0.3f, /*durationMillis=*/ 100)
.build()
.isHapticFeedbackCandidate());
}
diff --git a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
index 1cc38ded1c2c..40710577b154 100644
--- a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
@@ -16,6 +16,8 @@
package android.os.vibrator.persistence;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
import static android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
import static android.os.VibrationEffect.Composition.PRIMITIVE_SPIN;
@@ -31,6 +33,7 @@ import android.os.PersistableBundle;
import android.os.VibrationEffect;
import android.os.vibrator.Flags;
import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -437,7 +440,7 @@ public class VibrationEffectXmlSerializationTest {
@Test
@EnableFlags(Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
- public void testVendorEffect_featureFlagEnabled_allSucceed() throws Exception {
+ public void testVendorEffect_allSucceed() throws Exception {
PersistableBundle vendorData = new PersistableBundle();
vendorData.putInt("id", 1);
vendorData.putDouble("scale", 0.5);
@@ -476,7 +479,7 @@ public class VibrationEffectXmlSerializationTest {
@Test
@EnableFlags(Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
- public void testInvalidVendorEffect_featureFlagEnabled_allFail() throws IOException {
+ public void testInvalidVendorEffect_allFail() throws IOException {
String emptyTag = "<vibration-effect><vendor-effect/></vibration-effect>";
assertPublicApisParserFails(emptyTag);
assertHiddenApisParserFails(emptyTag);
@@ -526,6 +529,81 @@ public class VibrationEffectXmlSerializationTest {
assertHiddenApisSerializerFails(vendorEffect);
}
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveDelayType_allSucceed() throws Exception {
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET)
+ .addPrimitive(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE)
+ .compose();
+ String xml = """
+ <vibration-effect>
+ <primitive-effect name="tick" delayType="relative_start_offset"/>
+ <primitive-effect name="click" scale="0.123" delayMs="10"/>
+ </vibration-effect>
+ """;
+
+ assertPublicApisParserSucceeds(xml, effect);
+ assertPublicApisSerializerSucceeds(effect, "tick", "click");
+ // Delay type pause is not serialized, as it's the default one
+ assertPublicApisSerializerSucceeds(effect, "relative_start_offset", "click");
+ assertPublicApisRoundTrip(effect);
+
+ assertHiddenApisParserSucceeds(xml, effect);
+ assertHiddenApisSerializerSucceeds(effect, "tick", "click");
+ assertHiddenApisRoundTrip(effect);
+
+ // Check PersistableBundle from round-trip
+ VibrationEffect.Composed parsedEffect = ((VibrationEffect.Composed) parseVibrationEffect(
+ serialize(effect), /* flags= */ 0));
+ assertThat(parsedEffect.getRepeatIndex()).isEqualTo(-1);
+ assertThat(parsedEffect.getSegments()).containsExactly(
+ new PrimitiveSegment(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE))
+ .inOrder();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveInvalidDelayType_allFail() {
+ String emptyAttribute = """
+ <vibration-effect>
+ <primitive-effect name="tick" delayType=""/>
+ </vibration-effect>
+ """;
+ assertPublicApisParserFails(emptyAttribute);
+ assertHiddenApisParserFails(emptyAttribute);
+
+ String invalidString = """
+ <vibration-effect>
+ <primitive-effect name="tick" delayType="invalid"/>
+ </vibration-effect>
+ """;
+ assertPublicApisParserFails(invalidString);
+ assertHiddenApisParserFails(invalidString);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveDelayType_featureFlagDisabled_allFail() {
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET)
+ .addPrimitive(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE)
+ .compose();
+ String xml = """
+ <vibration-effect>
+ <primitive-effect name="tick" delayType="relative_start_offset"/>
+ <primitive-effect name="click" scale="0.123" delayMs="10" delayType="pause"/>
+ </vibration-effect>
+ """;
+
+ assertPublicApisParserFails(xml);
+ assertPublicApisSerializerFails(effect);
+
+ assertHiddenApisParserFails(xml);
+ assertHiddenApisSerializerFails(effect);
+ }
+
private void assertPublicApisParserFails(String xml) {
assertThrows("Expected parseVibrationEffect to fail for " + xml,
VibrationXmlParser.ParseFailedException.class,
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 0ec8f7d4f2ae..0a0ca7c2248b 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -43,6 +43,7 @@
<xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app"/>
<xs:element name="privapp-permissions" type="privapp-permissions"/>
<xs:element name="oem-permissions" type="oem-permissions"/>
+ <xs:element name="signature-permissions" type="signature-permissions"/>
<xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/>
<xs:element name="allow-association" type="allow-association"/>
<xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/>
@@ -156,6 +157,21 @@
</xs:sequence>
<xs:attribute name="package" type="xs:string"/>
</xs:complexType>
+ <xs:complexType name="signature-permissions">
+ <xs:sequence>
+ <xs:element name="permission" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="deny-permission" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="package" type="xs:string"/>
+ </xs:complexType>
<xs:complexType name="hidden-api-whitelisted-app">
<xs:attribute name="package" type="xs:string"/>
</xs:complexType>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index f3beea1b96a9..cdec6ab6e014 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -183,6 +183,7 @@ package com.android.xml.permission.configfile {
method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions_optional();
method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission_optional();
method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions_optional();
+ method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions> getSignaturePermissions_optional();
method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission_optional();
method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp_optional();
method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp_optional();
@@ -209,6 +210,26 @@ package com.android.xml.permission.configfile {
method public void setName(String);
}
+ public class SignaturePermissions {
+ ctor public SignaturePermissions();
+ method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions.DenyPermission> getDenyPermission();
+ method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions.Permission> getPermission();
+ method public String get_package();
+ method public void set_package(String);
+ }
+
+ public static class SignaturePermissions.DenyPermission {
+ ctor public SignaturePermissions.DenyPermission();
+ method public String getName();
+ method public void setName(String);
+ }
+
+ public static class SignaturePermissions.Permission {
+ ctor public SignaturePermissions.Permission();
+ method public String getName();
+ method public void setName(String);
+ }
+
public class SplitPermission {
ctor public SplitPermission();
method public java.util.List<com.android.xml.permission.configfile.SplitPermission.Library> getLibrary();
diff --git a/core/xsd/vibrator/vibration/schema/current.txt b/core/xsd/vibrator/vibration/schema/current.txt
index 280b40516b7e..b4148d657b0d 100644
--- a/core/xsd/vibrator/vibration/schema/current.txt
+++ b/core/xsd/vibrator/vibration/schema/current.txt
@@ -15,12 +15,20 @@ package com.android.internal.vibrator.persistence {
enum_constant public static final com.android.internal.vibrator.persistence.PredefinedEffectName tick;
}
+ public enum PrimitiveDelayType {
+ method public String getRawName();
+ enum_constant public static final com.android.internal.vibrator.persistence.PrimitiveDelayType pause;
+ enum_constant public static final com.android.internal.vibrator.persistence.PrimitiveDelayType relative_start_offset;
+ }
+
public class PrimitiveEffect {
ctor public PrimitiveEffect();
method public java.math.BigInteger getDelayMs();
+ method public com.android.internal.vibrator.persistence.PrimitiveDelayType getDelayType();
method public com.android.internal.vibrator.persistence.PrimitiveEffectName getName();
method public float getScale();
method public void setDelayMs(java.math.BigInteger);
+ method public void setDelayType(com.android.internal.vibrator.persistence.PrimitiveDelayType);
method public void setName(com.android.internal.vibrator.persistence.PrimitiveEffectName);
method public void setScale(float);
}
diff --git a/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd b/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
index 21a6facad242..910a9b700b5c 100644
--- a/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
+++ b/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
@@ -147,6 +147,7 @@
<xs:attribute name="name" type="PrimitiveEffectName" use="required"/>
<xs:attribute name="scale" type="PrimitiveScale"/>
<xs:attribute name="delayMs" type="xs:nonNegativeInteger"/>
+ <xs:attribute name="delayType" type="PrimitiveDelayType"/>
</xs:complexType>
<!-- Primitive names as defined by VibrationEffect.Composition.PRIMITIVE_* -->
@@ -171,4 +172,12 @@
</xs:restriction>
</xs:simpleType>
+ <!-- Primitive delay types VibrationEffect.Composition.DELAY_TYPE_* -->
+ <xs:simpleType name="PrimitiveDelayType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="pause"/>
+ <xs:enumeration value="relative_start_offset"/>
+ </xs:restriction>
+ </xs:simpleType>
+
</xs:schema>
diff --git a/core/xsd/vibrator/vibration/vibration.xsd b/core/xsd/vibrator/vibration/vibration.xsd
index d35d777d4450..3c8e01605659 100644
--- a/core/xsd/vibrator/vibration/vibration.xsd
+++ b/core/xsd/vibrator/vibration/vibration.xsd
@@ -124,6 +124,7 @@
<xs:attribute name="name" type="PrimitiveEffectName" use="required"/>
<xs:attribute name="scale" type="PrimitiveScale"/>
<xs:attribute name="delayMs" type="xs:nonNegativeInteger"/>
+ <xs:attribute name="delayType" type="PrimitiveDelayType"/>
</xs:complexType>
<!-- Primitive names as defined by VibrationEffect.Composition.PRIMITIVE_* -->
@@ -148,4 +149,12 @@
</xs:restriction>
</xs:simpleType>
+ <!-- Primitive delay types VibrationEffect.Composition.DELAY_TYPE_* -->
+ <xs:simpleType name="PrimitiveDelayType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="pause"/>
+ <xs:enumeration value="relative_start_offset"/>
+ </xs:restriction>
+ </xs:simpleType>
+
</xs:schema>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 541ca602a386..af690f4449af 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -93,6 +93,10 @@ applications that come with the platform
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.media.quality">
+ <permission name="android.permission.OBSERVE_PICTURE_PROFILES"/>
+ </privapp-permissions>
+
<privapp-permissions package="com.android.mtp">
<permission name="android.permission.ACCESS_MTP"/>
<permission name="android.permission.MANAGE_USB"/>
@@ -262,6 +266,8 @@ applications that come with the platform
<!-- BLUETOOTH_PRIVILEGED is needed for test only -->
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
<permission name="android.permission.BIND_APPWIDGET"/>
+ <!-- Needed for CTS tests only -->
+ <permission name="android.permission.OBSERVE_PICTURE_PROFILES"/>
<permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
@@ -527,6 +533,8 @@ applications that come with the platform
<permission name="com.android.cellbroadcastservice.FULL_ACCESS_CELL_BROADCAST_HISTORY" />
<!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
<permission name="android.permission.LOCK_DEVICE" />
+ <!-- Permission required for AuthenticationPolicyManagerTest -->
+ <permission name="android.permission.MANAGE_SECURE_LOCK_DEVICE" />
<!-- Permissions required for CTS test - CtsSafetyCenterTestCases -->
<permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
@@ -575,7 +583,6 @@ applications that come with the platform
<permission name="android.permission.READ_BLOCKED_NUMBERS" />
<!-- Permission required for CTS test - PackageManagerTest -->
<permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
- <permission name="android.permission.VERIFICATION_AGENT"/>
<!-- Permission required for CTS test CtsInputTestCases -->
<permission name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" />
<!-- Permission required for CTS test - PackageManagerShellCommandInstallTest -->
@@ -592,11 +599,14 @@ applications that come with the platform
<!-- Permission required for CTS test - CtsAppTestCases -->
<permission name="android.permission.KILL_UID" />
<!-- Permission required for CTS test - AdvancedProtectionManagerTest -->
- <permission name="android.permission.SET_ADVANCED_PROTECTION_MODE" />
+ <permission name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE" />
<permission name="android.permission.QUERY_ADVANCED_PROTECTION_MODE" />
<!-- Permissions required for CTS test - SettingsPreferenceServiceClientTest -->
<permission name="android.permission.READ_SYSTEM_PREFERENCES" />
<permission name="android.permission.WRITE_SYSTEM_PREFERENCES" />
+ <!-- Permission required for CTS test - IntrusionDetectionManagerTest -->
+ <permission name="android.permission.READ_INTRUSION_DETECTION_STATE" />
+ <permission name="android.permission.MANAGE_INTRUSION_DETECTION_STATE" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/sounds/Android.bp b/data/sounds/Android.bp
new file mode 100644
index 000000000000..65d4872cdc16
--- /dev/null
+++ b/data/sounds/Android.bp
@@ -0,0 +1,304 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+phony {
+ name: "frameworks_sounds",
+ required: [
+ "frameworks_alarm_sounds",
+ "frameworks_notifications_sounds",
+ "frameworks_ringtones_sounds",
+ "frameworks_ui_sounds",
+ "frameworks_ui_48k_sounds",
+ ],
+}
+
+prebuilt_media {
+ name: "frameworks_alarm_sounds",
+ srcs: [
+ "Alarm_Beep_01.ogg",
+ "Alarm_Beep_02.ogg",
+ "Alarm_Beep_03.ogg",
+ "Alarm_Buzzer.ogg",
+ "Alarm_Classic.ogg",
+ "Alarm_Rooster_02.ogg",
+ "alarms/ogg/Argon.ogg",
+ "alarms/ogg/Barium.ogg",
+ "alarms/ogg/Carbon.ogg",
+ "alarms/ogg/Helium.ogg",
+ "alarms/ogg/Krypton.ogg",
+ "alarms/ogg/Neon.ogg",
+ "alarms/ogg/Neptunium.ogg",
+ "alarms/ogg/Osmium.ogg",
+ "alarms/ogg/Oxygen.ogg",
+ "alarms/ogg/Platinum.ogg",
+ "alarms/ogg/Promethium.ogg",
+ "alarms/ogg/Scandium.ogg",
+ ],
+ relative_install_path: "audio/alarms",
+ product_specific: true,
+ no_full_install: true,
+}
+
+prebuilt_media {
+ name: "frameworks_notifications_sounds",
+ srcs: [
+ "notifications/ogg/Adara.ogg",
+ "notifications/Aldebaran.ogg",
+ "notifications/Altair.ogg",
+ "notifications/ogg/Alya.ogg",
+ "notifications/Antares.ogg",
+ "notifications/ogg/Antimony.ogg",
+ "notifications/ogg/Arcturus.ogg",
+ "notifications/ogg/Argon.ogg",
+ "notifications/Beat_Box_Android.ogg",
+ "notifications/ogg/Bellatrix.ogg",
+ "notifications/ogg/Beryllium.ogg",
+ "notifications/Betelgeuse.ogg",
+ "newwavelabs/CaffeineSnake.ogg",
+ "notifications/Canopus.ogg",
+ "notifications/ogg/Capella.ogg",
+ "notifications/Castor.ogg",
+ "notifications/ogg/CetiAlpha.ogg",
+ "notifications/ogg/Cobalt.ogg",
+ "notifications/Cricket.ogg",
+ "newwavelabs/DearDeer.ogg",
+ "notifications/Deneb.ogg",
+ "notifications/Doink.ogg",
+ "newwavelabs/DontPanic.ogg",
+ "notifications/Drip.ogg",
+ "notifications/Electra.ogg",
+ "F1_MissedCall.ogg",
+ "F1_New_MMS.ogg",
+ "F1_New_SMS.ogg",
+ "notifications/ogg/Fluorine.ogg",
+ "notifications/Fomalhaut.ogg",
+ "notifications/ogg/Gallium.ogg",
+ "notifications/Heaven.ogg",
+ "notifications/ogg/Helium.ogg",
+ "newwavelabs/Highwire.ogg",
+ "notifications/ogg/Hojus.ogg",
+ "notifications/ogg/Iridium.ogg",
+ "notifications/ogg/Krypton.ogg",
+ "newwavelabs/KzurbSonar.ogg",
+ "notifications/ogg/Lalande.ogg",
+ "notifications/Merope.ogg",
+ "notifications/ogg/Mira.ogg",
+ "newwavelabs/OnTheHunt.ogg",
+ "notifications/ogg/Palladium.ogg",
+ "notifications/Plastic_Pipe.ogg",
+ "notifications/ogg/Polaris.ogg",
+ "notifications/ogg/Pollux.ogg",
+ "notifications/ogg/Procyon.ogg",
+ "notifications/ogg/Proxima.ogg",
+ "notifications/ogg/Radon.ogg",
+ "notifications/ogg/Rubidium.ogg",
+ "notifications/ogg/Selenium.ogg",
+ "notifications/ogg/Shaula.ogg",
+ "notifications/Sirrah.ogg",
+ "notifications/SpaceSeed.ogg",
+ "notifications/ogg/Spica.ogg",
+ "notifications/ogg/Strontium.ogg",
+ "notifications/ogg/Syrma.ogg",
+ "notifications/TaDa.ogg",
+ "notifications/ogg/Talitha.ogg",
+ "notifications/ogg/Tejat.ogg",
+ "notifications/ogg/Thallium.ogg",
+ "notifications/Tinkerbell.ogg",
+ "notifications/ogg/Upsilon.ogg",
+ "notifications/ogg/Vega.ogg",
+ "newwavelabs/Voila.ogg",
+ "notifications/ogg/Xenon.ogg",
+ "notifications/ogg/Zirconium.ogg",
+ "notifications/arcturus.ogg",
+ "notifications/moonbeam.ogg",
+ "notifications/pixiedust.ogg",
+ "notifications/pizzicato.ogg",
+ "notifications/regulus.ogg",
+ "notifications/sirius.ogg",
+ "notifications/tweeters.ogg",
+ "notifications/vega.ogg",
+ ],
+ relative_install_path: "audio/notifications",
+ product_specific: true,
+ no_full_install: true,
+}
+
+prebuilt_media {
+ name: "frameworks_ringtones_sounds",
+ srcs: [
+ "ringtones/ANDROMEDA.ogg",
+ "ringtones/ogg/Andromeda.ogg",
+ "ringtones/ogg/Aquila.ogg",
+ "ringtones/ogg/ArgoNavis.ogg",
+ "ringtones/ogg/Atria.ogg",
+ "ringtones/BOOTES.ogg",
+ "newwavelabs/Backroad.ogg",
+ "newwavelabs/BeatPlucker.ogg",
+ "newwavelabs/BentleyDubs.ogg",
+ "newwavelabs/Big_Easy.ogg",
+ "newwavelabs/BirdLoop.ogg",
+ "newwavelabs/Bollywood.ogg",
+ "newwavelabs/BussaMove.ogg",
+ "ringtones/CANISMAJOR.ogg",
+ "ringtones/CASSIOPEIA.ogg",
+ "newwavelabs/Cairo.ogg",
+ "newwavelabs/Calypso_Steel.ogg",
+ "ringtones/ogg/CanisMajor.ogg",
+ "newwavelabs/CaribbeanIce.ogg",
+ "ringtones/ogg/Carina.ogg",
+ "ringtones/ogg/Centaurus.ogg",
+ "newwavelabs/Champagne_Edition.ogg",
+ "newwavelabs/Club_Cubano.ogg",
+ "newwavelabs/CrayonRock.ogg",
+ "newwavelabs/CrazyDream.ogg",
+ "newwavelabs/CurveBall.ogg",
+ "ringtones/ogg/Cygnus.ogg",
+ "newwavelabs/DancinFool.ogg",
+ "newwavelabs/Ding.ogg",
+ "newwavelabs/DonMessWivIt.ogg",
+ "ringtones/ogg/Draco.ogg",
+ "newwavelabs/DreamTheme.ogg",
+ "newwavelabs/Eastern_Sky.ogg",
+ "newwavelabs/Enter_the_Nexus.ogg",
+ "ringtones/Eridani.ogg",
+ "newwavelabs/EtherShake.ogg",
+ "ringtones/FreeFlight.ogg",
+ "newwavelabs/FriendlyGhost.ogg",
+ "newwavelabs/Funk_Yall.ogg",
+ "newwavelabs/GameOverGuitar.ogg",
+ "newwavelabs/Gimme_Mo_Town.ogg",
+ "ringtones/ogg/Girtab.ogg",
+ "newwavelabs/Glacial_Groove.ogg",
+ "newwavelabs/Growl.ogg",
+ "newwavelabs/HalfwayHome.ogg",
+ "ringtones/ogg/Hydra.ogg",
+ "newwavelabs/InsertCoin.ogg",
+ "ringtones/ogg/Kuma.ogg",
+ "newwavelabs/LoopyLounge.ogg",
+ "newwavelabs/LoveFlute.ogg",
+ "ringtones/Lyra.ogg",
+ "ringtones/ogg/Machina.ogg",
+ "newwavelabs/MidEvilJaunt.ogg",
+ "newwavelabs/MildlyAlarming.ogg",
+ "newwavelabs/Nairobi.ogg",
+ "newwavelabs/Nassau.ogg",
+ "newwavelabs/NewPlayer.ogg",
+ "newwavelabs/No_Limits.ogg",
+ "newwavelabs/Noises1.ogg",
+ "newwavelabs/Noises2.ogg",
+ "newwavelabs/Noises3.ogg",
+ "newwavelabs/OrganDub.ogg",
+ "ringtones/ogg/Orion.ogg",
+ "ringtones/PERSEUS.ogg",
+ "newwavelabs/Paradise_Island.ogg",
+ "ringtones/ogg/Pegasus.ogg",
+ "ringtones/ogg/Perseus.ogg",
+ "newwavelabs/Playa.ogg",
+ "ringtones/ogg/Pyxis.ogg",
+ "ringtones/ogg/Rasalas.ogg",
+ "newwavelabs/Revelation.ogg",
+ "ringtones/ogg/Rigel.ogg",
+ "Ring_Classic_02.ogg",
+ "Ring_Digital_02.ogg",
+ "Ring_Synth_02.ogg",
+ "Ring_Synth_04.ogg",
+ "newwavelabs/Road_Trip.ogg",
+ "newwavelabs/RomancingTheTone.ogg",
+ "newwavelabs/Safari.ogg",
+ "newwavelabs/Savannah.ogg",
+ "ringtones/ogg/Scarabaeus.ogg",
+ "ringtones/ogg/Sceptrum.ogg",
+ "newwavelabs/Seville.ogg",
+ "newwavelabs/Shes_All_That.ogg",
+ "newwavelabs/SilkyWay.ogg",
+ "newwavelabs/SitarVsSitar.ogg",
+ "ringtones/ogg/Solarium.ogg",
+ "newwavelabs/SpringyJalopy.ogg",
+ "newwavelabs/Steppin_Out.ogg",
+ "newwavelabs/Terminated.ogg",
+ "ringtones/Testudo.ogg",
+ "ringtones/ogg/Themos.ogg",
+ "newwavelabs/Third_Eye.ogg",
+ "newwavelabs/Thunderfoot.ogg",
+ "newwavelabs/TwirlAway.ogg",
+ "ringtones/URSAMINOR.ogg",
+ "ringtones/ogg/UrsaMinor.ogg",
+ "newwavelabs/VeryAlarmed.ogg",
+ "ringtones/Vespa.ogg",
+ "newwavelabs/World.ogg",
+ "ringtones/ogg/Zeta.ogg",
+ "ringtones/hydra.ogg",
+ ],
+ relative_install_path: "audio/ringtones",
+ product_specific: true,
+ no_full_install: true,
+}
+
+prebuilt_media {
+ name: "frameworks_ui_48k_sounds",
+ srcs: [
+ "effects/ogg/Effect_Tick_48k.ogg",
+ "effects/ogg/KeypressDelete_120_48k.ogg",
+ "effects/ogg/KeypressReturn_120_48k.ogg",
+ "effects/ogg/KeypressSpacebar_120_48k.ogg",
+ "effects/ogg/KeypressStandard_120_48k.ogg",
+ "effects/ogg/KeypressInvalid_120_48k.ogg",
+ "effects/ogg/Trusted_48k.ogg",
+ "effects/ogg/VideoRecord_48k.ogg",
+ "effects/ogg/VideoStop_48k.ogg",
+ "effects/ogg/camera_click_48k.ogg",
+ ],
+ dsts: [
+ "Effect_Tick.ogg",
+ "KeypressDelete.ogg",
+ "KeypressReturn.ogg",
+ "KeypressSpacebar.ogg",
+ "KeypressStandard.ogg",
+ "KeypressInvalid.ogg",
+ "Trusted.ogg",
+ "VideoRecord.ogg",
+ "VideoStop.ogg",
+ "camera_click.ogg",
+ ],
+ relative_install_path: "audio/ui",
+ product_specific: true,
+ no_full_install: true,
+}
+
+prebuilt_media {
+ name: "frameworks_ui_sounds",
+ srcs: [
+ "effects/ogg/Dock.ogg",
+ "effects/ogg/Lock.ogg",
+ "effects/ogg/LowBattery.ogg",
+ "effects/ogg/Undock.ogg",
+ "effects/ogg/Unlock.ogg",
+ "effects/ogg/WirelessChargingStarted.ogg",
+ "effects/ogg/camera_focus.ogg",
+ "effects/ogg/ChargingStarted.ogg",
+ "effects/ogg/InCallNotification.ogg",
+ "effects/ogg/NFCFailure.ogg",
+ "effects/ogg/NFCInitiated.ogg",
+ "effects/ogg/NFCSuccess.ogg",
+ "effects/ogg/NFCTransferComplete.ogg",
+ "effects/ogg/NFCTransferInitiated.ogg",
+ ],
+ relative_install_path: "audio/ui",
+ product_specific: true,
+ no_full_install: true,
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java
index cae5d8e6846d..35b2375fbc46 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java
@@ -96,7 +96,7 @@ public final class EfficientParcelableChecker extends BugChecker
}
if (WRITE_PARCELABLE.matches(tree, state)) {
return buildDescription(tree)
- .setMessage("Recommended to use 'item.writeToParcel()' to improve "
+ .setMessage("Recommended to use 'writeTypedObject()' to improve "
+ "efficiency; saves overhead of Parcelable class name")
.build();
}
diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java
index 5c294aa72ce8..c6ae680d01bf 100644
--- a/graphics/java/android/graphics/BlendMode.java
+++ b/graphics/java/android/graphics/BlendMode.java
@@ -571,10 +571,10 @@ public enum BlendMode {
}
@NonNull
- private final Xfermode mXfermode;
+ private final PorterDuffXfermode mXfermode;
BlendMode(int mode) {
- mXfermode = new Xfermode();
+ mXfermode = new PorterDuffXfermode();
mXfermode.porterDuffMode = mode;
}
@@ -582,7 +582,7 @@ public enum BlendMode {
* @hide
*/
@NonNull
- public Xfermode getXfermode() {
+ public PorterDuffXfermode getXfermode() {
return mXfermode;
}
}
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 977aeaa2f4d9..e7145686247e 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -40,9 +40,12 @@ public class ComposeShader extends Shader {
* @param mode The mode that combines the colors from the two shaders. If mode
* is null, then SRC_OVER is assumed.
*/
+ //TODO(358126864): allow a ComposeShader to accept a RuntimeXfermode
@Deprecated
public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull Xfermode mode) {
- this(shaderA, shaderB, mode.porterDuffMode);
+ this(shaderA, shaderB,
+ mode instanceof PorterDuffXfermode ? ((PorterDuffXfermode) mode).porterDuffMode
+ : BlendMode.SRC_OVER.getXfermode().porterDuffMode);
}
/**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 56bb0f0d12d5..9bf4d65e1865 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -71,6 +71,7 @@ public class Paint {
private long mNativePaint;
private long mNativeShader;
private long mNativeColorFilter;
+ private long mNativeXfermode;
// Use a Holder to allow static initialization of Paint in the boot image.
private static class NoImagePreloadHolder {
@@ -735,6 +736,7 @@ public class Paint {
mPathEffect = null;
mShader = null;
mNativeShader = 0;
+ mNativeXfermode = 0;
mTypeface = null;
mXfermode = null;
@@ -780,6 +782,7 @@ public class Paint {
mNativeShader = paint.mNativeShader;
mTypeface = paint.mTypeface;
mXfermode = paint.mXfermode;
+ mNativeXfermode = paint.mNativeXfermode;
mHasCompatScaling = paint.mHasCompatScaling;
mCompatScaling = paint.mCompatScaling;
@@ -815,7 +818,7 @@ public class Paint {
*
* Note: Although this method is |synchronized|, this is simply so it
* is not thread-hostile to multiple threads calling this method. It
- * is still unsafe to attempt to change the Shader/ColorFilter while
+ * is still unsafe to attempt to change the Shader/ColorFilter/Xfermode while
* another thread attempts to access the native object.
*
* @hide
@@ -833,6 +836,15 @@ public class Paint {
mNativeColorFilter = newNativeColorFilter;
nSetColorFilter(mNativePaint, mNativeColorFilter);
}
+ if (com.android.graphics.hwui.flags.Flags.runtimeColorFiltersBlenders()) {
+ if (mXfermode instanceof RuntimeXfermode) {
+ long newNativeXfermode = ((RuntimeXfermode) mXfermode).createNativeInstance();
+ if (newNativeXfermode != mNativeXfermode) {
+ mNativeXfermode = newNativeXfermode;
+ nSetXfermode(mNativePaint, mNativeXfermode);
+ }
+ }
+ }
return mNativePaint;
}
@@ -1427,16 +1439,17 @@ public class Paint {
}
/**
- * Get the paint's blend mode object.
+ * Get the paint's blend mode object. Will return null if there is a Xfermode applied that
+ * cannot be represented by a blend mode (i.e. a custom {@code RuntimeXfermode}
*
* @return the paint's blend mode (or null)
*/
@Nullable
public BlendMode getBlendMode() {
- if (mXfermode == null) {
+ if (mXfermode == null || !(mXfermode instanceof PorterDuffXfermode)) {
return null;
} else {
- return BlendMode.fromValue(mXfermode.porterDuffMode);
+ return BlendMode.fromValue(((PorterDuffXfermode) mXfermode).porterDuffMode);
}
}
@@ -1459,8 +1472,17 @@ public class Paint {
@Nullable
private Xfermode installXfermode(Xfermode xfermode) {
- int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT;
- int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT;
+ if (com.android.graphics.hwui.flags.Flags.runtimeColorFiltersBlenders()) {
+ if (xfermode instanceof RuntimeXfermode) {
+ mXfermode = xfermode;
+ nSetXfermode(mNativePaint, ((RuntimeXfermode) xfermode).createNativeInstance());
+ return xfermode;
+ }
+ }
+ int newMode = (xfermode instanceof PorterDuffXfermode)
+ ? ((PorterDuffXfermode) xfermode).porterDuffMode : PorterDuffXfermode.DEFAULT;
+ int curMode = (mXfermode instanceof PorterDuffXfermode)
+ ? ((PorterDuffXfermode) mXfermode).porterDuffMode : PorterDuffXfermode.DEFAULT;
if (newMode != curMode) {
nSetXfermode(mNativePaint, newMode);
}
@@ -3823,6 +3845,8 @@ public class Paint {
@CriticalNative
private static native void nSetXfermode(long paintPtr, int xfermode);
@CriticalNative
+ private static native void nSetXfermode(long paintPtr, long xfermodePtr);
+ @CriticalNative
private static native long nSetPathEffect(long paintPtr, long effect);
@CriticalNative
private static native long nSetMaskFilter(long paintPtr, long maskfilter);
diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java
index ff9ff8b0069d..83d0507a5074 100644
--- a/graphics/java/android/graphics/PorterDuffXfermode.java
+++ b/graphics/java/android/graphics/PorterDuffXfermode.java
@@ -29,6 +29,9 @@ public class PorterDuffXfermode extends Xfermode {
*
* @param mode The porter-duff mode that is applied
*/
+ static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt;
+ int porterDuffMode = DEFAULT;
+ PorterDuffXfermode() {}
public PorterDuffXfermode(PorterDuff.Mode mode) {
porterDuffMode = mode.nativeInt;
}
diff --git a/graphics/java/android/graphics/RuntimeColorFilter.java b/graphics/java/android/graphics/RuntimeColorFilter.java
index 52724ceaf301..a64acfe767a9 100644
--- a/graphics/java/android/graphics/RuntimeColorFilter.java
+++ b/graphics/java/android/graphics/RuntimeColorFilter.java
@@ -280,7 +280,25 @@ public class RuntimeColorFilter extends ColorFilter {
if (colorFilter == null) {
throw new NullPointerException("The colorFilter parameter must not be null");
}
- nativeUpdateChild(getNativeInstance(), filterName, colorFilter.getNativeInstance());
+ nativeUpdateInputColorFilter(getNativeInstance(), filterName,
+ colorFilter.getNativeInstance());
+ }
+
+ /**
+ * Assigns the uniform xfermode to the provided xfermode parameter. If the shader program does
+ * not have a uniform xfermode with that name then an IllegalArgumentException is thrown.
+ *
+ * @param xfermodeName name matching the uniform declared in the AGSL program
+ * @param xfermode filter passed into the AGSL program for sampling
+ */
+ public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) {
+ if (xfermodeName == null) {
+ throw new NullPointerException("The xfermodeName parameter must not be null");
+ }
+ if (xfermode == null) {
+ throw new NullPointerException("The xfermode parameter must not be null");
+ }
+ nativeUpdateChild(getNativeInstance(), xfermodeName, xfermode.createNativeInstance());
}
/** @hide */
@@ -301,5 +319,6 @@ public class RuntimeColorFilter extends ColorFilter {
long colorFilter, String uniformName, int value1, int value2, int value3,
int value4, int count);
private static native void nativeUpdateChild(long colorFilter, String childName, long child);
-
+ private static native void nativeUpdateInputColorFilter(long colorFilter, String childName,
+ long inputFilter);
}
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 78d257f86613..3543e991924e 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -18,10 +18,13 @@ package android.graphics;
import android.annotation.ColorInt;
import android.annotation.ColorLong;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.util.ArrayMap;
import android.view.Window;
+import com.android.graphics.hwui.flags.Flags;
+
import libcore.util.NativeAllocationRegistry;
/**
@@ -261,6 +264,9 @@ public class RuntimeShader extends Shader {
* enable better heap tracking & tooling support
*/
private ArrayMap<String, Shader> mShaderUniforms = new ArrayMap<>();
+ private ArrayMap<String, ColorFilter> mColorFilterUniforms = new ArrayMap<>();
+ private ArrayMap<String, RuntimeXfermode> mXfermodeUniforms = new ArrayMap<>();
+
/**
* Creates a new RuntimeShader.
@@ -525,6 +531,49 @@ public class RuntimeShader extends Shader {
discardNativeInstance();
}
+ /**
+ * Assigns the uniform color filter to the provided color filter parameter. If the shader
+ * program does not have a uniform color filter with that name then an IllegalArgumentException
+ * is thrown.
+ *
+ * @param filterName name matching the uniform declared in the AGSL program
+ * @param colorFilter filter passed into the AGSL program for sampling
+ */
+ @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
+ public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) {
+ if (filterName == null) {
+ throw new NullPointerException("The filterName parameter must not be null");
+ }
+ if (colorFilter == null) {
+ throw new NullPointerException("The colorFilter parameter must not be null");
+ }
+ mColorFilterUniforms.put(filterName, colorFilter);
+ nativeUpdateColorFilter(mNativeInstanceRuntimeShaderBuilder, filterName,
+ colorFilter.getNativeInstance());
+ discardNativeInstance();
+ }
+
+ /**
+ * Assigns the uniform xfermode to the provided xfermode parameter. If the shader program does
+ * not have a uniform xfermode with that name then an IllegalArgumentException is thrown.
+ *
+ * @param xfermodeName name matching the uniform declared in the AGSL program
+ * @param xfermode filter passed into the AGSL program for sampling
+ */
+ @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
+ public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) {
+ if (xfermodeName == null) {
+ throw new NullPointerException("The xfermodeName parameter must not be null");
+ }
+ if (xfermode == null) {
+ throw new NullPointerException("The xfermode parameter must not be null");
+ }
+ mXfermodeUniforms.put(xfermodeName, xfermode);
+ nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, xfermodeName,
+ xfermode.createNativeInstance());
+ discardNativeInstance();
+ }
+
/** @hide */
@Override
@@ -552,5 +601,9 @@ public class RuntimeShader extends Shader {
int value4, int count);
private static native void nativeUpdateShader(
long shaderBuilder, String shaderName, long shader);
+ private static native void nativeUpdateColorFilter(
+ long shaderBuilder, String colorFilterName, long colorFilter);
+ private static native void nativeUpdateChild(
+ long shaderBuilder, String childName, long child);
}
diff --git a/graphics/java/android/graphics/RuntimeXfermode.java b/graphics/java/android/graphics/RuntimeXfermode.java
new file mode 100644
index 000000000000..c8a0b1a11339
--- /dev/null
+++ b/graphics/java/android/graphics/RuntimeXfermode.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.ColorInt;
+import android.annotation.ColorLong;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+
+import com.android.graphics.hwui.flags.Flags;
+
+import libcore.util.NativeAllocationRegistry;
+
+
+/**
+ * <p>A {@link RuntimeXfermode} calculates a per-pixel color based on the output of a user
+ * * defined Android Graphics Shading Language (AGSL) function.</p>
+ *
+ * <p>This AGSL function takes in two input colors to be operated on. These colors are in sRGB
+ * * and the output is also interpreted as sRGB. The AGSL function signature expects a single input
+ * * of color (packed as a half4 or float4 or vec4).</p>
+ *
+ * <pre class="prettyprint">
+ * vec4 main(half4 src, half4 dst);
+ * </pre>
+ */
+@FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
+public class RuntimeXfermode extends Xfermode {
+
+ private static class NoImagePreloadHolder {
+ public static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ RuntimeXfermode.class.getClassLoader(), nativeGetFinalizer());
+ }
+
+ private long mBuilderNativeInstance;
+
+ /**
+ * Creates a new RuntimeBlender.
+ *
+ * @param agsl The text of AGSL color filter program to run.
+ */
+ public RuntimeXfermode(@NonNull String agsl) {
+ if (agsl == null) {
+ throw new NullPointerException("RuntimeShader requires a non-null AGSL string");
+ }
+ mBuilderNativeInstance = nativeCreateBlenderBuilder(agsl);
+ RuntimeXfermode.NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+ this, mBuilderNativeInstance);
+ }
+ /**
+ * Sets the uniform color value corresponding to this color filter. If the effect does not have
+ * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4
+ * and corresponding layout(color) annotation then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the color uniform declared in the AGSL program
+ * @param color the provided sRGB color
+ */
+ public void setColorUniform(@NonNull String uniformName, @ColorInt int color) {
+ setUniform(uniformName, Color.valueOf(color).getComponents(), true);
+ }
+
+ /**
+ * Sets the uniform color value corresponding to this color filter. If the effect does not have
+ * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4
+ * and corresponding layout(color) annotation then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the color uniform declared in the AGSL program
+ * @param color the provided sRGB color
+ */
+ public void setColorUniform(@NonNull String uniformName, @ColorLong long color) {
+ Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
+ setUniform(uniformName, exSRGB.getComponents(), true);
+ }
+
+ /**
+ * Sets the uniform color value corresponding to this color filter. If the effect does not have
+ * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4
+ * and corresponding layout(color) annotation then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the color uniform declared in the AGSL program
+ * @param color the provided sRGB color
+ */
+ public void setColorUniform(@NonNull String uniformName, @NonNull Color color) {
+ if (color == null) {
+ throw new NullPointerException("The color parameter must not be null");
+ }
+ Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
+ setUniform(uniformName, exSRGB.getComponents(), true);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than a float or
+ * float[1] then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setFloatUniform(@NonNull String uniformName, float value) {
+ setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than a vec2 or
+ * float[2] then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setFloatUniform(@NonNull String uniformName, float value1, float value2) {
+ setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than a vec3 or
+ * float[3] then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setFloatUniform(@NonNull String uniformName, float value1, float value2,
+ float value3) {
+ setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3);
+
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than a vec4 or
+ * float[4] then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setFloatUniform(@NonNull String uniformName, float value1, float value2,
+ float value3, float value4) {
+ setFloatUniform(uniformName, value1, value2, value3, value4, 4);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than a float
+ * (for N=1), vecN, or float[N] where N is the length of the values param then an
+ * IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setFloatUniform(@NonNull String uniformName, @NonNull float[] values) {
+ setUniform(uniformName, values, false);
+ }
+
+ private void setFloatUniform(@NonNull String uniformName, float value1, float value2,
+ float value3, float value4, int count) {
+ if (uniformName == null) {
+ throw new NullPointerException("The uniformName parameter must not be null");
+ }
+ nativeUpdateUniforms(mBuilderNativeInstance, uniformName, value1, value2, value3, value4,
+ count);
+ }
+
+ private void setUniform(@NonNull String uniformName, @NonNull float[] values, boolean isColor) {
+ if (uniformName == null) {
+ throw new NullPointerException("The uniformName parameter must not be null");
+ }
+ if (values == null) {
+ throw new NullPointerException("The uniform values parameter must not be null");
+ }
+ nativeUpdateUniforms(mBuilderNativeInstance, uniformName, values, isColor);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than an int or int[1]
+ * then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setIntUniform(@NonNull String uniformName, int value) {
+ setIntUniform(uniformName, value, 0, 0, 0, 1);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than an ivec2 or
+ * int[2] then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setIntUniform(@NonNull String uniformName, int value1, int value2) {
+ setIntUniform(uniformName, value1, value2, 0, 0, 2);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than an ivec3 or
+ * int[3] then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3) {
+ setIntUniform(uniformName, value1, value2, value3, 0, 3);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than an ivec4 or
+ * int[4] then an IllegalArgumentException is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setIntUniform(@NonNull String uniformName, int value1, int value2,
+ int value3, int value4) {
+ setIntUniform(uniformName, value1, value2, value3, value4, 4);
+ }
+
+ /**
+ * Sets the uniform value corresponding to this color filter. If the effect does not have a
+ * uniform with that name or if the uniform is declared with a type other than an int (for N=1),
+ * ivecN, or int[N] where N is the length of the values param then an IllegalArgumentException
+ * is thrown.
+ *
+ * @param uniformName name matching the uniform declared in the AGSL program
+ */
+ public void setIntUniform(@NonNull String uniformName, @NonNull int[] values) {
+ if (uniformName == null) {
+ throw new NullPointerException("The uniformName parameter must not be null");
+ }
+ if (values == null) {
+ throw new NullPointerException("The uniform values parameter must not be null");
+ }
+ nativeUpdateUniforms(mBuilderNativeInstance, uniformName, values);
+ }
+
+ private void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3,
+ int value4, int count) {
+ if (uniformName == null) {
+ throw new NullPointerException("The uniformName parameter must not be null");
+ }
+ nativeUpdateUniforms(mBuilderNativeInstance, uniformName, value1, value2, value3, value4,
+ count);
+ }
+
+ /**
+ * Assigns the uniform shader to the provided shader parameter. If the shader program does not
+ * have a uniform shader with that name then an IllegalArgumentException is thrown.
+ *
+ * @param shaderName name matching the uniform declared in the AGSL program
+ * @param shader shader passed into the AGSL program for sampling
+ */
+ public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) {
+ if (shaderName == null) {
+ throw new NullPointerException("The shaderName parameter must not be null");
+ }
+ if (shader == null) {
+ throw new NullPointerException("The shader parameter must not be null");
+ }
+ nativeUpdateChild(mBuilderNativeInstance, shaderName, shader.getNativeInstance());
+ }
+
+ /**
+ * Assigns the uniform color filter to the provided color filter parameter. If the shader
+ * program does not have a uniform color filter with that name then an IllegalArgumentException
+ * is thrown.
+ *
+ * @param filterName name matching the uniform declared in the AGSL program
+ * @param colorFilter filter passed into the AGSL program for sampling
+ */
+ public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) {
+ if (filterName == null) {
+ throw new NullPointerException("The filterName parameter must not be null");
+ }
+ if (colorFilter == null) {
+ throw new NullPointerException("The colorFilter parameter must not be null");
+ }
+ nativeUpdateColorFilter(mBuilderNativeInstance, filterName,
+ colorFilter.getNativeInstance());
+ }
+
+ /**
+ * Assigns the uniform xfermode to the provided xfermode parameter. If the shader program does
+ * not have a uniform xfermode with that name then an IllegalArgumentException is thrown.
+ *
+ * @param xfermodeName name matching the uniform declared in the AGSL program
+ * @param xfermode xfermode function passed into the AGSL program for sampling
+ */
+ public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) {
+ if (xfermodeName == null) {
+ throw new NullPointerException("The xfermodeName parameter must not be null");
+ }
+ if (xfermode == null) {
+ throw new NullPointerException("The xfermode parameter must not be null");
+ }
+ nativeUpdateChild(mBuilderNativeInstance, xfermodeName, xfermode.createNativeInstance());
+ }
+
+ /** @hide */
+ public long createNativeInstance() {
+ return nativeCreateNativeInstance(mBuilderNativeInstance);
+ }
+
+ /** @hide */
+ private static native long nativeGetFinalizer();
+ private static native long nativeCreateBlenderBuilder(String agsl);
+ private static native long nativeCreateNativeInstance(long builder);
+ private static native void nativeUpdateUniforms(
+ long builder, String uniformName, float[] uniforms, boolean isColor);
+ private static native void nativeUpdateUniforms(
+ long builder, String uniformName, float value1, float value2, float value3,
+ float value4, int count);
+ private static native void nativeUpdateUniforms(
+ long builder, String uniformName, int[] uniforms);
+ private static native void nativeUpdateUniforms(
+ long builder, String uniformName, int value1, int value2, int value3,
+ int value4, int count);
+ private static native void nativeUpdateChild(long builder, String childName, long child);
+ private static native void nativeUpdateColorFilter(long builder, String childName, long filter);
+
+}
diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java
index 6bb22a12280e..fb689e4cb9c2 100644
--- a/graphics/java/android/graphics/Xfermode.java
+++ b/graphics/java/android/graphics/Xfermode.java
@@ -21,9 +21,6 @@
package android.graphics;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-
/**
* Xfermode is the base class for objects that are called to implement custom
* "transfer-modes" in the drawing pipeline. The static function Create(Modes)
@@ -31,8 +28,4 @@ import android.os.Build;
* specified in the Modes enum. When an Xfermode is assigned to a Paint, then
* objects drawn with that paint have the xfermode applied.
*/
-public class Xfermode {
- static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- int porterDuffMode = DEFAULT;
-}
+public class Xfermode {}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index 089613853555..5ea38431829e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -30,8 +30,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
-import androidx.annotation.BinderThread;
-import androidx.annotation.GuardedBy;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -39,14 +37,12 @@ import androidx.window.common.layout.CommonFoldingFeature;
import androidx.window.common.layout.DisplayFoldFeatureCommon;
import com.android.internal.R;
-import com.android.window.flags.Flags;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
@@ -70,20 +66,8 @@ public final class DeviceStateManagerFoldingFeatureProducer
* "rear display". Concurrent mode for example is activated via public API and can be active in
* both the "open" and "half folded" device states.
*/
- // TODO: b/337820752 - Add @GuardedBy("mCurrentDeviceStateLock") after flag cleanup.
private DeviceState mCurrentDeviceState = INVALID_DEVICE_STATE;
- /**
- * Lock to synchronize access to {@link #mCurrentDeviceState}.
- *
- * <p>This lock is used to ensure thread-safety when accessing and modifying the
- * {@link #mCurrentDeviceState} field. It is acquired by both the binder thread (if
- * {@link Flags#wlinfoOncreate()} is enabled) and the main thread (if
- * {@link Flags#wlinfoOncreate()} is disabled) to prevent race conditions and
- * ensure data consistency.
- */
- private final Object mCurrentDeviceStateLock = new Object();
-
@NonNull
private final RawFoldingFeatureProducer mRawFoldSupplier;
@@ -95,15 +79,12 @@ public final class DeviceStateManagerFoldingFeatureProducer
// The GuardedBy analysis is intra-procedural, meaning it doesn’t consider the getData()
// implementation. See https://errorprone.info/bugpattern/GuardedBy for limitations.
@SuppressWarnings("GuardedBy")
- @BinderThread // When Flags.wlinfoOncreate() is enabled.
- @MainThread // When Flags.wlinfoOncreate() is disabled.
+ @MainThread
@Override
public void onDeviceStateChanged(@NonNull DeviceState state) {
- synchronized (mCurrentDeviceStateLock) {
- mCurrentDeviceState = state;
- mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer.this
- ::notifyFoldingFeatureChangeLocked);
- }
+ mCurrentDeviceState = state;
+ mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer.this
+ ::notifyFoldingFeatureChangeLocked);
}
};
@@ -115,10 +96,8 @@ public final class DeviceStateManagerFoldingFeatureProducer
new DeviceStateMapper(context, deviceStateManager.getSupportedDeviceStates());
if (!mDeviceStateMapper.isDeviceStateToPostureMapEmpty()) {
- final Executor executor =
- Flags.wlinfoOncreate() ? Runnable::run : context.getMainExecutor();
Objects.requireNonNull(deviceStateManager)
- .registerCallback(executor, mDeviceStateCallback);
+ .registerCallback(context.getMainExecutor(), mDeviceStateCallback);
}
}
@@ -145,21 +124,17 @@ public final class DeviceStateManagerFoldingFeatureProducer
@Override
protected void onListenersChanged() {
super.onListenersChanged();
- synchronized (mCurrentDeviceStateLock) {
- if (hasListeners()) {
- mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
- } else {
- mCurrentDeviceState = INVALID_DEVICE_STATE;
- mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
- }
+ if (hasListeners()) {
+ mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
+ } else {
+ mCurrentDeviceState = INVALID_DEVICE_STATE;
+ mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
}
}
@NonNull
private DeviceState getCurrentDeviceState() {
- synchronized (mCurrentDeviceStateLock) {
- return mCurrentDeviceState;
- }
+ return mCurrentDeviceState;
}
@NonNull
@@ -231,7 +206,6 @@ public final class DeviceStateManagerFoldingFeatureProducer
});
}
- @GuardedBy("mCurrentDeviceStateLock")
private void notifyFoldingFeatureChangeLocked(String displayFeaturesString) {
final DeviceState state = mCurrentDeviceState;
if (!mDeviceStateMapper.isDeviceStateValid(state)) {
@@ -252,29 +226,16 @@ public final class DeviceStateManagerFoldingFeatureProducer
return parseListFromString(displayFeaturesString, hingeState);
}
- /**
- * Internal class to map device states to corresponding postures.
- *
- * <p>This class encapsulates the logic for mapping device states to postures. The mapping is
- * immutable after initialization to ensure thread safety.
- */
+ /** Internal class to map device states to corresponding postures. */
private static class DeviceStateMapper {
/**
* Emulated device state
* {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)} to
* {@link CommonFoldingFeature.State} map.
- *
- * <p>This map must be immutable after initialization to ensure thread safety, as it may be
- * accessed from multiple threads. Modifications should only occur during object
- * construction.
*/
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
- /**
- * The list of device states that are supported.
- *
- * <p>This list must be immutable after initialization to ensure thread safety.
- */
+ /** The list of device states that are supported. */
@NonNull
private final List<DeviceState> mSupportedStates;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
index 220fc6f82a71..819cf3492d24 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
@@ -94,7 +94,6 @@ class BackupHelper {
*/
void scheduleBackup() {
if (!mSaveEmbeddingState) {
- // TODO(b/289875940): enabled internally for broader testing.
return;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
index cb280c530c1b..0f1246cd17e3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
@@ -44,7 +44,6 @@ class ParcelableSplitContainerData implements Parcelable {
@NonNull
private final IBinder mSecondaryContainerToken;
- // TODO(b/289875940): making this as non-null once the tag can be auto-generated from the rule.
@Nullable
final String mSplitRuleTag;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
index a79a89a210ac..bf342d76f4c2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
@@ -25,6 +25,9 @@ import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* This class holds the Parcelable data of a {@link TaskFragmentContainer}.
*/
@@ -61,6 +64,12 @@ class ParcelableTaskFragmentContainerData implements Parcelable {
@NonNull
final Rect mLastRequestedBounds;
+ /**
+ * Individual associated activity tokens in different containers that should be finished on
+ * exit.
+ */
+ final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>();
+
ParcelableTaskFragmentContainerData(@NonNull IBinder token, @Nullable String overlayTag,
@Nullable IBinder associatedActivityToken) {
mToken = token;
@@ -74,6 +83,7 @@ class ParcelableTaskFragmentContainerData implements Parcelable {
mOverlayTag = in.readString();
mAssociatedActivityToken = in.readStrongBinder();
mLastRequestedBounds = in.readTypedObject(Rect.CREATOR);
+ in.readBinderList(mActivitiesToFinishOnExit);
}
public static final Creator<ParcelableTaskFragmentContainerData> CREATOR = new Creator<>() {
@@ -99,7 +109,7 @@ class ParcelableTaskFragmentContainerData implements Parcelable {
dest.writeString(mOverlayTag);
dest.writeStrongBinder(mAssociatedActivityToken);
dest.writeTypedObject(mLastRequestedBounds, flags);
+ dest.writeBinderList(mActivitiesToFinishOnExit);
}
-
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index faf73c24073f..5ba30ddd2f18 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -98,10 +98,20 @@ class SplitContainer {
mCurrentSplitAttributes = mDefaultSplitAttributes;
if (shouldFinishPrimaryWithSecondary(splitRule)) {
- mSecondaryContainer.addContainerToFinishOnExit(mPrimaryContainer);
+ addContainerToFinishOnExitWhenRestore(mSecondaryContainer, mPrimaryContainer);
}
if (shouldFinishSecondaryWithPrimary(splitRule)) {
- mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
+ addContainerToFinishOnExitWhenRestore(mPrimaryContainer, mSecondaryContainer);
+ }
+ }
+
+ private void addContainerToFinishOnExitWhenRestore(
+ @NonNull TaskFragmentContainer containerToAdd,
+ @NonNull TaskFragmentContainer containerToFinish) {
+ // If an activity was already added to be finished after the restoration, then that's it.
+ // Otherwise, add the container to finish on exit.
+ if (!containerToAdd.hasActivityToFinishOnExit(containerToFinish)) {
+ containerToAdd.addContainerToFinishOnExit(containerToFinish);
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index dc1d983997c6..b3e003e7ad95 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -96,12 +96,6 @@ class TaskFragmentContainer {
new ArrayList<>();
/**
- * Individual associated activity tokens in different containers that should be finished on
- * exit.
- */
- private final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>();
-
- /**
* The launch options that was used to create this container. Must not {@link Bundle#isEmpty()}
* for {@link #isOverlay()} container.
*/
@@ -114,7 +108,6 @@ class TaskFragmentContainer {
/**
* Windowing mode that was requested last via {@link android.window.WindowContainerTransaction}.
*/
- // TODO(b/289875940): review this and other field that might need to be moved in the base class.
@WindowingMode
private int mLastRequestedWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -443,7 +436,7 @@ class TaskFragmentContainer {
// Remove the activity now because there can be a delay before the server callback.
mInfo.getActivities().remove(activityToken);
}
- mActivitiesToFinishOnExit.remove(activityToken);
+ mParcelableData.mActivitiesToFinishOnExit.remove(activityToken);
finishSelfWithActivityIfNeeded(wct, activityToken);
}
@@ -624,7 +617,20 @@ class TaskFragmentContainer {
if (mIsFinished) {
return;
}
- mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken());
+ mParcelableData.mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken());
+ }
+
+ /**
+ * Returns {@code true} if an Activity from the given {@code container} was added to be
+ * finished on exit. Otherwise, return {@code false}.
+ */
+ boolean hasActivityToFinishOnExit(@NonNull TaskFragmentContainer container) {
+ for (IBinder activity : mParcelableData.mActivitiesToFinishOnExit) {
+ if (container.hasActivity(activity)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -634,7 +640,7 @@ class TaskFragmentContainer {
if (mIsFinished) {
return;
}
- mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken());
+ mParcelableData.mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken());
}
/** Removes all dependencies that should be finished when this container is finished. */
@@ -643,7 +649,7 @@ class TaskFragmentContainer {
return;
}
mContainersToFinishOnExit.clear();
- mActivitiesToFinishOnExit.clear();
+ mParcelableData.mActivitiesToFinishOnExit.clear();
}
/**
@@ -721,7 +727,7 @@ class TaskFragmentContainer {
mContainersToFinishOnExit.clear();
// Finish associated activities
- for (IBinder activityToken : mActivitiesToFinishOnExit) {
+ for (IBinder activityToken : mParcelableData.mActivitiesToFinishOnExit) {
final Activity activity = mController.getActivity(activityToken);
if (activity == null || activity.isFinishing()
|| controller.shouldRetainAssociatedActivity(this, activity)) {
@@ -729,7 +735,7 @@ class TaskFragmentContainer {
}
wct.finishActivity(activity.getActivityToken());
}
- mActivitiesToFinishOnExit.clear();
+ mParcelableData.mActivitiesToFinishOnExit.clear();
}
@GuardedBy("mController.mLock")
@@ -1082,7 +1088,7 @@ class TaskFragmentContainer {
+ " pendingAppearedActivities=" + mPendingAppearedActivities
+ (includeContainersToFinishOnExit ? " containersToFinishOnExit="
+ containersToFinishOnExitToString() : "")
- + " activitiesToFinishOnExit=" + mActivitiesToFinishOnExit
+ + " activitiesToFinishOnExit=" + mParcelableData.mActivitiesToFinishOnExit
+ " info=" + mInfo
+ "}";
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
index 90887a747a6f..fb01cd88158c 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
@@ -20,9 +20,6 @@ import android.content.Context
import android.content.res.Resources
import android.hardware.devicestate.DeviceState
import android.hardware.devicestate.DeviceStateManager
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.window.common.layout.CommonFoldingFeature
import androidx.window.common.layout.CommonFoldingFeature.COMMON_STATE_FLAT
@@ -34,15 +31,11 @@ import androidx.window.common.layout.DisplayFoldFeatureCommon
import androidx.window.common.layout.DisplayFoldFeatureCommon.DISPLAY_FOLD_FEATURE_PROPERTY_SUPPORTS_HALF_OPENED
import androidx.window.common.layout.DisplayFoldFeatureCommon.DISPLAY_FOLD_FEATURE_TYPE_SCREEN_FOLD_IN
import com.android.internal.R
-import com.android.window.flags.Flags
import com.google.common.truth.Truth.assertThat
import java.util.Optional
-import java.util.concurrent.Executor
import java.util.function.Consumer
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
@@ -60,9 +53,6 @@ import org.mockito.kotlin.verify
*/
@RunWith(AndroidJUnit4::class)
class DeviceStateManagerFoldingFeatureProducerTest {
- @get:Rule
- val setFlagsRule: SetFlagsRule = SetFlagsRule()
-
private val mMockDeviceStateManager = mock<DeviceStateManager>()
private val mMockResources = mock<Resources> {
on { getStringArray(R.array.config_device_state_postures) } doReturn DEVICE_STATE_POSTURES
@@ -79,8 +69,7 @@ class DeviceStateManagerFoldingFeatureProducerTest {
}
@Test
- @DisableFlags(Flags.FLAG_WLINFO_ONCREATE)
- fun testRegisterCallback_whenWlinfoOncreateIsDisabled_usesMainExecutor() {
+ fun testRegisterCallback_usesMainExecutor() {
DeviceStateManagerFoldingFeatureProducer(
mMockContext,
mRawFoldSupplier,
@@ -91,23 +80,6 @@ class DeviceStateManagerFoldingFeatureProducerTest {
}
@Test
- @EnableFlags(Flags.FLAG_WLINFO_ONCREATE)
- fun testRegisterCallback_whenWlinfoOncreateIsEnabled_usesRunnableRun() {
- val executorCaptor = ArgumentCaptor.forClass(Executor::class.java)
- val runnable = mock<Runnable>()
-
- DeviceStateManagerFoldingFeatureProducer(
- mMockContext,
- mRawFoldSupplier,
- mMockDeviceStateManager,
- )
-
- verify(mMockDeviceStateManager).registerCallback(executorCaptor.capture(), any())
- executorCaptor.value.execute(runnable)
- verify(runnable).run()
- }
-
- @Test
fun testGetCurrentData_validCurrentState_returnsFoldingFeatureWithState() {
val ffp = DeviceStateManagerFoldingFeatureProducer(
mMockContext,
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 42188dec4236..4c75ea4777da 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -156,51 +156,6 @@ java_library {
},
}
-filegroup {
- name: "wm_shell-shared-utils",
- srcs: [
- "shared/src/com/android/wm/shell/shared/TransitionUtil.java",
- ],
-}
-
-filegroup {
- name: "wm_shell-shared-aidls",
-
- srcs: [
- "shared/**/*.aidl",
- ],
-
- path: "shared/src",
-}
-
-java_library {
- name: "WindowManager-Shell-shared",
-
- srcs: [
- "shared/**/*.java",
- "shared/**/*.kt",
- ":wm_shell-shared-aidls",
- ],
- static_libs: [
- "androidx.core_core-animation",
- "androidx.dynamicanimation_dynamicanimation",
- "jsr330",
- ],
- kotlincflags: ["-Xjvm-default=all"],
-}
-
-java_library {
- name: "WindowManager-Shell-shared-desktopMode",
-
- srcs: [
- "shared/**/desktopmode/*.java",
- "shared/**/desktopmode/*.kt",
- ],
- static_libs: [
- "com.android.window.flags.window-aconfig-java",
- ],
-}
-
android_library {
name: "WindowManager-Shell",
srcs: [
@@ -227,6 +182,7 @@ android_library {
"kotlinx-coroutines-core",
"//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
"//frameworks/libs/systemui:iconloader_base",
+ "com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
"PlatformAnimationLib",
"WindowManager-Shell-proto",
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
index 6ac36a3319c9..1bf6af8d1f6d 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.bubbles.bar
import android.app.ActivityManager
+import android.content.ComponentName
import android.content.Context
import android.content.pm.ShortcutInfo
import android.graphics.Insets
@@ -24,6 +25,7 @@ import android.graphics.Rect
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
+import android.widget.FrameLayout
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -110,9 +112,9 @@ class BubbleBarExpandedViewTest {
regionSamplingProvider = TestRegionSamplingProvider()
- bubbleExpandedView = (inflater.inflate(
+ bubbleExpandedView = inflater.inflate(
R.layout.bubble_bar_expanded_view, null, false /* attachToRoot */
- ) as BubbleBarExpandedView)
+ ) as BubbleBarExpandedView
bubbleExpandedView.initialize(
expandedViewManager,
positioner,
@@ -124,11 +126,11 @@ class BubbleBarExpandedViewTest {
regionSamplingProvider,
)
- getInstrumentation().runOnMainSync(Runnable {
+ getInstrumentation().runOnMainSync {
bubbleExpandedView.onAttachedToWindow()
// Helper should be created once attached to window
testableRegionSamplingHelper = regionSamplingProvider!!.helper
- })
+ }
bubble = Bubble(
"key",
@@ -254,6 +256,93 @@ class BubbleBarExpandedViewTest {
assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble)
}
+ @Test
+ fun animateExpansion_waitsUntilTaskCreated() {
+ var animated = false
+ bubbleExpandedView.animateExpansionWhenTaskViewVisible { animated = true }
+ assertThat(animated).isFalse()
+ bubbleExpandedView.onTaskCreated()
+ assertThat(animated).isTrue()
+ }
+
+ @Test
+ fun animateExpansion_taskViewAttachedAndVisible() {
+ val inflater = LayoutInflater.from(context)
+ val expandedView = inflater.inflate(
+ R.layout.bubble_bar_expanded_view, null, false /* attachToRoot */
+ ) as BubbleBarExpandedView
+ val taskView = FakeBubbleTaskViewFactory().create()
+ val taskViewParent = FrameLayout(context)
+ taskViewParent.addView(taskView.taskView)
+ taskView.listener.onTaskCreated(666, ComponentName(context, "BubbleBarExpandedViewTest"))
+ assertThat(taskView.isVisible).isTrue()
+
+ expandedView.initialize(
+ expandedViewManager,
+ positioner,
+ BubbleLogger(uiEventLoggerFake),
+ false /* isOverflow */,
+ taskView,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingProvider,
+ )
+
+ // the task view should be removed from its parent
+ assertThat(taskView.taskView.parent).isNull()
+
+ var animated = false
+ expandedView.animateExpansionWhenTaskViewVisible { animated = true }
+ assertThat(animated).isFalse()
+
+ // send an invisible signal to simulate the surface getting destroyed
+ expandedView.onContentVisibilityChanged(false)
+
+ // send a visible signal to simulate a new surface getting created
+ expandedView.onContentVisibilityChanged(true)
+
+ assertThat(taskView.taskView.parent).isEqualTo(expandedView)
+ assertThat(animated).isTrue()
+ }
+
+ @Test
+ fun animateExpansion_taskViewAttachedAndInvisible() {
+ val inflater = LayoutInflater.from(context)
+ val expandedView = inflater.inflate(
+ R.layout.bubble_bar_expanded_view, null, false /* attachToRoot */
+ ) as BubbleBarExpandedView
+ val taskView = FakeBubbleTaskViewFactory().create()
+ val taskViewParent = FrameLayout(context)
+ taskViewParent.addView(taskView.taskView)
+ taskView.listener.onTaskCreated(666, ComponentName(context, "BubbleBarExpandedViewTest"))
+ assertThat(taskView.isVisible).isTrue()
+ taskView.listener.onTaskVisibilityChanged(666, false)
+ assertThat(taskView.isVisible).isFalse()
+
+ expandedView.initialize(
+ expandedViewManager,
+ positioner,
+ BubbleLogger(uiEventLoggerFake),
+ false /* isOverflow */,
+ taskView,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingProvider,
+ )
+
+ // the task view should be added to the expanded view
+ assertThat(taskView.taskView.parent).isEqualTo(expandedView)
+
+ var animated = false
+ expandedView.animateExpansionWhenTaskViewVisible { animated = true }
+ assertThat(animated).isFalse()
+
+ // send a visible signal to simulate a new surface getting created
+ expandedView.onContentVisibilityChanged(true)
+
+ assertThat(animated).isTrue()
+ }
+
private fun BubbleBarExpandedView.menuView(): BubbleBarMenuView {
return findViewByPredicate { it is BubbleBarMenuView }
}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
index 0044593ad228..3d34cbaeaf08 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
@@ -253,6 +253,7 @@ class BubbleBarLayerViewTest {
getInstrumentation().runOnMainSync {
bubbleBarLayerView.showExpandedView(bubble)
+ bubble.bubbleBarExpandedView!!.onContentVisibilityChanged(true)
}
waitForExpandedViewAnimation()
@@ -276,6 +277,7 @@ class BubbleBarLayerViewTest {
getInstrumentation().runOnMainSync {
bubbleBarLayerView.showExpandedView(bubble)
+ bubble.bubbleBarExpandedView!!.onContentVisibilityChanged(true)
}
waitForExpandedViewAnimation()
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
index a18a2510f0f7..bfd9c818a96e 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -23,7 +23,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:paddingBottom="@dimen/desktop_mode_handle_menu_pill_elevation"
- android:paddingRight="@dimen/desktop_mode_handle_menu_pill_elevation"
+ android:paddingEnd="@dimen/desktop_mode_handle_menu_pill_elevation"
android:orientation="vertical">
<LinearLayout
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
index 5e41865cd31e..375968ab0ad2 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
@@ -113,7 +113,7 @@
style="?android:attr/buttonBarButtonStyle"
android:layout_width="41dp"
android:layout_height="@dimen/desktop_mode_maximize_menu_button_height"
- android:layout_marginRight="4dp"
+ android:layout_marginEnd="4dp"
android:background="@drawable/desktop_mode_maximize_menu_button_background"
android:importantForAccessibility="yes"
android:contentDescription="@string/desktop_mode_maximize_menu_snap_left_button_text"
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index a4aa3480fb46..9a1a3da06a77 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Kies"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Skermskoot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Maak in blaaier oop"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Maak in app oop"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nuwe venster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Bestuur vensters"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Verander aspekverhouding"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Maak kieslys oop"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimeer skerm"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gryp skerm vas"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App kan nie hierheen geskuif word nie"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Meesleurend"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Stel terug"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 1cd980460cee..9d22fef66636 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ምረጥ"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ቅጽበታዊ ገፅ ዕይታ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"በአሳሽ ውስጥ ክፈት"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"መተግበሪያ ውስጥ ክፈት"</string>
<string name="new_window_text" msgid="6318648868380652280">"አዲስ መስኮት"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"መስኮቶችን አስተዳድር"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ምጥጥነ ገፅታ ለውጥ"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ምናሌን ክፈት"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"የማያ ገጹ መጠን አሳድግ"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ማያ ገጹን አሳድግ"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"መተግበሪያ ወደዚህ መንቀሳቀስ አይችልም"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"አስማጭ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ወደነበረበት መልስ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 41ebfcd0ee85..46ab090e310e 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"اختيار"</string>
<string name="screenshot_text" msgid="1477704010087786671">"لقطة شاشة"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"فتح في المتصفِّح"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"فتح في التطبيق"</string>
<string name="new_window_text" msgid="6318648868380652280">"نافذة جديدة"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"إدارة النوافذ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغيير نسبة العرض إلى الارتفاع"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"فتح القائمة"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"التقاط صورة للشاشة"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"مجسَّم"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"استعادة"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 203fed0aecef..1e35d6ed132f 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"বাছনি কৰক"</string>
<string name="screenshot_text" msgid="1477704010087786671">"স্ক্ৰীনশ্বট"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ব্ৰাউজাৰত খোলক"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"এপত খোলক"</string>
<string name="new_window_text" msgid="6318648868380652280">"নতুন ৱিণ্ড’"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ৱিণ্ড’ পৰিচালনা কৰক"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"আকাৰৰ অনুপাত সলনি কৰক"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"মেনু খোলক"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্ৰীন স্নেপ কৰক"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ইয়ালৈ এপ্‌টো আনিব নোৱাৰি"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ইমাৰ্ছিভ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"পুনঃস্থাপন কৰক"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 31ddc9b78b68..136d4c18c3d5 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Seçin"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Skrinşot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Brauzerdə açın"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Tətbiqdə açın"</string>
<string name="new_window_text" msgid="6318648868380652280">"Yeni pəncərə"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pəncərələri idarə edin"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tərəflər nisbətini dəyişin"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menyunu açın"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı maksimum böyüdün"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranı çəkin"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Tətbiqi bura köçürmək mümkün deyil"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"İmmersiv"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Bərpa edin"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 486b3cfbfee4..10a33bb6aca7 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Izaberite"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvorite u pregledaču"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Otvorite u aplikaciji"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljajte prozorima"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promenite razmeru"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvorite meni"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Uklopi ekran"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imerzivne"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index cc42da947c36..163fbddbc967 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Выбраць"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Здымак экрана"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Адкрыць у браўзеры"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Адкрыць у праграме"</string>
<string name="new_window_text" msgid="6318648868380652280">"Новае акно"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Кіраваць вокнамі"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змяніць суадносіны бакоў"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Адкрыць меню"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Разгарнуць на ўвесь экран"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Размясціць на палавіне экрана"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Нельга перамясціць сюды праграму"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"З эфектам прысутнасці"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Аднавіць"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index c12b37b34d5a..d7da3aef02bb 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Избиране"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Екранна снимка"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Отваряне в браузър"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Отваряне в приложение"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нов прозорец"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управление на прозорците"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промяна на съотношението"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отваряне на менюто"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Прилепване на екрана"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложението не може да бъде преместено тук"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Реалистично"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Възстановяване"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index aca5b34ae4c0..9c2fc6e98818 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"বেছে নিন"</string>
<string name="screenshot_text" msgid="1477704010087786671">"স্ক্রিনশট"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ব্রাউজারে খুলুন"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"অ্যাপে খুলুন"</string>
<string name="new_window_text" msgid="6318648868380652280">"নতুন উইন্ডো"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"উইন্ডো ম্যানেজ করুন"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"অ্যাস্পেক্ট রেশিও পরিবর্তন করুন"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"মেনু খুলুন"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্রিনে অ্যাপ মানানসই হিসেবে ছোট বড় করুন"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"অ্যাপটি এখানে সরানো যাবে না"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ইমারসিভ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ফিরিয়ে আনুন"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 6bd6473a5f13..911285d060f1 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Odabir"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvaranje u pregledniku"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Otvaranje u aplikaciji"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promjena formata slike"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvaranje menija"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snimi ekran"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Uvjerljivo"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vraćanje"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index d9ad5a68d163..4249373e0a3d 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Selecciona"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Obre al navegador"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Obre a l\'aplicació"</string>
<string name="new_window_text" msgid="6318648868380652280">"Finestra nova"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestiona les finestres"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Canvia la relació d\'aspecte"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Obre el menú"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajusta la pantalla"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"L\'aplicació no es pot moure aquí"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiu"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaura"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index ab51b666cdda..a12534372135 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Vybrat"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Snímek obrazovky"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otevřít v prohlížeči"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Otevřít v aplikaci"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nové okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Spravovat okna"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Změnit poměr stran"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otevřít nabídku"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Rozpůlit obrazovku"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikaci sem nelze přesunout"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Pohlcující"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnovit"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 443620804e10..5b657f4c9bb6 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Vælg"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Åbn i browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Åbn i app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nyt vindue"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduer"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Skift billedformat"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Åbn menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimér skærm"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tilpas skærm"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apps kan ikke flyttes hertil"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Opslugende"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Gendan"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index b6e89c0eeb8e..6d360e8e0af2 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Auswählen"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Im Browser öffnen"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"In der App öffnen"</string>
<string name="new_window_text" msgid="6318648868380652280">"Neues Fenster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Fenster verwalten"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Seitenverhältnis ändern"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menü öffnen"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Bildschirm maximieren"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Bildschirm teilen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Die App kann nicht hierher verschoben werden"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiv"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Wiederherstellen"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 601c0ceee27f..85a44f6d760d 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Επιλογή"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Στιγμιότυπο οθόνης"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Άνοιγμα σε πρόγραμμα περιήγησης"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Άνοιγμα στην εφαρμογή"</string>
<string name="new_window_text" msgid="6318648868380652280">"Νέο παράθυρο"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Διαχείριση παραθύρων"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Αλλαγή λόγου διαστάσεων"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Άνοιγμα μενού"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Προβολή στο μισό της οθόνης"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Καθηλωτικό"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Επαναφορά"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index fd6317530109..3e30ff048c6d 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Select"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Open in app"</string>
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index dac1b9a1460d..0d7189bd16b3 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Select"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Open in App"</string>
<string name="new_window_text" msgid="6318648868380652280">"New Window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage Windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open Menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap Screen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index fd6317530109..3e30ff048c6d 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Select"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Open in app"</string>
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index fd6317530109..3e30ff048c6d 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Select"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Open in app"</string>
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index e67fc8e2c63c..6a1a2e5a4d39 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Seleccionar"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir en el navegador"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Abrir en la app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nueva ventana"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Administrar ventanas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir el menú"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Inmersivo"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restablecer"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 2f5ec64be629..f93cf5a2fefd 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Seleccionar"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir en el navegador"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Abrir en la aplicación"</string>
<string name="new_window_text" msgid="6318648868380652280">"Ventana nueva"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestionar ventanas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir menú"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"La aplicación no se puede mover aquí"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Inmersivo"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index dd78628093d4..f0d1d4e60392 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Vali"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Ekraanipilt"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Avamine brauseris"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Ava rakenduses"</string>
<string name="new_window_text" msgid="6318648868380652280">"Uus aken"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Akende haldamine"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Kuvasuhte muutmine"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ava menüü"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Kuva poolel ekraanil"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Rakendust ei saa siia teisaldada"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Kaasahaarav"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Taasta"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 1cfc69457ce9..c6a7f2eca877 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Hautatu"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Pantaila-argazkia"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Ireki arakatzailean"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Ireki aplikazioan"</string>
<string name="new_window_text" msgid="6318648868380652280">"Leiho berria"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Kudeatu leihoak"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Aldatu aspektu-erlazioa"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ireki menua"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zatitu pantaila"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikazioa ezin da hona ekarri"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Murgiltzailea"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Leheneratu"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index f76f67d2e796..d10a02d75c18 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"انتخاب"</string>
<string name="screenshot_text" msgid="1477704010087786671">"نماگرفت"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"باز کردن در مرورگر"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"باز کردن در برنامه"</string>
<string name="new_window_text" msgid="6318648868380652280">"پنجره جدید"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"مدیریت کردن پنجره‌ها"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغییر نسبت ابعادی"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"باز کردن منو"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"بزرگ کردن صفحه"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"برنامه را نمی‌توان به اینجا منتقل کرد"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"فراگیر"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"بازیابی"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index a1ec0150ffae..0655f9a390a0 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Valitse"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Kuvakaappaus"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Avaa selaimessa"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Avaa sovelluksessa"</string>
<string name="new_window_text" msgid="6318648868380652280">"Uusi ikkuna"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Hallinnoi ikkunoita"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Vaihda kuvasuhdetta"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Avaa valikko"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Suurenna näyttö"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Jaa näyttö"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Sovellusta ei voi siirtää tänne"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiivinen"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Palauta"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 1b9b74a45671..b9bdbd73aed6 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Sélectionner"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Capture d\'écran"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Ouvrir dans le navigateur"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Ouvrir dans l\'appli"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nouvelle fenêtre"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier les proportions"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ouvrir le menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Agrandir l\'écran"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aligner l\'écran"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersif"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurer"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 7e0a0b1acb7b..a1eb028a4f9c 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Sélectionner"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Capture d\'écran"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Ouvrir dans un navigateur"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Ouvrir dans l\'appli"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nouvelle fenêtre"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier le format"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ouvrir le menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mettre en plein écran"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fractionner l\'écran"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersif"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurer"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index bdd07476efcf..22a7f7fcb35b 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Seleccionar"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Abrir na aplicación"</string>
<string name="new_window_text" msgid="6318648868380652280">"Ventá nova"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Xestionar as ventás"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar a proporción"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menú"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar pantalla"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Non se pode mover aquí a aplicación"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Envolvente"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index d23c4fd8f0e0..06c21b46a97e 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"પસંદ કરો"</string>
<string name="screenshot_text" msgid="1477704010087786671">"સ્ક્રીનશૉટ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"બ્રાઉઝરમાં ખોલો"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ઍપમાં ખોલો"</string>
<string name="new_window_text" msgid="6318648868380652280">"નવી વિન્ડો"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"વિન્ડો મેનેજ કરો"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"સાપેક્ષ ગુણોત્તર બદલો"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"મેનૂ ખોલો"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"સ્ક્રીન કરો મોટી કરો"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"સ્ક્રીન સ્નૅપ કરો"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ઍપ અહીં ખસેડી શકાતી નથી"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ઇમર્સિવ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"રિસ્ટોર કરો"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 4eec6f877fab..0eab10c34606 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"चुनें"</string>
<string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ब्राउज़र में खोलें"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ऐप्लिकेशन में खोलें"</string>
<string name="new_window_text" msgid="6318648868380652280">"नई विंडो"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"विंडो मैनेज करें"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेन्यू खोलें"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्नैप स्क्रीन"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ऐप्लिकेशन को यहां मूव नहीं किया जा सकता"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिव"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"वापस लाएं"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index a119d9e7f782..bf756f63395b 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Odaberite"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Snimka zaslona"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvori u pregledniku"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Otvori u aplikaciji"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promijeni omjer slike"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvaranje izbornika"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Izradi snimku zaslona"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija se ne može premjestiti ovdje"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Interaktivno"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index c07b6c3b9f1d..b02be18cb6f2 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Kiválasztás"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Képernyőkép"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Megnyitás böngészőben"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Megnyitás alkalmazásban"</string>
<string name="new_window_text" msgid="6318648868380652280">"Új ablak"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Ablakok kezelése"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Méretarány módosítása"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menü megnyitása"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Képernyő méretének maximalizálása"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Igazodás a képernyő adott részéhez"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Az alkalmazás nem helyezhető át ide"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Magával ragadó"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Visszaállítás"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 52eb18580de1..59a95f0c1393 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Ընտրել"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Սքրինշոթ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Բացել դիտարկիչում"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Բացել հավելվածում"</string>
<string name="new_window_text" msgid="6318648868380652280">"Նոր պատուհան"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Կառավարել պատուհանները"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Փոխել կողմերի հարաբերակցությունը"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Բացել ընտրացանկը"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ծալել էկրանը"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Հավելվածը հնարավոր չէ տեղափոխել այստեղ"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Ներկայության էֆեկտով"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Վերականգնել"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index f8f9d5e16439..baa1d0ec6bae 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Pilih"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Buka di browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Buka di Aplikasi"</string>
<string name="new_window_text" msgid="6318648868380652280">"Jendela Baru"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Kelola Jendela"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ubah rasio aspek"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buka Menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Perbesar Layar"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gabungkan Layar"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikasi tidak dapat dipindahkan ke sini"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imersif"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Pulihkan"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 8a9e3c0ca0a4..c3ad5d66e17a 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Velja"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Skjámynd"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Opna í vafra"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Opna í forriti"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nýr gluggi"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Stjórna gluggum"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Breyta myndhlutfalli"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Opna valmynd"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Smelluskjár"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ekki er hægt að færa forritið hingað"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Umlykjandi"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Endurheimta"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 138adefed160..b75c041afdab 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Seleziona"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Apri nel browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Apri nell\'app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nuova finestra"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestisci finestre"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambia proporzioni"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Apri il menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aggancia schermo"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossibile spostare l\'app qui"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersivo"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Ripristina"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 917738dc1575..5f37590298de 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"בחירה"</string>
<string name="screenshot_text" msgid="1477704010087786671">"צילום מסך"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"פתיחה בדפדפן"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"פתיחה באפליקציה"</string>
<string name="new_window_text" msgid="6318648868380652280">"חלון חדש"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ניהול החלונות"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי של יחס גובה-רוחב"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"פתיחת התפריט"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"כיווץ המסך"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"לא ניתן להעביר את האפליקציה לכאן"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"סוחף"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"שחזור"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 35c48212cf39..2960a19cef0a 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"選択"</string>
<string name="screenshot_text" msgid="1477704010087786671">"スクリーンショット"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ブラウザで開く"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"アプリで開く"</string>
<string name="new_window_text" msgid="6318648868380652280">"新しいウィンドウ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ウィンドウを管理する"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"アスペクト比を変更"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"メニューを開く"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"画面のスナップ"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"アプリはここに移動できません"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"没入モード"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"復元"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 9b9966f152ee..6420bf531f24 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"არჩევა"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ეკრანის ანაბეჭდი"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ბრაუზერში გახსნა"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"აპში გახსნა"</string>
<string name="new_window_text" msgid="6318648868380652280">"ახალი ფანჯარა"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ფანჯრების მართვა"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"თანაფარდობის შეცვლა"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"მენიუს გახსნა"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"აპლიკაციის დაპატარავება ეკრანზე"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"აპის აქ გადატანა შეუძლებელია"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"იმერსიული"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"აღდგენა"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 8618ba9b2b0f..ef169537a899 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Таңдау"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Браузерден ашу"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Қолданбада ашу"</string>
<string name="new_window_text" msgid="6318648868380652280">"Жаңа терезе"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Терезелерді басқару"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Арақатынасты өзгерту"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Мәзірді ашу"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды бөлу"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Қолданба бұл жерге қойылмайды."</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Әсерлі"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Қалпына келтіру"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 7f853f3e1e2f..a625201261b1 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ជ្រើសរើស"</string>
<string name="screenshot_text" msgid="1477704010087786671">"រូបថតអេក្រង់"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"បើកក្នុងកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"បើក​នៅ​ក្នុង​កម្មវិធី"</string>
<string name="new_window_text" msgid="6318648868380652280">"វិនដូ​ថ្មី"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"គ្រប់គ្រង​វិនដូ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ប្ដូរ​​សមាមាត្រ"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"បិទ​ម៉ឺនុយ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"បើកម៉ឺនុយ"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ថតអេក្រង់"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"មិនអាចផ្លាស់ទីកម្មវិធីមកទីនេះបានទេ"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ជក់ចិត្ត"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ស្ដារ"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 456dea2fdb0f..b2bf3a50d505 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ಬ್ರೌಸರ್‌ನಲ್ಲಿ ತೆರೆಯಿರಿ"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ಆ್ಯಪ್‌ನಲ್ಲಿ ತೆರೆಯಿರಿ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ಹೊಸ ವಿಂಡೋ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ವಿಂಡೋಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ಮೆನು ತೆರೆಯಿರಿ"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ಸ್ನ್ಯಾಪ್ ಸ್ಕ್ರೀನ್"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ಆ್ಯಪ್ ಅನ್ನು ಇಲ್ಲಿಗೆ ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ಇಮ್ಮರ್ಸಿವ್"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ಮರುಸ್ಥಾಪಿಸಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 763cda738541..ad0368a57460 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"선택"</string>
<string name="screenshot_text" msgid="1477704010087786671">"스크린샷"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"브라우저에서 열기"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"앱에서 열기"</string>
<string name="new_window_text" msgid="6318648868380652280">"새 창"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"창 관리"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"가로세로 비율 변경"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"메뉴 열기"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"화면 최대화"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"화면 분할"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"앱을 여기로 이동할 수 없음"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"몰입형"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"복원"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index bffc3b1d11a8..0b4eb934ff99 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Тандоо"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Серепчиден ачуу"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Колдонмодо ачуу"</string>
<string name="new_window_text" msgid="6318648868380652280">"Жаңы терезе"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Терезелерди тескөө"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Тараптардын катнашын өзгөртүү"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Менюну ачуу"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды чоңойтуу"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды сүрөткө тартып алуу"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Колдонмону бул жерге жылдырууга болбойт"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Сүңгүтүүчү"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Калыбына келтирүү"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index b48b07067521..9710e69a0418 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ເລືອກ"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ຮູບໜ້າຈໍ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ເປີດໃນໂປຣແກຣມທ່ອງເວັບ"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ເປີດຢູ່ໃນແອັບ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ໜ້າຈໍໃໝ່"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ຈັດການໜ້າຈໍ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ປ່ຽນອັດຕາສ່ວນຮູບ"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ເປີດເມນູ"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ສະແນັບໜ້າຈໍ"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ບໍ່ສາມາດຍ້າຍແອັບມາບ່ອນນີ້ໄດ້"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ສົມຈິງ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ກູ້ຄືນ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index d7a907cdc105..5bfb8e34fd53 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Pasirinkti"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Ekrano kopija"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Atidaryti naršyklėje"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Atidaryti programoje"</string>
<string name="new_window_text" msgid="6318648868380652280">"Naujas langas"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Tvarkyti langus"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Keisti kraštinių santykį"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Atidaryti meniu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Sutraukti ekraną"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Programos negalima perkelti čia"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Įtraukiantis"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Atkurti"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 4ba7c2346a33..07342000ca66 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Atlasīt"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Ekrānuzņēmums"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Atvērt pārlūkā"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Atvērt lietotnē"</string>
<string name="new_window_text" msgid="6318648868380652280">"Jauns logs"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pārvaldīt logus"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mainīt malu attiecību"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Atvērt izvēlni"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizēt ekrānu"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fiksēt ekrānu"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Lietotni nevar pārvietot šeit."</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Iekļaujoši"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Atjaunot"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index d20eba55eac9..2c4503c23e80 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Изберете"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Слика од екранот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Отвори во прелистувач"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Отвори во апликацијата"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нов прозорец"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управувајте со прозорци"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени го соодносот"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отвори го менито"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Максимизирај го екранот"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Подели го екранот на половина"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликацијата не може да се премести овде"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Реалистично"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Врати"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 81c5094526c1..7e20ee1fc36b 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"തിരഞ്ഞെടുക്കുക"</string>
<string name="screenshot_text" msgid="1477704010087786671">"സ്ക്രീൻഷോട്ട്"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ബ്രൗസറിൽ തുറക്കുക"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ആപ്പിൽ തുറക്കുക"</string>
<string name="new_window_text" msgid="6318648868380652280">"പുതിയ വിന്‍ഡോ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"വിൻഡോകൾ മാനേജ് ചെയ്യുക"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"വീക്ഷണ അനുപാതം മാറ്റുക"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"മെനു തുറക്കുക"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്‌ക്രീൻ വലുതാക്കുക"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"സ്‌ക്രീൻ സ്‌നാപ്പ് ചെയ്യുക"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ആപ്പ് ഇവിടേക്ക് നീക്കാനാകില്ല"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ഇമേഴ്‌സീവ്"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"പുനഃസ്ഥാപിക്കുക"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 35da93e774b5..ef24222cdef1 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Сонгох"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Дэлгэцийн агшин"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Хөтчид нээх"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Аппад нээх"</string>
<string name="new_window_text" msgid="6318648868380652280">"Шинэ цонх"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Windows-г удирдах"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Харьцааг өөрчлөх"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Цэсийг нээх"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Дэлгэцийг томруулах"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Дэлгэцийг таллах"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Аппыг ийш зөөх боломжгүй"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Бодит мэт"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Сэргээх"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index c6b874a6780b..e665639ca217 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"निवडा"</string>
<string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ब्राउझरमध्ये उघडा"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"अ‍ॅपमध्ये उघडा"</string>
<string name="new_window_text" msgid="6318648868380652280">"नवीन विंडो"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"विंडो व्यवस्थापित करा"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"आस्पेक्ट रेशो बदला"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेनू उघडा"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रीन स्नॅप करा"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"अ‍ॅप इथे हलवू शकत नाही"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिव्ह"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"रिस्टोअर करा"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 0fce0e9da45f..5de79c2c9afc 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Pilih"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Tangkapan skrin"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Buka dalam penyemak imbas"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Buka pada Apl"</string>
<string name="new_window_text" msgid="6318648868380652280">"Tetingkap Baharu"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Urus Tetingkap"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tukar nisbah bidang"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buka Menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tangkap Skrin"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apl tidak boleh dialihkan ke sini"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Mengasyikkan"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Pulihkan"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index abc2a19ba989..e6d355379f9a 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ရွေးရန်"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ဘရောင်ဇာတွင် ဖွင့်ရန်"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"အက်ပ်တွင် ဖွင့်ရန်"</string>
<string name="new_window_text" msgid="6318648868380652280">"ဝင်းဒိုးအသစ်"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ဝင်းဒိုးများ စီမံရန်"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"အချိုးအစား ပြောင်းရန်"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"မီနူး ဖွင့်ရန်"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"စခရင်ကို ချဲ့မည်"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"စခရင်ကို ချုံ့မည်"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"အက်ပ်ကို ဤနေရာသို့ ရွှေ့၍မရပါ"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"သုံးဘက်မြင်"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ပြန်ပြောင်းရန်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index ed6fb900564f..bde7ec67d0cb 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Velg"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Skjermbilde"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Åpne i nettleseren"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Åpne i appen"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nytt vindu"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduene"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Endre høyde/bredde-forholdet"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Åpne menyen"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimer skjermen"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fest skjermen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Appen kan ikke flyttes hit"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Oppslukende"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Gjenopprett"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index aff712901ff6..a40e3adede16 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"चयन गर्नुहोस्"</string>
<string name="screenshot_text" msgid="1477704010087786671">"स्क्रिनसट"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ब्राउजरमा खोल्नुहोस्"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"एपमा खोल्नुहोस्"</string>
<string name="new_window_text" msgid="6318648868380652280">"नयाँ विन्डो"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"विन्डोहरू व्यवस्थापन गर्नुहोस्"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेनु खोल्नुहोस्"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रिन स्न्याप गर्नुहोस्"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"एप सारेर यहाँ ल्याउन सकिएन"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिभ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"रिस्टोर गर्नुहोस्"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 8db3a0ecfc2f..b28b69080051 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Selecteren"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Openen in browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Openen in app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nieuw venster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Vensters beheren"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Beeldverhouding wijzigen"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menu openen"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Scherm halveren"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Kan de app niet hierheen verplaatsen"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersief"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Herstellen"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 69540898161c..842e3def41f1 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ଚୟନ କରନ୍ତୁ"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ସ୍କ୍ରିନସଟ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ବ୍ରାଉଜରରେ ଖୋଲନ୍ତୁ"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ଆପରେ ଖୋଲନ୍ତୁ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ନୂଆ ୱିଣ୍ଡୋ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ୱିଣ୍ଡୋଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ମେନୁ ଖୋଲନ୍ତୁ"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ସ୍କ୍ରିନକୁ ସ୍ନାପ କରନ୍ତୁ"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ଆପକୁ ଏଠାକୁ ମୁଭ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ଇମର୍ସିଭ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index c627d7fcc2c5..e1c804a56289 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ਚੁਣੋ"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੋਲ੍ਹੋ"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ਐਪ ਵਿੱਚ ਖੋਲ੍ਹੋ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ਨਵੀਂ ਵਿੰਡੋ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ਵਿੰਡੋਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ਆਕਾਰ ਅਨੁਪਾਤ ਬਦਲੋ"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ਸਕ੍ਰੀਨ ਦਾ ਆਕਾਰ ਵਧਾਓ"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ਸਕ੍ਰੀਨ ਨੂੰ ਸਨੈਪ ਕਰੋ"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ਐਪ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਲਿਜਾਇਆ ਜਾ ਸਕਦਾ"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ਇਮਰਸਿਵ"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ਮੁੜ-ਬਹਾਲ ਕਰੋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index a138c08d319a..e82916b89033 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Wybierz"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Zrzut ekranu"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otwórz w przeglądarce"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Otwórz w aplikacji"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nowe okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Zarządzaj oknami"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmień format obrazu"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otwórz menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Przyciągnij ekran"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Nie można przenieść aplikacji tutaj"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Tryb immersyjny"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Przywróć"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 9942f6980306..6d8c9ce2a72f 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Selecionar"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Abrir no app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gerenciar janelas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imersivo"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 559eea2d3cab..e0e91e715ed0 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Selecionar"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captura de ecrã"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Abrir na app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Faça a gestão das janelas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Alterar formato"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar ecrã"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover a app para aqui"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Envolvente"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 9942f6980306..6d8c9ce2a72f 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Selecionar"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Abrir no app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gerenciar janelas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imersivo"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index df0ee45695b2..5a381556207e 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Selectează"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Captură de ecran"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Deschide în browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Deschide în aplicație"</string>
<string name="new_window_text" msgid="6318648868380652280">"Fereastră nouă"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestionează ferestrele"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Schimbă raportul de dimensiuni"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Deschide meniul"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizează fereastra"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Micșorează fereastra și fixeaz-o"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplicația nu poate fi mutată aici"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Captivant"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restabilește"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 430f1b1448da..d26eb532be28 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Выбрать"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Открыть в браузере"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Открыть в приложении"</string>
<string name="new_window_text" msgid="6318648868380652280">"Новое окно"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управление окнами"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Изменить соотношение сторон"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Открыть меню"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Развернуть на весь экран"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Свернуть"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложение нельзя сюда переместить"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Погружение"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Восстановить"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 3e3766768a7f..5bfa4c91bc6c 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"තෝරන්න"</string>
<string name="screenshot_text" msgid="1477704010087786671">"තිර රුව"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"බ්‍රව්සරයේ විවෘත කරන්න"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"යෙදුම තුළ විවෘත කරන්න"</string>
<string name="new_window_text" msgid="6318648868380652280">"නව කවුළුව"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"කවුළු කළමනාකරණය කරන්න"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"දර්ශන අනුපාතය වෙනස් කරන්න"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"මෙනුව විවෘත කරන්න"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"තිරය උපරිම කරන්න"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ස්නැප් තිරය"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"යෙදුම මෙතැනට ගෙන යා නොහැක"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ගිලෙන සුළු"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ප්‍රතිසාධනය කරන්න"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 56a7edd08b23..cd20df5e1a1c 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Vybrať"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Snímka obrazovky"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvoriť v prehliadači"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Otvoriť v aplikácii"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nové okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Správa okien"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmeniť pomer strán"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvoriť ponuku"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovať obrazovku"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zobraziť polovicu obrazovky"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikácia sa sem nedá presunúť"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Pútavé"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnoviť"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index b6344c981fc9..063e47c80d5f 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Izberi"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Posnetek zaslona"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Odpri v brskalniku"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Odpiranje v aplikaciji"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novo okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje oken"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Sprememba razmerja stranic"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Odpri meni"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Pripni zaslon"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacije ni mogoče premakniti sem"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Poglobljeno"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnovi"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index ab7499d505f8..f2fb7da44807 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Zgjidh"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Pamja e ekranit"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Hape në shfletues"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Hap në aplikacion"</string>
<string name="new_window_text" msgid="6318648868380652280">"Dritare e re"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Menaxho dritaret"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ndrysho raportin e pamjes"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Hap menynë"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizo ekranin"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Regjistro ekranin"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacioni nuk mund të zhvendoset këtu"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Përfshirës"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restauro"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 773ed16dc4b9..f74e460226b6 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Изаберите"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Снимак екрана"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Отворите у прегледачу"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Отворите у апликацији"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нови прозор"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управљајте прозорима"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промените размеру"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отворите мени"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Повећај екран"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Уклопи екран"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликација не може да се премести овде"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Имерзивне"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Врати"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 6f6a97b4495f..7a5549eb5f59 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Välj"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Skärmbild"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Öppna i webbläsaren"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Öppna i appen"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nytt fönster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Hantera fönster"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ändra bildformat"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Öppna menyn"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximera skärmen"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fäst skärmen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Det går inte att flytta appen hit"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Uppslukande"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Återställ"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 72b7384fa83a..128ba74fd80c 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Chagua"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Picha ya skrini"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Fungua katika kivinjari"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Fungua kwenye Programu"</string>
<string name="new_window_text" msgid="6318648868380652280">"Dirisha Jipya"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Dhibiti Windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Badilisha uwiano"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Fungua Menyu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Panua Dirisha kwenye Skrini"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Panga Madirisha kwenye Skrini"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Imeshindwa kuhamishia programu hapa"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Shirikishi"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Rejesha"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 9d902912b377..668efd5ebf82 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"தேர்ந்தெடுக்கும்"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ஸ்கிரீன்ஷாட்"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"உலாவியில் திறக்கும்"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ஆப்ஸில் திறக்கும்"</string>
<string name="new_window_text" msgid="6318648868380652280">"புதிய சாளரம்"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"சாளரங்களை நிர்வகிக்கலாம்"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"தோற்ற விகிதத்தை மாற்று"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"மெனுவைத் திறக்கும்"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"திரையைப் பெரிதாக்கு"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"திரையை ஸ்னாப் செய்"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ஆப்ஸை இங்கே நகர்த்த முடியாது"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ஈடுபட வைக்கும்"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"மீட்டெடுக்கும்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 3c7c06a4fc1a..a3827bb3703a 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -102,7 +102,7 @@
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"యాప్ మెనూ నుండి ఏ సమయంలోనైనా ఫుల్ స్క్రీన్‌కు తిరిగి రండి"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"చూసి, మరిన్ని చేయండి"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్‌లోకి లాగండి"</string>
- <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"యాప్ స్థానాన్ని మార్చడానికి దాని వెలుపల డబుల్-ట్యాప్ చేయండి"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"యాప్ లొకేషన్‌ను మార్చడానికి దాని వెలుపల డబుల్-ట్యాప్ చేయండి"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"మరింత సమాచారం కోసం విస్తరించండి."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"మెరుగైన వీక్షణ కోసం రీస్టార్ట్ చేయాలా?"</string>
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"ఎంచుకోండి"</string>
<string name="screenshot_text" msgid="1477704010087786671">"స్క్రీన్‌షాట్"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"బ్రౌజర్‌లో తెరవండి"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"యాప్‌లో తెరవండి"</string>
<string name="new_window_text" msgid="6318648868380652280">"కొత్త విండో"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"విండోలను మేనేజ్ చేయండి"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ఆకార నిష్పత్తిని మార్చండి"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"మెనూను తెరవండి"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"స్క్రీన్ సైజ్‌ను పెంచండి"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"స్క్రీన్‌ను స్నాప్ చేయండి"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"యాప్‌ను ఇక్కడకి తరలించడం సాధ్యం కాదు"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"లీనమయ్యే"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"రీస్టోర్ చేయండి"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 9071bfb66e92..fe7556156e78 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"เลือก"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ภาพหน้าจอ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"เปิดในเบราว์เซอร์"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"เปิดในแอป"</string>
<string name="new_window_text" msgid="6318648868380652280">"หน้าต่างใหม่"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"จัดการหน้าต่าง"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"เปลี่ยนสัดส่วนการแสดงผล"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"เปิดเมนู"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"สแนปหน้าจอ"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ย้ายแอปมาที่นี่ไม่ได้"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"สมจริง"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"คืนค่า"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index a00f7839186b..d9fb13bb0b6f 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Piliin"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Buksan sa browser"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Buksan sa App"</string>
<string name="new_window_text" msgid="6318648868380652280">"Bagong Window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pamahalaan ang Mga Window"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Baguhin ang aspect ratio"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buksan ang Menu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"I-snap ang Screen"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Hindi mailipat dito ang app"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"I-restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 8310a66e9d33..e6d900af0cf8 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Seç"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Ekran görüntüsü"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Tarayıcıda aç"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Uygulamada Aç"</string>
<string name="new_window_text" msgid="6318648868380652280">"Yeni Pencere"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pencereleri yönet"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"En boy oranını değiştir"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menüyü aç"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı Büyüt"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranın Yarısına Tuttur"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Uygulama buraya taşınamıyor"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Etkileyici"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Geri yükle"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 624a19e67724..ea599952a0e7 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Вибрати"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Знімок екрана"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Відкрити у вебпереглядачі"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Відкрити в додатку"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нове вікно"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Керувати вікнами"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змінити формат"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Відкрити меню"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Розгорнути екран"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Зафіксувати екран"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Сюди не можна перемістити додаток"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Реалістичність"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Відновити"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 2ccaf50fee21..6749629f2c3e 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"منتخب کریں"</string>
<string name="screenshot_text" msgid="1477704010087786671">"اسکرین شاٹ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"براؤزر میں کھولیں"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"ایپ میں کھولیں"</string>
<string name="new_window_text" msgid="6318648868380652280">"نئی ونڈو"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"‏‫Windows کا نظم کریں"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تناسبی شرح کو تبدیل کریں"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"مینو کھولیں"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"اسکرین کو بڑا کریں"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"اسکرین کا اسناپ شاٹ لیں"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ایپ کو یہاں منتقل نہیں کیا جا سکتا"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"عمیق"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"بحال کریں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 88edc929528b..3417fef84de5 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Tanlash"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Skrinshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Brauzerda ochish"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Ilovada ochish"</string>
<string name="new_window_text" msgid="6318648868380652280">"Yangi oyna"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Oynalarni boshqarish"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tomonlar nisbatini oʻzgartirish"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menyuni ochish"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranni yoyish"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranni biriktirish"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ilova bu yerga surilmaydi"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiv"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Tiklash"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index c1c7653ce90c..559bff8711bf 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Chọn"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Ảnh chụp màn hình"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Mở trong trình duyệt"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Mở trong Ứng dụng"</string>
<string name="new_window_text" msgid="6318648868380652280">"Cửa sổ mới"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Quản lý cửa sổ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Thay đổi tỷ lệ khung hình"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Mở Trình đơn"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mở rộng màn hình"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Điều chỉnh kích thước màn hình"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Không di chuyển được ứng dụng đến đây"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Hiển thị tối đa"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Khôi phục"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 83e15d8cbdf6..f327653bd5d9 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"选择"</string>
<string name="screenshot_text" msgid="1477704010087786671">"屏幕截图"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"在浏览器中打开"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"在应用内打开"</string>
<string name="new_window_text" msgid="6318648868380652280">"新窗口"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"管理窗口"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"更改宽高比"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"打开菜单"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"屏幕快照"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"无法将应用移至此处"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"沉浸式"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"恢复"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index f60b3efc6f38..e1ecd44eb69f 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"選取"</string>
<string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"在瀏覽器中開啟"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"在應用程式中開啟"</string>
<string name="new_window_text" msgid="6318648868380652280">"新視窗"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"管理視窗"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更長寬比"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"打開選單"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至這裡"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"身歷其境"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"還原"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index b2227deeccc3..1b8f704cef29 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"選取"</string>
<string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"在瀏覽器中開啟"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"在應用程式中開啟"</string>
<string name="new_window_text" msgid="6318648868380652280">"新視窗"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"管理視窗"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更顯示比例"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"開啟選單"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至此處"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"沉浸"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"還原"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 10d904fa17d2..604031733ed2 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -125,6 +125,7 @@
<string name="select_text" msgid="5139083974039906583">"Khetha"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Isithombe-skrini"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Vula kubhrawuza"</string>
+ <string name="open_in_app_text" msgid="2874590745116268525">"Vula Ku-app"</string>
<string name="new_window_text" msgid="6318648868380652280">"Iwindi Elisha"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Phatha Amawindi"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Shintsha ukubukeka kwesilinganiselo"</string>
@@ -132,7 +133,8 @@
<string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Vula Imenyu"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Khulisa Isikrini Sifike Ekugcineni"</string>
- <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Thwebula Isikrini"</string>
+ <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
+ <skip />
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"I-app ayikwazi ukuhanjiswa lapha"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Okugxilile"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Buyisela"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 249e9a26e6a6..21ec84d9bc0a 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -504,17 +504,15 @@
<dimen name="desktop_mode_maximize_menu_buttons_fill_radius">4dp</dimen>
<!-- The padding between the outline and fill of the maximize menu snap and maximize buttons. -->
<dimen name="desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding">4dp</dimen>
- <!-- The padding between the outline and fill of the maximize menu snap and maximize buttons. -->
- <dimen name="desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding_bottom">8dp</dimen>
<!-- The vertical padding between the outline and fill of the maximize menu restore button. -->
<dimen name="desktop_mode_maximize_menu_restore_button_fill_vertical_padding">13dp</dimen>
<!-- The horizontal padding between the outline and fill of the maximize menu restore button. -->
- <dimen name="desktop_mode_maximize_menu_restore_button_fill_horizontal_padding">21dp</dimen>
+ <dimen name="desktop_mode_maximize_menu_restore_button_fill_horizontal_padding">15dp</dimen>
<!-- The padding between the outline and fill of the maximize menu immersive button. -->
- <dimen name="desktop_mode_maximize_menu_immersive_button_fill_padding">4dp</dimen>
+ <dimen name="desktop_mode_maximize_menu_immersive_button_fill_padding">0dp</dimen>
<!-- The corner radius of the maximize menu. -->
- <dimen name="desktop_mode_maximize_menu_corner_radius">8dp</dimen>
+ <dimen name="desktop_mode_maximize_menu_corner_radius">16dp</dimen>
<!-- The radius of the Maximize menu shadow. -->
<dimen name="desktop_mode_maximize_menu_shadow_radius">8dp</dimen>
@@ -661,4 +659,7 @@
<dimen name="desktop_windowing_education_promo_height">352dp</dimen>
<!-- The corner radius of the desktop windowing education promo. -->
<dimen name="desktop_windowing_education_promo_corner_radius">28dp</dimen>
+
+ <!-- The corner radius of freeform tasks in desktop windowing. -->
+ <dimen name="desktop_windowing_freeform_rounded_corner_radius">16dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 012579a6d40c..468c345259d0 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -318,7 +318,7 @@
<!-- Maximize menu maximize button string. -->
<string name="desktop_mode_maximize_menu_maximize_text">Maximize Screen</string>
<!-- Maximize menu snap buttons string. -->
- <string name="desktop_mode_maximize_menu_snap_text">Snap Screen</string>
+ <string name="desktop_mode_maximize_menu_snap_text">Resize</string>
<!-- Snap resizing non-resizable string. -->
<string name="desktop_mode_non_resizable_snap_text">App can\'t be moved here</string>
<!-- Accessibility text for the Maximize Menu's immersive button [CHAR LIMIT=NONE] -->
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index 55cda783005f..597a921302b7 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -29,6 +29,7 @@
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowAnimationStyle">@null</item>
+ <item name="android:windowIsTranslucent">true</item>
</style>
<style name="Animation.ForcedResizable" parent="@android:style/Animation">
diff --git a/libs/WindowManager/Shell/shared/Android.bp b/libs/WindowManager/Shell/shared/Android.bp
new file mode 100644
index 000000000000..5113d980fb7d
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/Android.bp
@@ -0,0 +1,78 @@
+// Copyright (C) 2024 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 {
+ // 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"],
+ default_team: "trendy_team_multitasking_windowing",
+}
+
+filegroup {
+ name: "wm_shell-shared-utils",
+ srcs: [
+ "src/com/android/wm/shell/shared/TransitionUtil.java",
+ ],
+}
+
+filegroup {
+ name: "wm_shell-shared-aidls",
+
+ srcs: [
+ "**/*.aidl",
+ ],
+
+ path: "src",
+}
+
+// NOTE: This shared lib is built with various apps and should not
+// contain resources that can be overlaid, as they would need
+// to be overlaid in each app individually.
+android_library {
+ name: "WindowManager-Shell-shared",
+
+ resource_dirs: [
+ "res",
+ ],
+ srcs: [
+ "**/*.java",
+ "**/*.kt",
+ ":wm_shell-shared-aidls",
+ ],
+ static_libs: [
+ "androidx.core_core-animation",
+ "androidx.dynamicanimation_dynamicanimation",
+ "jsr330",
+ ],
+ kotlincflags: ["-Xjvm-default=all"],
+ use_resource_processor: true,
+}
+
+// NOTE: This shared lib is built with various apps and should not
+// contain resources that can be overlaid, as they would need
+// to be overlaid in each app individually.
+java_library {
+ name: "WindowManager-Shell-shared-desktopMode",
+
+ srcs: [
+ "**/desktopmode/*.java",
+ "**/desktopmode/*.kt",
+ ],
+ static_libs: [
+ "com.android.window.flags.window-aconfig-java",
+ ],
+}
diff --git a/packages/BackupRestoreConfirmation/res/values/styles.xml b/libs/WindowManager/Shell/shared/AndroidManifest.xml
index ce54568ed6d6..5a4af5163fbe 100644
--- a/packages/BackupRestoreConfirmation/res/values/styles.xml
+++ b/libs/WindowManager/Shell/shared/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2024 The Android Open Source Project
+<!--
+ Copyright (C) 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,12 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <!--
- TODO(b/309578419): Make activities handle insets properly and then remove this.
- -->
- <style name="OptOutEdgeToEdgeEnforcement">
- <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
- </style>
-</resources>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.shared">
+</manifest>
diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml b/libs/WindowManager/Shell/shared/res/values/config.xml
index 17c0222ef69e..a1d81cea093a 100644
--- a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml
+++ b/libs/WindowManager/Shell/shared/res/values/config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2024 The Android Open Source Project
@@ -13,14 +14,5 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/hearing_devices_preset_option_text"
- style="?android:attr/spinnerDropDownItemStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/hearing_devices_preset_spinner_height"
- android:paddingStart="@dimen/hearing_devices_preset_spinner_text_padding_start"
- android:gravity="center_vertical"
- android:textDirection="locale"
- android:ellipsize="end" /> \ No newline at end of file
+<resources>
+</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
index 03e0ab0591a1..4300e84e8044 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
@@ -168,6 +168,16 @@ public class GroupedTaskInfo implements Parcelable {
}
/**
+ * @return The task info for the task in this group with the given {@code taskId}.
+ */
+ @Nullable
+ public TaskInfo getTaskById(int taskId) {
+ return mTasks.stream()
+ .filter(task -> task.taskId == taskId)
+ .findFirst().orElse(null);
+ }
+
+ /**
* Get all {@link RecentTaskInfo}s grouped together.
*/
@NonNull
@@ -176,6 +186,14 @@ public class GroupedTaskInfo implements Parcelable {
}
/**
+ * @return Whether this grouped task contains a task with the given {@code taskId}.
+ */
+ public boolean containsTask(int taskId) {
+ return mTasks.stream()
+ .anyMatch((task -> task.taskId == taskId));
+ }
+
+ /**
* Return {@link SplitBounds} if this is a split screen entry or {@code null}
*/
@Nullable
@@ -249,9 +267,10 @@ public class GroupedTaskInfo implements Parcelable {
return null;
}
return "id=" + taskInfo.taskId
- + " baseIntent=" + (taskInfo.baseIntent != null
- ? taskInfo.baseIntent.getComponent()
- : "null")
+ + " baseIntent=" +
+ (taskInfo.baseIntent != null && taskInfo.baseIntent.getComponent() != null
+ ? taskInfo.baseIntent.getComponent().flattenToString()
+ : "null")
+ " winMode=" + WindowConfiguration.windowingModeToString(
taskInfo.getWindowingMode());
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 6bc995f14d44..04c17e54d11f 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -191,6 +191,23 @@ public class DesktopModeStatus {
}
/**
+ * @return {@code true} if this device is requesting to show the app handle despite non
+ * necessarily enabling desktop mode
+ */
+ public static boolean overridesShowAppHandle(@NonNull Context context) {
+ return Flags.showAppHandleLargeScreens()
+ && context.getResources().getBoolean(R.bool.config_enableAppHandle);
+ }
+
+ /**
+ * @return {@code true} if the app handle should be shown because desktop mode is enabled or
+ * the device is overriding {@code R.bool.config_enableAppHandle}
+ */
+ public static boolean canEnterDesktopModeOrShowAppHandle(@NonNull Context context) {
+ return canEnterDesktopMode(context) || overridesShowAppHandle(context);
+ }
+
+ /**
* Return {@code true} if the override desktop density is enabled and valid.
*/
public static boolean useDesktopOverrideDensity() {
@@ -264,5 +281,8 @@ public class DesktopModeStatus {
SystemProperties.Handle maxTaskLimitHandle = SystemProperties.find(MAX_TASK_LIMIT_SYS_PROP);
pw.print(innerPrefix); pw.print("maxTaskLimit sysprop=");
pw.println(maxTaskLimitHandle == null ? "null" : maxTaskLimitHandle.getInt(/* def= */ -1));
+
+ pw.print(innerPrefix); pw.print("showAppHandle config override=");
+ pw.print(context.getResources().getBoolean(R.bool.config_enableAppHandle));
}
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
index 23e7441ff86b..f14dfdbc7d30 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
@@ -50,6 +50,22 @@ abstract class ManageWindowsViewContainer(
fun createMenu(snapshotList: List<Pair<Int, TaskSnapshot>>,
onIconClickListener: ((Int) -> Unit),
onOutsideClickListener: (() -> Unit)): ManageWindowsView {
+ val bitmapList = snapshotList.map { (index, snapshot) ->
+ index to Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace)
+ }
+ return createAndShowMenuView(
+ bitmapList,
+ onIconClickListener,
+ onOutsideClickListener
+ )
+ }
+
+ /** Creates the menu view with the given bitmaps, and displays it. */
+ fun createAndShowMenuView(
+ snapshotList: List<Pair<Int, Bitmap?>>,
+ onIconClickListener: ((Int) -> Unit),
+ onOutsideClickListener: (() -> Unit)
+ ): ManageWindowsView {
menuView = ManageWindowsView(context, menuBackgroundColor).apply {
this.onOutsideClickListener = onOutsideClickListener
this.onIconClickListener = onIconClickListener
@@ -120,7 +136,7 @@ abstract class ManageWindowsViewContainer(
}
fun generateIconViews(
- snapshotList: List<Pair<Int, TaskSnapshot>>
+ snapshotList: List<Pair<Int, Bitmap?>>
) {
menuWidth = 0
menuHeight = 0
@@ -133,7 +149,7 @@ abstract class ManageWindowsViewContainer(
// Add each icon to the menu, adding a new row when needed.
for ((iconCount, taskInfoSnapshotPair) in snapshotList.withIndex()) {
val taskId = taskInfoSnapshotPair.first
- val snapshot = taskInfoSnapshotPair.second
+ val snapshotBitmap = taskInfoSnapshotPair.second
// Once a row is filled, make a new row and increase the menu height.
if (iconCount % MENU_MAX_ICONS_PER_ROW == 0) {
rowLayout = LinearLayout(context)
@@ -141,10 +157,7 @@ abstract class ManageWindowsViewContainer(
rootView.addView(rowLayout)
menuHeight += (instanceIconHeight + iconMargin).toInt()
}
- val snapshotBitmap = Bitmap.wrapHardwareBuffer(
- snapshot.hardwareBuffer,
- snapshot.colorSpace
- )
+
val croppedBitmap = snapshotBitmap?.let { cropBitmap(it) }
val scaledSnapshotBitmap = croppedBitmap?.let {
Bitmap.createScaledBitmap(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index ce7a97703f44..e9cfd9bc2209 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -37,6 +37,7 @@ import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_B
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.TaskInfo;
@@ -73,10 +74,12 @@ import android.window.BackMotionEvent;
import android.window.BackNavigationInfo;
import android.window.BackTouchTracker;
import android.window.IBackAnimationFinishedCallback;
+import android.window.IBackAnimationHandoffHandler;
import android.window.IBackAnimationRunner;
import android.window.IOnBackInvokedCallback;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowAnimationState;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -84,6 +87,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
+import com.android.systemui.animation.TransitionAnimator;
+import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
@@ -227,6 +232,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private Runnable mPilferPointerCallback;
private BackAnimation.TopUiRequest mRequestTopUiCallback;
+ private final IBackAnimationHandoffHandler mHandoffHandler =
+ new IBackAnimationHandoffHandler.Stub() {
+ @Override
+ public void handOffAnimation(
+ RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
+ mBackTransitionHandler.handOffAnimation(targets, states);
+ }
+ };
+
public BackAnimationController(
@NonNull ShellInit shellInit,
@NonNull ShellController shellController,
@@ -282,7 +296,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mShellCommandHandler = shellCommandHandler;
mWindowManager = context.getSystemService(WindowManager.class);
mTransitions = transitions;
- mBackTransitionHandler = new BackTransitionHandler();
+ mBackTransitionHandler = new BackTransitionHandler(mTransitions);
mTransitions.addHandler(mBackTransitionHandler);
mHandler = handler;
mTransitions.registerObserver(mBackTransitionObserver);
@@ -715,6 +729,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
try {
callback.onBackStarted(backEvent);
+ if (mBackTransitionHandler.canHandOffAnimation()) {
+ callback.setHandoffHandler(mHandoffHandler);
+ }
mOnBackStartDispatched = true;
} catch (RemoteException e) {
Log.e(TAG, "dispatchOnBackStarted error: ", e);
@@ -1192,6 +1209,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
class BackTransitionHandler implements Transitions.TransitionHandler {
+ private final Transitions mTransitions;
Runnable mOnAnimationFinishCallback;
boolean mCloseTransitionRequested;
@@ -1203,6 +1221,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
// animation is canceled, start a close prepare transition to finish the whole transition.
IBinder mClosePrepareTransition;
TransitionInfo mOpenTransitionInfo;
+ Transitions.TransitionHandler mTakeoverHandler;
+
+ BackTransitionHandler(Transitions transitions) {
+ mTransitions = transitions;
+ }
+
void onAnimationFinished() {
if (!mCloseTransitionRequested && mPrepareOpenTransition != null) {
createClosePrepareTransition();
@@ -1214,18 +1238,23 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
private void applyFinishOpenTransition() {
- mOpenTransitionInfo = null;
- mPrepareOpenTransition = null;
if (mFinishOpenTransaction != null) {
final SurfaceControl.Transaction t = mFinishOpenTransaction;
- mFinishOpenTransaction = null;
t.apply();
}
if (mFinishOpenTransitionCallback != null) {
final Transitions.TransitionFinishCallback callback = mFinishOpenTransitionCallback;
- mFinishOpenTransitionCallback = null;
callback.onTransitionFinished(null);
}
+ cleanUpInternalState();
+ }
+
+ private void cleanUpInternalState() {
+ mOpenTransitionInfo = null;
+ mPrepareOpenTransition = null;
+ mFinishOpenTransaction = null;
+ mFinishOpenTransitionCallback = null;
+ mTakeoverHandler = null;
}
private void applyAndFinish(@NonNull SurfaceControl.Transaction st,
@@ -1237,6 +1266,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
finishCallback.onTransitionFinished(null);
mCloseTransitionRequested = false;
}
+
@Override
public boolean startAnimation(@NonNull IBinder transition,
@NonNull TransitionInfo info,
@@ -1246,6 +1276,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
final boolean isPrepareTransition =
info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
if (isPrepareTransition) {
+ if (checkTakeoverFlags()) {
+ mTakeoverHandler = mTransitions.getHandlerForTakeover(transition, info);
+ }
kickStartAnimation();
}
// Both mShellExecutor and Transitions#mMainExecutor are ShellMainThread, so we don't
@@ -1288,6 +1321,57 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return handleCloseTransition(info, st, ft, finishCallback);
}
+ private boolean canHandOffAnimation() {
+ if (!checkTakeoverFlags()) {
+ return false;
+ }
+
+ return mTakeoverHandler != null;
+ }
+
+ private void handOffAnimation(
+ RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
+ if (!checkTakeoverFlags()) {
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+ "Trying to hand off the animation, but the required flags are disabled.");
+ return;
+ } else if (mTakeoverHandler == null) {
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+ "Missing takeover handler when trying to hand off animation.");
+ return;
+ } else if (targets.length != states.length) {
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+ "Targets passed for takeover don't match the window states.");
+ return;
+ }
+
+ // The states passed to this method are paired with the targets, but they need to be
+ // paired with the changes inside the TransitionInfo. So for each change we find its
+ // matching target, and leave the state for any change missing a matching target blank.
+ WindowAnimationState[] updatedStates =
+ new WindowAnimationState[mOpenTransitionInfo.getChanges().size()];
+ for (int i = 0; i < mOpenTransitionInfo.getChanges().size(); i++) {
+ ActivityManager.RunningTaskInfo taskInfo =
+ mOpenTransitionInfo.getChanges().get(i).getTaskInfo();
+ if (taskInfo == null) {
+ continue;
+ }
+
+ for (int j = 0; j < targets.length; j++) {
+ if (taskInfo.taskId == targets[j].taskId) {
+ updatedStates[i] = states[j];
+ break;
+ }
+ }
+ }
+
+ mTakeoverHandler.takeOverAnimation(
+ mPrepareOpenTransition, mOpenTransitionInfo, new SurfaceControl.Transaction(),
+ mFinishOpenTransitionCallback, updatedStates);
+
+ cleanUpInternalState();
+ }
+
@Override
public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
@Nullable SurfaceControl.Transaction finishTransaction) {
@@ -1673,6 +1757,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
return null;
}
+
+ private static boolean checkTakeoverFlags() {
+ return TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()
+ && Flags.unifyBackNavigationTransition();
+ }
}
private static boolean isNotGestureBackTransition(@NonNull TransitionInfo info) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index 37339307f5b0..7e5a82e640cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -39,6 +39,8 @@ import android.view.animation.DecelerateInterpolator
import android.view.animation.Interpolator
import android.view.animation.Transformation
import android.window.BackEvent
+import android.window.BackEvent.EDGE_LEFT
+import android.window.BackEvent.EDGE_RIGHT
import android.window.BackMotionEvent
import android.window.BackNavigationInfo
import android.window.BackProgressAnimator
@@ -50,6 +52,7 @@ import com.android.internal.jank.Cuj
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.policy.SystemBarUtils
import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags.predictiveBackTimestampApi
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup
@@ -118,7 +121,9 @@ abstract class CrossActivityBackAnimation(
private val postCommitFlingSpring = SpringForce(SPRING_SCALE)
.setStiffness(SpringForce.STIFFNESS_LOW)
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ private var swipeEdge = EDGE_LEFT
protected var gestureProgress = 0f
+ private val velocityTracker = ProgressVelocityTracker()
/** Background color to be used during the animation, also see [getBackgroundColor] */
protected var customizedBackgroundColor = 0
@@ -175,6 +180,7 @@ abstract class CrossActivityBackAnimation(
)
return
}
+ swipeEdge = backMotionEvent.swipeEdge
triggerBack = backMotionEvent.triggerBack
initialTouchPos.set(backMotionEvent.touchX, backMotionEvent.touchY)
@@ -241,6 +247,9 @@ abstract class CrossActivityBackAnimation(
)
applyTransaction()
background.customizeStatusBarAppearance(currentClosingRect.top.toInt())
+ if (predictiveBackTimestampApi()) {
+ velocityTracker.addPosition(backEvent.frameTimeMillis, progress)
+ }
}
private fun getYOffset(centeredRect: RectF, touchY: Float): Float {
@@ -272,10 +281,19 @@ abstract class CrossActivityBackAnimation(
// kick off spring animation with the current velocity from the pre-commit phase, this
// affects the scaling of the closing and/or opening activity during post-commit
- val startVelocity =
- if (gestureProgress < 0.1f) -DEFAULT_FLING_VELOCITY else -velocity * SPRING_SCALE
+
+ var startVelocity = if (predictiveBackTimestampApi()) {
+ // pronounce fling animation more for gestures
+ val velocityFactor = if (swipeEdge == EDGE_LEFT || swipeEdge == EDGE_RIGHT) 2f else 1f
+ velocity * SPRING_SCALE * (1f - MAX_SCALE) * velocityFactor
+ } else {
+ velocity * SPRING_SCALE
+ }
+ if (gestureProgress < 0.1f) {
+ startVelocity = startVelocity.coerceAtLeast(DEFAULT_FLING_VELOCITY)
+ }
val flingAnimation = SpringAnimation(postCommitFlingScale, SPRING_SCALE)
- .setStartVelocity(startVelocity.coerceIn(-MAX_FLING_VELOCITY, 0f))
+ .setStartVelocity(-startVelocity.coerceIn(0f, MAX_FLING_VELOCITY))
.setStartValue(SPRING_SCALE)
.setSpring(postCommitFlingSpring)
flingAnimation.start()
@@ -338,6 +356,7 @@ abstract class CrossActivityBackAnimation(
lastPostCommitFlingScale = SPRING_SCALE
gestureProgress = 0f
triggerBack = false
+ velocityTracker.resetTracking()
}
protected fun applyTransform(
@@ -520,7 +539,11 @@ abstract class CrossActivityBackAnimation(
override fun onBackInvoked() {
triggerBack = true
progressAnimator.reset()
- onGestureCommitted(progressAnimator.velocity)
+ if (predictiveBackTimestampApi()) {
+ onGestureCommitted(velocityTracker.calculateVelocity())
+ } else {
+ onGestureCommitted(progressAnimator.velocity)
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index dc50fdbd1af3..f48b3ffcd598 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.back;
-import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.window.BackEvent.EDGE_RIGHT;
@@ -43,10 +42,8 @@ import android.util.TimeUtils;
import android.view.Choreographer;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
-import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
-import android.view.VelocityTracker;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.window.BackEvent;
@@ -132,9 +129,8 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {
private final SpringForce mPostCommitFlingSpring = new SpringForce(SPRING_SCALE)
.setStiffness(FLING_SPRING_STIFFNESS)
.setDampingRatio(1f);
- private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+ private final ProgressVelocityTracker mVelocityTracker = new ProgressVelocityTracker();
private float mGestureProgress = 0f;
- private long mDownTime = 0L;
@Inject
public CrossTaskBackAnimation(Context context, BackAnimationBackground background,
@@ -316,8 +312,7 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {
mClosingCurrentRect.setEmpty();
mInitialTouchPos.set(0, 0);
mGestureProgress = 0;
- mDownTime = 0;
- mVelocityTracker.clear();
+ mVelocityTracker.resetTracking();
if (mFinishCallback != null) {
try {
@@ -333,22 +328,13 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {
private void onGestureProgress(@NonNull BackEvent backEvent) {
if (!mBackInProgress) {
mBackInProgress = true;
- mDownTime = backEvent.getFrameTimeMillis();
}
float progress = backEvent.getProgress();
mTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
float interpolatedProgress = getInterpolatedProgress(progress);
if (predictiveBackTimestampApi()) {
- mVelocityTracker.addMovement(
- MotionEvent.obtain(
- /* downTime */ mDownTime,
- /* eventTime */ backEvent.getFrameTimeMillis(),
- /* action */ ACTION_MOVE,
- /* x */ interpolatedProgress * SPRING_SCALE,
- /* y */ 0f,
- /* metaState */ 0
- )
- );
+ mVelocityTracker.addPosition(backEvent.getFrameTimeMillis(),
+ interpolatedProgress * SPRING_SCALE);
}
updateGestureBackProgress(interpolatedProgress, backEvent);
}
@@ -362,9 +348,8 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {
if (predictiveBackTimestampApi()) {
// kick off spring animation with the current velocity from the pre-commit phase, this
// affects the scaling of the closing and/or opening task during post-commit
- mVelocityTracker.computeCurrentVelocity(1000);
float startVelocity = mGestureProgress < 0.1f
- ? -DEFAULT_FLING_VELOCITY : -mVelocityTracker.getXVelocity();
+ ? -DEFAULT_FLING_VELOCITY : -mVelocityTracker.calculateVelocity();
SpringAnimation flingAnimation =
new SpringAnimation(mPostCommitFlingScale, SPRING_SCALE)
.setStartVelocity(Math.max(-MAX_FLING_VELOCITY, Math.min(0f, startVelocity)))
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt
new file mode 100644
index 000000000000..6bbda0fd7b19
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.back
+
+import android.view.MotionEvent
+import android.view.VelocityTracker
+
+internal class ProgressVelocityTracker {
+ private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
+ private var downTime = -1L
+
+ fun addPosition(timeMillis: Long, position: Float) {
+ if (downTime == -1L) downTime = timeMillis
+ velocityTracker.addMovement(
+ MotionEvent.obtain(
+ /* downTime */ downTime,
+ /* eventTime */ timeMillis,
+ /* action */ MotionEvent.ACTION_MOVE,
+ /* x */ position,
+ /* y */ 0f,
+ /* metaState */0
+ )
+ )
+ }
+
+ /** calculates current velocity (unit: progress per second) */
+ fun calculateVelocity(): Float {
+ velocityTracker.computeCurrentVelocity(1000)
+ return velocityTracker.xVelocity
+ }
+
+ fun resetTracking() {
+ velocityTracker.clear()
+ downTime = -1L
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 0fd98ed7eaf1..b82496e45415 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1295,6 +1295,14 @@ public class BubbleController implements ConfigurationChangeListener,
// We still have bubbles, if we dragged an individual bubble to dismiss we were expanded
// so re-expand to whatever is selected.
showExpandedViewForBubbleBar();
+ if (bubbleKey.equals(selectedBubbleKey)) {
+ // We dragged the selected bubble to dismiss, log switch event
+ if (mBubbleData.getSelectedBubble() instanceof Bubble) {
+ // Log only bubbles as overflow can't be dragged
+ mLogger.log((Bubble) mBubbleData.getSelectedBubble(),
+ BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED);
+ }
+ }
}
}
@@ -1319,7 +1327,11 @@ public class BubbleController implements ConfigurationChangeListener,
/** Promote the provided bubble from the overflow view. */
public void promoteBubbleFromOverflow(Bubble bubble) {
- mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
+ if (isShowingAsBubbleBar()) {
+ mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_REMOVE_BACK_TO_BAR);
+ } else {
+ mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
+ }
ProtoLog.d(WM_SHELL_BUBBLES, "promoteBubbleFromOverflow=%s", bubble.getKey());
bubble.setInflateSynchronously(mInflateSynchronously);
bubble.setShouldAutoExpand(true);
@@ -1337,10 +1349,12 @@ public class BubbleController implements ConfigurationChangeListener,
public void expandStackAndSelectBubbleFromLauncher(String key, int topOnScreen) {
mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen);
+ boolean wasExpanded = (mLayerView != null && mLayerView.isExpanded());
+
if (BubbleOverflow.KEY.equals(key)) {
mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
mLayerView.showExpandedView(mBubbleData.getOverflow());
- mLogger.log(BubbleLogger.Event.BUBBLE_BAR_EXPANDED);
+ mLogger.log(BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_SELECTED);
return;
}
@@ -1352,7 +1366,11 @@ public class BubbleController implements ConfigurationChangeListener,
// already in the stack
mBubbleData.setSelectedBubbleFromLauncher(b);
mLayerView.showExpandedView(b);
- mLogger.log(b, BubbleLogger.Event.BUBBLE_BAR_EXPANDED);
+ if (wasExpanded) {
+ mLogger.log(b, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED);
+ } else {
+ mLogger.log(b, BubbleLogger.Event.BUBBLE_BAR_EXPANDED);
+ }
} else if (mBubbleData.hasOverflowBubbleWithKey(b.getKey())) {
// TODO: (b/271468319) handle overflow
} else {
@@ -2069,8 +2087,9 @@ public class BubbleController implements ConfigurationChangeListener,
BubbleLogger.Event event = isExpanded ? BubbleLogger.Event.BUBBLE_BAR_EXPANDED
: BubbleLogger.Event.BUBBLE_BAR_COLLAPSED;
- if (mBubbleData.getSelectedBubble() instanceof Bubble bubble) {
- mLogger.log(bubble, event);
+ BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
+ if (selectedBubble instanceof Bubble) {
+ mLogger.log((Bubble) selectedBubble, event);
} else {
mLogger.log(event);
}
@@ -2081,6 +2100,10 @@ public class BubbleController implements ConfigurationChangeListener,
// Only need to update the layer view if we're currently expanded for selection changes.
if (mLayerView != null && mLayerView.isExpanded()) {
mLayerView.showExpandedView(selectedBubble);
+ if (selectedBubble instanceof Bubble) {
+ mLogger.log((Bubble) selectedBubble,
+ BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED);
+ }
}
}
};
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 4de9dfa54c5d..dc2025bb2dce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -759,7 +759,9 @@ public class BubbleData {
if (b != null) {
b.stopInflation();
}
- mLogger.logOverflowRemove(b, reason);
+ if (!mPositioner.isShowingInBubbleBar()) {
+ mLogger.logStackOverflowRemove(b, reason);
+ }
mOverflowBubbles.remove(b);
mStateChange.bubbleRemoved(b, reason);
mStateChange.removedOverflowBubble = b;
@@ -802,6 +804,27 @@ public class BubbleData {
setNewSelectedIndex(indexToRemove);
}
maybeSendDeleteIntent(reason, bubbleToRemove);
+
+ if (mPositioner.isShowingInBubbleBar()) {
+ logBubbleBarBubbleRemoved(bubbleToRemove, reason);
+ }
+ }
+
+ private void logBubbleBarBubbleRemoved(Bubble bubble, @DismissReason int reason) {
+ switch (reason) {
+ case Bubbles.DISMISS_NOTIF_CANCEL:
+ mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_CANCELED);
+ break;
+ case Bubbles.DISMISS_TASK_FINISHED:
+ mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_ACTIVITY_FINISH);
+ break;
+ case Bubbles.DISMISS_BLOCKED:
+ case Bubbles.DISMISS_NO_LONGER_BUBBLE:
+ mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED);
+ break;
+ default:
+ // skip logging other events
+ }
}
private void setNewSelectedIndex(int indexOfSelected) {
@@ -862,7 +885,7 @@ public class BubbleData {
return;
}
ProtoLog.d(WM_SHELL_BUBBLES, "overflowBubble=%s", bubble.getKey());
- mLogger.logOverflowAdd(bubble, reason);
+ mLogger.logOverflowAdd(bubble, mPositioner.isShowingInBubbleBar(), reason);
if (mOverflowBubbles.isEmpty()) {
mStateChange.showOverflowChanged = true;
}
@@ -875,7 +898,10 @@ public class BubbleData {
Bubble oldest = mOverflowBubbles.get(mOverflowBubbles.size() - 1);
ProtoLog.d(WM_SHELL_BUBBLES, "overflow full, remove=%s", oldest.getKey());
mStateChange.bubbleRemoved(oldest, Bubbles.DISMISS_OVERFLOW_MAX_REACHED);
- mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
+ if (!mPositioner.isShowingInBubbleBar()) {
+ // Only logged for bubbles in stack view
+ mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
+ }
mOverflowBubbles.remove(oldest);
mStateChange.removedOverflowBubble = oldest;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index 36630733e1da..347df330c4b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -182,10 +182,12 @@ public class BubbleLogger {
}
/**
+ * Log when a bubble is removed from overflow in stack view
+ *
* @param b Bubble removed from overflow
* @param r Reason that bubble was removed
*/
- public void logOverflowRemove(Bubble b, @Bubbles.DismissReason int r) {
+ public void logStackOverflowRemove(Bubble b, @Bubbles.DismissReason int r) {
if (r == Bubbles.DISMISS_NOTIF_CANCEL) {
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_CANCEL);
} else if (r == Bubbles.DISMISS_GROUP_CANCELLED) {
@@ -201,13 +203,19 @@ public class BubbleLogger {
* @param b Bubble added to overflow
* @param r Reason that bubble was added to overflow
*/
- public void logOverflowAdd(Bubble b, @Bubbles.DismissReason int r) {
- if (r == Bubbles.DISMISS_AGED) {
- log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
- } else if (r == Bubbles.DISMISS_USER_GESTURE) {
- log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
- } else if (r == Bubbles.DISMISS_RELOAD_FROM_DISK) {
- log(b, Event.BUBBLE_OVERFLOW_RECOVER);
+ public void logOverflowAdd(Bubble b, boolean bubbleBar, @Bubbles.DismissReason int r) {
+ if (bubbleBar) {
+ if (r == Bubbles.DISMISS_AGED) {
+ log(b, Event.BUBBLE_BAR_OVERFLOW_ADD_AGED);
+ }
+ } else {
+ if (r == Bubbles.DISMISS_AGED) {
+ log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
+ } else if (r == Bubbles.DISMISS_USER_GESTURE) {
+ log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
+ } else if (r == Bubbles.DISMISS_RELOAD_FROM_DISK) {
+ log(b, Event.BUBBLE_OVERFLOW_RECOVER);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index c386c9398624..068b2d246500 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -830,6 +830,13 @@ public class BubblePositioner {
mShowingInBubbleBar = showingInBubbleBar;
}
+ /**
+ * Whether bubbles ar showing in the bubble bar from launcher.
+ */
+ boolean isShowingInBubbleBar() {
+ return mShowingInBubbleBar;
+ }
+
public void setBubbleBarLocation(BubbleBarLocation location) {
mBubbleBarLocation = location;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt
index 68fc0c99abee..a517a2d550b9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt
@@ -42,6 +42,16 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) {
var componentName: ComponentName? = null
private set
+ /**
+ * Whether the task view is visible and has a surface. Note that this does not check the alpha
+ * value of the task view.
+ *
+ * When this is `true` it is safe to start showing the task view. Otherwise if this is `false`
+ * callers should wait for it to be visible which will be indicated either by a call to
+ * [TaskView.Listener.onTaskCreated] or [TaskView.Listener.onTaskVisibilityChanged]. */
+ var isVisible = false
+ private set
+
/** [TaskView.Listener] for users of this class. */
var delegateListener: TaskView.Listener? = null
@@ -61,9 +71,12 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) {
this@BubbleTaskView.taskId = taskId
isCreated = true
componentName = name
+ // when the task is created it is visible
+ isVisible = true
}
override fun onTaskVisibilityChanged(taskId: Int, visible: Boolean) {
+ this@BubbleTaskView.isVisible = visible
delegateListener?.onTaskVisibilityChanged(taskId, visible)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 74c3748dccaf..a313bd004a51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -161,6 +161,7 @@ public class BubbleBarAnimationHelper {
updateExpandedView();
bbev.setAnimating(true);
+ bbev.setSurfaceZOrderedOnTop(true);
bbev.setContentVisibility(false);
bbev.setAlpha(0f);
bbev.setTaskViewAlpha(0f);
@@ -171,28 +172,29 @@ public class BubbleBarAnimationHelper {
bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
- mExpandedViewAlphaAnimator.start();
-
- PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
- PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
- .spring(AnimatableScaleMatrix.SCALE_X,
- AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
- mScaleInSpringConfig)
- .spring(AnimatableScaleMatrix.SCALE_Y,
- AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
- mScaleInSpringConfig)
- .addUpdateListener((target, values) -> {
- bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
- })
- .withEndActions(() -> {
- bbev.setAnimationMatrix(null);
- updateExpandedView();
- bbev.setSurfaceZOrderedOnTop(false);
- if (afterAnimation != null) {
- afterAnimation.run();
- }
- })
- .start();
+ bbev.animateExpansionWhenTaskViewVisible(() -> {
+ mExpandedViewAlphaAnimator.start();
+
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+ .spring(AnimatableScaleMatrix.SCALE_X,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .spring(AnimatableScaleMatrix.SCALE_Y,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .addUpdateListener((target, values) -> {
+ bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
+ })
+ .withEndActions(() -> {
+ bbev.setAnimationMatrix(null);
+ updateExpandedView();
+ if (afterAnimation != null) {
+ afterAnimation.run();
+ }
+ })
+ .start();
+ });
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 3764bcd42ac6..ed49417ad3bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -131,6 +131,11 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
/** Current corner radius */
private float mCurrentCornerRadius = 0f;
+ /** A runnable to start the expansion animation as soon as the task view is made visible. */
+ @Nullable
+ private Runnable mAnimateExpansion = null;
+ private TaskViewVisibilityState mVisibilityState = TaskViewVisibilityState.INVISIBLE;
+
/**
* Whether we want the {@code TaskView}'s content to be visible (alpha = 1f). If
* {@link #mIsAnimating} is true, this may not reflect the {@code TaskView}'s actual alpha
@@ -140,6 +145,18 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
private boolean mIsAnimating;
private boolean mIsDragging;
+ /** An enum value that tracks the visibility state of the task view */
+ private enum TaskViewVisibilityState {
+ /** The task view is going away, and we're waiting for the surface to be destroyed. */
+ PENDING_INVISIBLE,
+ /** The task view is invisible and does not have a surface. */
+ INVISIBLE,
+ /** The task view is in the process of being added to a surface. */
+ PENDING_VISIBLE,
+ /** The task view is visible and has a surface. */
+ VISIBLE
+ }
+
public BubbleBarExpandedView(Context context) {
this(context, null);
}
@@ -206,16 +223,27 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, expandedViewManager,
/* listener= */ this, bubbleTaskView,
/* viewParent= */ this);
+
+ // if the task view is already attached to a parent we need to remove it
if (mTaskView.getParent() != null) {
+ // it's possible that the task view is visible, e.g. if we're unfolding, in which
+ // case removing it will trigger a visibility change. we have to wait for that
+ // signal before we can add it to this expanded view, otherwise the signal will be
+ // incorrect because the task view will have a surface.
+ // if the task view is not visible, then it has no surface and removing it will not
+ // trigger any visibility change signals.
+ if (bubbleTaskView.isVisible()) {
+ mVisibilityState = TaskViewVisibilityState.PENDING_INVISIBLE;
+ }
((ViewGroup) mTaskView.getParent()).removeView(mTaskView);
}
- FrameLayout.LayoutParams lp =
- new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
- addView(mTaskView, lp);
- mTaskView.setEnableSurfaceClipping(true);
- mTaskView.setCornerRadius(mCurrentCornerRadius);
- mTaskView.setVisibility(VISIBLE);
- mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
+
+ // if we're invisible it's safe to setup the task view and then await on the visibility
+ // signal.
+ if (mVisibilityState == TaskViewVisibilityState.INVISIBLE) {
+ mVisibilityState = TaskViewVisibilityState.PENDING_VISIBLE;
+ setupTaskView();
+ }
// Handle view needs to draw on top of task view.
bringChildToFront(mHandleView);
@@ -269,6 +297,16 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
});
}
+ private void setupTaskView() {
+ FrameLayout.LayoutParams lp =
+ new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
+ addView(mTaskView, lp);
+ mTaskView.setEnableSurfaceClipping(true);
+ mTaskView.setCornerRadius(mCurrentCornerRadius);
+ mTaskView.setVisibility(VISIBLE);
+ mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
+ }
+
public BubbleBarHandleView getHandleView() {
return mHandleView;
}
@@ -326,15 +364,28 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
@Override
public void onTaskCreated() {
- setContentVisibility(true);
+ if (mTaskView != null) {
+ mTaskView.setAlpha(0);
+ }
if (mListener != null) {
mListener.onTaskCreated();
}
+ // when the task is created we're visible
+ onTaskViewVisible();
}
@Override
public void onContentVisibilityChanged(boolean visible) {
- setContentVisibility(visible);
+ if (mVisibilityState == TaskViewVisibilityState.PENDING_INVISIBLE && !visible) {
+ // the surface is now destroyed. set up the task view and wait for the visibility
+ // signal.
+ mVisibilityState = TaskViewVisibilityState.PENDING_VISIBLE;
+ setupTaskView();
+ return;
+ }
+ if (visible) {
+ onTaskViewVisible();
+ }
}
@Override
@@ -350,6 +401,25 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
mListener.onBackPressed();
}
+ void animateExpansionWhenTaskViewVisible(Runnable animateExpansion) {
+ if (mVisibilityState == TaskViewVisibilityState.VISIBLE || mIsOverflow) {
+ animateExpansion.run();
+ } else {
+ mAnimateExpansion = animateExpansion;
+ }
+ }
+
+ private void onTaskViewVisible() {
+ // if we're waiting to be visible, start the expansion animation if it's pending.
+ if (mVisibilityState == TaskViewVisibilityState.PENDING_VISIBLE) {
+ mVisibilityState = TaskViewVisibilityState.VISIBLE;
+ if (mAnimateExpansion != null) {
+ mAnimateExpansion.run();
+ mAnimateExpansion = null;
+ }
+ }
+ }
+
/**
* Set whether this view is currently being dragged.
*
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index f532be6b8277..12d20bf0e517 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -96,6 +96,14 @@ public class DisplayController {
}
/**
+ * Get all the displays from DisplayManager.
+ */
+ public Display[] getDisplays() {
+ final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ return displayManager.getDisplays();
+ }
+
+ /**
* Gets the DisplayLayout associated with a display.
*/
public @Nullable DisplayLayout getDisplayLayout(int displayId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
index 9abf0f678179..de5c834f3120 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -33,6 +33,9 @@ public interface TaskStackListenerCallback {
default void onRecentTaskListFrozenChanged(boolean frozen) { }
+ /** A task is removed from recents as a result of another task being added to recent tasks. */
+ default void onRecentTaskRemovedForAddTask(int taskId) { }
+
@BinderThread
default void onTaskStackChangedBackground() { }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
index d8859bac471f..4e1dec60d956 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -59,6 +59,7 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 18;
private static final int ON_TASK_DESCRIPTION_CHANGED = 19;
private static final int ON_ACTIVITY_ROTATION = 20;
+ private static final int ON_RECENT_TASK_REMOVED_FOR_ADD_TASK = 21;
/**
* List of {@link TaskStackListenerCallback} registered from {@link #addListener}.
@@ -132,6 +133,11 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
}
@Override
+ public void onRecentTaskRemovedForAddTask(int taskId) {
+ mMainHandler.obtainMessage(ON_RECENT_TASK_REMOVED_FOR_ADD_TASK, taskId).sendToTarget();
+ }
+
+ @Override
public void onTaskStackChanged() {
// Call the task changed callback for the non-ui thread listeners first. Copy to a set
// of temp listeners so that we don't lock on mTaskStackListeners while calling all the
@@ -408,6 +414,13 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
}
break;
}
+ case ON_RECENT_TASK_REMOVED_FOR_ADD_TASK: {
+ final int taskId = (int) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onRecentTaskRemovedForAddTask(taskId);
+ }
+ break;
+ }
case ON_TASK_DESCRIPTION_CHANGED: {
final ActivityManager.RunningTaskInfo
info = (ActivityManager.RunningTaskInfo) msg.obj;
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 cf858deb0327..2c418d34f09a 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
@@ -90,8 +90,8 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private int mHandleRegionHeight;
/**
- * Tracks divider bar visible bounds in screen-based coordination. Used to calculate with
- * insets.
+ * This is not the visible bounds you see on screen, but the actual behind-the-scenes window
+ * bounds, which is larger.
*/
private final Rect mDividerBounds = new Rect();
private final Rect mTempRect = new Rect();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java
new file mode 100644
index 000000000000..381f0b037023
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.split;
+
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+
+import static com.android.wm.shell.common.split.SplitLayout.RESTING_TOUCH_LAYER;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.os.Binder;
+import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+/**
+ * Holds and manages a single touchable surface. These are used in offscreen split layouts, where
+ * we use them as a signal that the user wants to bring an offscreen app back onscreen.
+ * <br>
+ * Split root
+ * / | \
+ * Stage root Divider Stage root
+ * / \
+ * Task *this class*
+ *
+ */
+public class OffscreenTouchZone {
+ private static final String TAG = "OffscreenTouchZone";
+
+ /**
+ * Whether this touch zone is on the top/left or the bottom/right screen edge.
+ */
+ private final boolean mIsTopLeft;
+ /** The function that will be run when this zone is tapped. */
+ private final Runnable mOnClickRunnable;
+ private SurfaceControlViewHost mViewHost;
+
+ /**
+ * @param isTopLeft Whether the desired touch zone will be on the top/left or the bottom/right
+ * screen edge.
+ * @param runnable The function to run when the touch zone is tapped.
+ */
+ OffscreenTouchZone(boolean isTopLeft, Runnable runnable) {
+ mIsTopLeft = isTopLeft;
+ mOnClickRunnable = runnable;
+ }
+
+ /** Sets up a touch zone. */
+ public void inflate(Context context, Configuration config, SyncTransactionQueue syncQueue,
+ SurfaceControl stageRoot) {
+ View touchableView = new View(context);
+ touchableView.setOnTouchListener(new OffscreenTouchListener());
+
+ // Set WM flags, tokens, and sizing on the touchable view. It will be the same size as its
+ // parent, the stage root.
+ // TODO (b/349828130): It's a bit wasteful to have the touch zone cover the whole app
+ // surface, even extending offscreen (keeps buffer active in memory), so can trim it down
+ // to the visible onscreen area in a future patch.
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_INPUT_CONSUMER,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT);
+ lp.token = new Binder();
+ lp.setTitle(TAG);
+ lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+ touchableView.setLayoutParams(lp);
+
+ // Create a new leash under our stage leash.
+ final SurfaceControl.Builder builder = new SurfaceControl.Builder()
+ .setContainerLayer()
+ .setName(TAG + (mIsTopLeft ? "TopLeft" : "BottomRight"))
+ .setCallsite("OffscreenTouchZone::init");
+ builder.setParent(stageRoot);
+ SurfaceControl leash = builder.build();
+
+ // Create a ViewHost that will hold our view.
+ WindowlessWindowManager wwm = new WindowlessWindowManager(config, leash, null);
+ mViewHost = new SurfaceControlViewHost(context, context.getDisplay(), wwm,
+ "SplitTouchZones");
+ mViewHost.setView(touchableView, lp);
+
+ // Create a transaction so that we can activate and reposition our surface.
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ // Set layer to maximum. We want this surface to be above the app layer, or else touches
+ // will be blocked.
+ t.setLayer(leash, RESTING_TOUCH_LAYER);
+ // Leash starts off hidden, show it.
+ t.show(leash);
+ syncQueue.runInSync(transaction -> {
+ transaction.merge(t);
+ t.close();
+ });
+ }
+
+ /** Releases the touch zone when it's no longer needed. */
+ void release() {
+ if (mViewHost != null) {
+ mViewHost.release();
+ }
+ }
+
+ /**
+ * Listens for touch events.
+ * TODO (b/349828130): Update for mouse click events as well, and possibly keyboard?
+ */
+ private class OffscreenTouchListener implements View.OnTouchListener {
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
+ mOnClickRunnable.run();
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns {@code true} if this touch zone represents an offscreen app on the top/left edge of
+ * the display, {@code false} for bottom/right.
+ */
+ public boolean isTopLeft() {
+ return mIsTopLeft;
+ }
+}
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 de3152ad7687..d20ad5d1b908 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
@@ -23,8 +23,8 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static com.android.wm.shell.common.split.SplitLayout.BEHIND_APP_VEIL_LAYER;
-import static com.android.wm.shell.common.split.SplitLayout.FRONT_APP_VEIL_LAYER;
+import static com.android.wm.shell.common.split.SplitLayout.ANIMATING_BACK_APP_VEIL_LAYER;
+import static com.android.wm.shell.common.split.SplitLayout.ANIMATING_FRONT_APP_VEIL_LAYER;
import static com.android.wm.shell.shared.split.SplitScreenConstants.FADE_DURATION;
import static com.android.wm.shell.shared.split.SplitScreenConstants.VEIL_DELAY_DURATION;
@@ -66,6 +66,13 @@ import java.util.function.Consumer;
* Currently, we show a veil when:
* a) Task is resizing down from a fullscreen window.
* b) Task is being stretched past its original bounds.
+ * <br>
+ * Split root
+ * / | \
+ * Stage root Divider Stage root
+ * / \
+ * Task *this class*
+ *
*/
public class SplitDecorManager extends WindowlessWindowManager {
private static final String TAG = SplitDecorManager.class.getSimpleName();
@@ -77,6 +84,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
private Drawable mIcon;
private ImageView mVeilIconView;
private SurfaceControlViewHost mViewHost;
+ /** The parent surface that this is attached to. Should be the stage root. */
private SurfaceControl mHostLeash;
private SurfaceControl mIconLeash;
private SurfaceControl mBackgroundLeash;
@@ -389,7 +397,9 @@ public class SplitDecorManager extends WindowlessWindowManager {
mOffsetX = (int) iconOffsetX;
mOffsetY = (int) iconOffsetY;
- t.setLayer(leash, isGoingBehind ? BEHIND_APP_VEIL_LAYER : FRONT_APP_VEIL_LAYER);
+ t.setLayer(leash, isGoingBehind
+ ? ANIMATING_BACK_APP_VEIL_LAYER
+ : ANIMATING_FRONT_APP_VEIL_LAYER);
if (!mShown) {
if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index dab30b0f0b96..6beff1979e6d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -33,6 +33,8 @@ import static com.android.wm.shell.shared.animation.Interpolators.LINEAR;
import static com.android.wm.shell.shared.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_3_10_45_45;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_3_45_45_10;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -72,6 +74,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
@@ -80,6 +83,7 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.common.split.DividerSnapAlgorithm.SnapTarget;
+import com.android.wm.shell.common.split.SplitWindowManager.ParentContainerCallbacks;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
@@ -88,6 +92,8 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.StageTaskListener;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -111,15 +117,19 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public static final float OFFSCREEN_ASYMMETRIC_RATIO = 0.1f;
// Here are some (arbitrarily decided) layer definitions used during animations to make sure the
- // layers stay in order. Note: This does not affect any other layer numbering systems because
- // the layer system in WindowManager is local within sibling groups. So, for example, each
- // "veil layer" defined here actually has two sub-layers; and *their* layer values, which we set
- // in SplitDecorManager, are only important relative to each other.
- public static final int DIVIDER_LAYER = 0;
- public static final int FRONT_APP_VEIL_LAYER = DIVIDER_LAYER + 20;
- public static final int FRONT_APP_LAYER = DIVIDER_LAYER + 10;
- public static final int BEHIND_APP_VEIL_LAYER = DIVIDER_LAYER - 10;
- public static final int BEHIND_APP_LAYER = DIVIDER_LAYER - 20;
+ // layers stay in order. (During transitions, everything is reparented onto a transition root
+ // and can be freely relayered.)
+ public static final int ANIMATING_DIVIDER_LAYER = 0;
+ public static final int ANIMATING_FRONT_APP_VEIL_LAYER = ANIMATING_DIVIDER_LAYER + 20;
+ public static final int ANIMATING_FRONT_APP_LAYER = ANIMATING_DIVIDER_LAYER + 10;
+ public static final int ANIMATING_BACK_APP_VEIL_LAYER = ANIMATING_DIVIDER_LAYER - 10;
+ public static final int ANIMATING_BACK_APP_LAYER = ANIMATING_DIVIDER_LAYER - 20;
+ // The divider is on the split root, and is sibling with the stage roots. We want to keep it
+ // above the app stages.
+ public static final int RESTING_DIVIDER_LAYER = Integer.MAX_VALUE;
+ // The touch layer is on a stage root, and is sibling with things like the app activity itself
+ // and the app veil. We want it to be above all those.
+ public static final int RESTING_TOUCH_LAYER = Integer.MAX_VALUE;
// Animation specs for the swap animation
private static final int SWAP_ANIMATION_TOTAL_DURATION = 500;
@@ -139,19 +149,31 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
private final Rect mTempRect = new Rect();
private final Rect mRootBounds = new Rect();
private final Rect mDividerBounds = new Rect();
- // Bounds1 final position should be always at top or left
- private final Rect mBounds1 = new Rect();
- // Bounds2 final position should be always at bottom or right
- private final Rect mBounds2 = new Rect();
+ /**
+ * A list of stage bounds, kept in order from top/left to bottom/right. These are the sizes of
+ * the app surfaces, not necessarily the same as the size of the rendered content.
+ * See {@link #mContentBounds}.
+ */
+ private final List<Rect> mStageBounds = List.of(new Rect(), new Rect());
+ /**
+ * A list of app content bounds, kept in order from top/left to bottom/right. These are the
+ * sizes of the rendered app contents, not necessarily the same as the size of the drawn app
+ * surfaces. See {@link #mStageBounds}.
+ */
+ private final List<Rect> mContentBounds = List.of(new Rect(), new Rect());
// The temp bounds outside of display bounds for side stage when split screen inactive to avoid
// flicker next time active split screen.
private final Rect mInvisibleBounds = new Rect();
- private final Rect mWinBounds1 = new Rect();
- private final Rect mWinBounds2 = new Rect();
+ /**
+ * Areas on the screen that the user can touch to shift the layout, bringing offscreen apps
+ * onscreen. If n apps are offscreen, there should be n such areas. Empty otherwise.
+ */
+ private final List<OffscreenTouchZone> mOffscreenTouchZones = new ArrayList<>();
private final SplitLayoutHandler mSplitLayoutHandler;
private final SplitWindowManager mSplitWindowManager;
private final DisplayController mDisplayController;
private final DisplayImeController mDisplayImeController;
+ private final ParentContainerCallbacks mParentContainerCallbacks;
private final ImePositionProcessor mImePositionProcessor;
private final ResizingEffectPolicy mSurfaceEffectPolicy;
private final ShellTaskOrganizer mTaskOrganizer;
@@ -192,6 +214,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mSplitLayoutHandler = splitLayoutHandler;
mDisplayController = displayController;
mDisplayImeController = displayImeController;
+ mParentContainerCallbacks = parentContainerCallbacks;
mSplitWindowManager = new SplitWindowManager(windowName, mContext, configuration,
parentContainerCallbacks);
mTaskOrganizer = taskOrganizer;
@@ -233,26 +256,26 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mDividerWindowWidth = mDividerSize + 2 * mDividerInsets;
}
- /** Gets bounds of the primary split with screen based coordinate. */
- public Rect getBounds1() {
- return new Rect(mBounds1);
+ /** Gets the bounds of the top/left app in screen-based coordinates. */
+ public Rect getTopLeftBounds() {
+ return mStageBounds.getFirst();
}
- /** Gets bounds of the primary split with parent based coordinate. */
- public Rect getRefBounds1() {
- Rect outBounds = getBounds1();
- outBounds.offset(-mRootBounds.left, -mRootBounds.top);
- return outBounds;
+ /** Gets the bounds of the bottom/right app in screen-based coordinates. */
+ public Rect getBottomRightBounds() {
+ return mStageBounds.getLast();
}
- /** Gets bounds of the secondary split with screen based coordinate. */
- public Rect getBounds2() {
- return new Rect(mBounds2);
+ /** Gets the bounds of the top/left app in parent-based coordinates. */
+ public Rect getTopLeftRefBounds() {
+ Rect outBounds = getTopLeftBounds();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
}
- /** Gets bounds of the secondary split with parent based coordinate. */
- public Rect getRefBounds2() {
- final Rect outBounds = getBounds2();
+ /** Gets the bounds of the bottom/right app in parent-based coordinates. */
+ public Rect getBottomRightRefBounds() {
+ Rect outBounds = getBottomRightBounds();
outBounds.offset(-mRootBounds.left, -mRootBounds.top);
return outBounds;
}
@@ -262,51 +285,74 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return new Rect(mRootBounds);
}
- /** Gets bounds of divider window with screen based coordinate. */
- public Rect getDividerBounds() {
- return new Rect(mDividerBounds);
+ /** Copies the top/left bounds to the provided Rect (screen-based coordinates). */
+ public void copyTopLeftBounds(Rect rect) {
+ rect.set(getTopLeftBounds());
}
- /** Gets bounds of divider window with parent based coordinate. */
- public Rect getRefDividerBounds() {
- final Rect outBounds = getDividerBounds();
- outBounds.offset(-mRootBounds.left, -mRootBounds.top);
- return outBounds;
+ /** Copies the top/left bounds to the provided Rect (parent-based coordinates). */
+ public void copyTopLeftRefBounds(Rect rect) {
+ copyTopLeftBounds(rect);
+ rect.offset(-mRootBounds.left, -mRootBounds.top);
}
- /** Gets bounds of the primary split with screen based coordinate on the param Rect. */
- public void getBounds1(Rect rect) {
- rect.set(mBounds1);
+ /** Copies the bottom/right bounds to the provided Rect (screen-based coordinates). */
+ public void copyBottomRightBounds(Rect rect) {
+ rect.set(getBottomRightBounds());
}
- /** Gets bounds of the primary split with parent based coordinate on the param Rect. */
- public void getRefBounds1(Rect rect) {
- getBounds1(rect);
+ /** Copies the bottom/right bounds to the provided Rect (parent-based coordinates). */
+ public void copyBottomRightRefBounds(Rect rect) {
+ copyBottomRightBounds(rect);
rect.offset(-mRootBounds.left, -mRootBounds.top);
}
- /** Gets bounds of the secondary split with screen based coordinate on the param Rect. */
- public void getBounds2(Rect rect) {
- rect.set(mBounds2);
+ /**
+ * Gets the content bounds of the top/left app (the bounds of where the app contents would be
+ * drawn). Might be larger than the available surface space.
+ */
+ public Rect getTopLeftContentBounds() {
+ return mContentBounds.getFirst();
}
- /** Gets bounds of the secondary split with parent based coordinate on the param Rect. */
- public void getRefBounds2(Rect rect) {
- getBounds2(rect);
- rect.offset(-mRootBounds.left, -mRootBounds.top);
+ /**
+ * Gets the content bounds of the bottom/right app (the bounds of where the app contents would
+ * be drawn). Might be larger than the available surface space.
+ */
+ public Rect getBottomRightContentBounds() {
+ return mContentBounds.getLast();
}
- /** Gets root bounds of the whole split layout on the param Rect. */
- public void getRootBounds(Rect rect) {
- rect.set(mRootBounds);
+ /**
+ * Gets the bounds of divider window, in screen-based coordinates. This is not the visible
+ * bounds you see on screen, but the actual behind-the-scenes window bounds, which is larger.
+ */
+ public Rect getDividerBounds() {
+ return new Rect(mDividerBounds);
+ }
+
+ /**
+ * Gets the bounds of divider window, in parent-based coordinates. This is not the visible
+ * bounds you see on screen, but the actual behind-the-scenes window bounds, which is larger.
+ */
+ public Rect getRefDividerBounds() {
+ final Rect outBounds = getDividerBounds();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
}
- /** Gets bounds of divider window with screen based coordinate on the param Rect. */
+ /**
+ * Gets the bounds of divider window, in screen-based coordinates. This is not the visible
+ * bounds you see on screen, but the actual behind-the-scenes window bounds, which is larger.
+ */
public void getDividerBounds(Rect rect) {
rect.set(mDividerBounds);
}
- /** Gets bounds of divider window with parent based coordinate on the param Rect. */
+ /**
+ * Gets the bounds of divider window, in parent-based coordinates. This is not the visible
+ * bounds you see on screen, but the actual behind-the-scenes window bounds, which is larger.
+ */
public void getRefDividerBounds(Rect rect) {
getDividerBounds(rect);
rect.offset(-mRootBounds.left, -mRootBounds.top);
@@ -340,8 +386,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
*/
public float getDividerPositionAsFraction() {
return Math.min(1f, Math.max(0f, mIsLeftRightSplit
- ? (float) ((mBounds1.right + mBounds2.left) / 2f) / mBounds2.right
- : (float) ((mBounds1.bottom + mBounds2.top) / 2f) / mBounds2.bottom));
+ ? (float) ((getTopLeftBounds().right + getBottomRightBounds().left) / 2f)
+ / getBottomRightBounds().right
+ : (float) ((getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f)
+ / getBottomRightBounds().bottom));
}
private void updateInvisibleRect() {
@@ -352,6 +400,46 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mIsLeftRightSplit ? 0 : mRootBounds.bottom);
}
+ /**
+ * (Re)calculates and activates any needed touch zones, so the user can tap them and retrieve
+ * offscreen apps.
+ */
+ public void populateTouchZones() {
+ if (!Flags.enableFlexibleTwoAppSplit()) {
+ return;
+ }
+
+ if (!mOffscreenTouchZones.isEmpty()) {
+ removeTouchZones();
+ }
+
+ int currentPosition = calculateCurrentSnapPosition();
+ switch (currentPosition) {
+ case SNAP_TO_2_10_90:
+ case SNAP_TO_3_10_45_45:
+ mOffscreenTouchZones.add(new OffscreenTouchZone(true /* isTopLeft */,
+ () -> flingDividerToOtherSide(currentPosition)));
+ break;
+ case SNAP_TO_2_90_10:
+ case SNAP_TO_3_45_45_10:
+ mOffscreenTouchZones.add(new OffscreenTouchZone(false /* isTopLeft */,
+ () -> flingDividerToOtherSide(currentPosition)));
+ break;
+ }
+
+ mOffscreenTouchZones.forEach(mParentContainerCallbacks::inflateOnStageRoot);
+ }
+
+ /** Removes all touch zones. */
+ public void removeTouchZones() {
+ if (!Flags.enableFlexibleTwoAppSplit()) {
+ return;
+ }
+
+ mOffscreenTouchZones.forEach(OffscreenTouchZone::release);
+ mOffscreenTouchZones.clear();
+ }
+
/** Applies new configuration, returns {@code false} if there's no effect to the layout. */
public boolean updateConfiguration(Configuration configuration) {
// Update the split bounds when necessary. Besides root bounds changed, split bounds need to
@@ -435,7 +523,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
private void updateBounds(int position) {
- updateBounds(position, mBounds1, mBounds2, mDividerBounds, true /* setEffectBounds */);
+ updateBounds(position, getTopLeftBounds(), getBottomRightBounds(), mDividerBounds,
+ true /* setEffectBounds */);
}
/** Updates recording bounds of divider window and both of the splits. */
@@ -488,6 +577,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
if (mInitialized) return;
mInitialized = true;
mSplitWindowManager.init(this, mInsetsState, false /* isRestoring */);
+ populateTouchZones();
mDisplayImeController.addPositionProcessor(mImePositionProcessor);
}
@@ -496,6 +586,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
if (!mInitialized) return;
mInitialized = false;
mSplitWindowManager.release(t);
+ removeTouchZones();
mDisplayImeController.removePositionProcessor(mImePositionProcessor);
mImePositionProcessor.reset();
if (mDividerFlingAnimator != null) {
@@ -519,6 +610,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mImePositionProcessor.reset();
}
mSplitWindowManager.init(this, mInsetsState, true /* isRestoring */);
+ populateTouchZones();
// Update the surface positions again after recreating the divider in case nothing else
// triggers it
mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
@@ -638,8 +730,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
updateBounds(mDividerPosition);
mWinToken1 = null;
mWinToken2 = null;
- mWinBounds1.setEmpty();
- mWinBounds2.setEmpty();
+ getTopLeftContentBounds().setEmpty();
+ getBottomRightContentBounds().setEmpty();
}
/**
@@ -761,6 +853,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
* DividerSnapAlgorithm will need to be refactored, and this function will change as well.
*/
public void flingDividerToOtherSide(@PersistentSnapPosition int currentSnapPosition) {
+ // If a fling animation is already running, just return.
+ if (mDividerFlingAnimator != null) return;
+
switch (currentSnapPosition) {
case SNAP_TO_2_10_90 ->
snapToTarget(mDividerPosition, mDividerSnapAlgorithm.getLastSplitTarget(),
@@ -835,7 +930,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
insets.left != 0 || insets.top != 0 || insets.right != 0 || insets.bottom != 0;
final int dividerPos = mDividerSnapAlgorithm.calculateNonDismissingSnapTarget(
- mIsLeftRightSplit ? mBounds2.width() : mBounds2.height()).position;
+ mIsLeftRightSplit ? getBottomRightBounds().width() : getBottomRightBounds().height()
+ ).position;
final Rect endBounds1 = new Rect();
final Rect endBounds2 = new Rect();
final Rect endDividerBounds = new Rect();
@@ -847,12 +943,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
endBounds2.offset(-mRootBounds.left, -mRootBounds.top);
endDividerBounds.offset(-mRootBounds.left, -mRootBounds.top);
- ValueAnimator animator1 = moveSurface(t, topLeftStage, getRefBounds1(), endBounds1,
+ ValueAnimator animator1 = moveSurface(t, topLeftStage, getTopLeftRefBounds(), endBounds1,
-insets.left, -insets.top, true /* roundCorners */, true /* isGoingBehind */,
shouldVeil);
- ValueAnimator animator2 = moveSurface(t, bottomRightStage, getRefBounds2(), endBounds2,
- insets.left, insets.top, true /* roundCorners */, false /* isGoingBehind */,
- shouldVeil);
+ ValueAnimator animator2 = moveSurface(t, bottomRightStage, getBottomRightRefBounds(),
+ endBounds2, insets.left, insets.top, true /* roundCorners */,
+ false /* isGoingBehind */, shouldVeil);
ValueAnimator animator3 = moveSurface(t, null /* stage */, getRefDividerBounds(),
endDividerBounds, 0 /* offsetX */, 0 /* offsetY */, false /* roundCorners */,
false /* isGoingBehind */, false /* addVeil */);
@@ -996,9 +1092,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
// Set layers
if (taskInfo != null) {
- t.setLayer(leash, isGoingBehind ? BEHIND_APP_LAYER : FRONT_APP_LAYER);
+ t.setLayer(leash, isGoingBehind
+ ? ANIMATING_BACK_APP_LAYER
+ : ANIMATING_FRONT_APP_LAYER);
} else {
- t.setLayer(leash, DIVIDER_LAYER);
+ t.setLayer(leash, ANIMATING_DIVIDER_LAYER);
}
if (offsetX == 0 && offsetY == 0) {
@@ -1057,12 +1155,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
getRefDividerBounds(mTempRect);
t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
// Resets layer of divider bar to make sure it is always on top.
- t.setLayer(dividerLeash, Integer.MAX_VALUE);
+ t.setLayer(dividerLeash, RESTING_DIVIDER_LAYER);
}
- getRefBounds1(mTempRect);
+ copyTopLeftRefBounds(mTempRect);
t.setPosition(leash1, mTempRect.left, mTempRect.top)
.setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
- getRefBounds2(mTempRect);
+ copyBottomRightRefBounds(mTempRect);
t.setPosition(leash2, mTempRect.left, mTempRect.top)
.setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
@@ -1084,15 +1182,17 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public boolean applyTaskChanges(WindowContainerTransaction wct,
ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
boolean boundsChanged = false;
- if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) {
- setTaskBounds(wct, task1, mBounds1);
- mWinBounds1.set(mBounds1);
+ if (!getTopLeftBounds().equals(getTopLeftContentBounds())
+ || !task1.token.equals(mWinToken1)) {
+ setTaskBounds(wct, task1, getTopLeftBounds());
+ getTopLeftContentBounds().set(getTopLeftBounds());
mWinToken1 = task1.token;
boundsChanged = true;
}
- if (!mBounds2.equals(mWinBounds2) || !task2.token.equals(mWinToken2)) {
- setTaskBounds(wct, task2, mBounds2);
- mWinBounds2.set(mBounds2);
+ if (!getBottomRightBounds().equals(getBottomRightContentBounds())
+ || !task2.token.equals(mWinToken2)) {
+ setTaskBounds(wct, task2, getBottomRightBounds());
+ getBottomRightContentBounds().set(getBottomRightBounds());
mWinToken2 = task2.token;
boundsChanged = true;
}
@@ -1129,22 +1229,22 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void applyLayoutOffsetTarget(WindowContainerTransaction wct, int offsetX, int offsetY,
ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
if (offsetX == 0 && offsetY == 0) {
- wct.setBounds(taskInfo1.token, mBounds1);
+ wct.setBounds(taskInfo1.token, getTopLeftBounds());
wct.setScreenSizeDp(taskInfo1.token,
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
- wct.setBounds(taskInfo2.token, mBounds2);
+ wct.setBounds(taskInfo2.token, getBottomRightBounds());
wct.setScreenSizeDp(taskInfo2.token,
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
} else {
- getBounds1(mTempRect);
+ copyTopLeftBounds(mTempRect);
mTempRect.offset(offsetX, offsetY);
wct.setBounds(taskInfo1.token, mTempRect);
wct.setScreenSizeDp(taskInfo1.token,
taskInfo1.configuration.screenWidthDp,
taskInfo1.configuration.screenHeightDp);
- getBounds2(mTempRect);
+ copyBottomRightBounds(mTempRect);
mTempRect.offset(offsetX, offsetY);
wct.setBounds(taskInfo2.token, mTempRect);
wct.setScreenSizeDp(taskInfo2.token,
@@ -1162,9 +1262,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
pw.println(innerPrefix + "mFreezeDividerWindow=" + mFreezeDividerWindow);
pw.println(innerPrefix + "mDimNonImeSide=" + mDimNonImeSide);
pw.println(innerPrefix + "mDividerPosition=" + mDividerPosition);
- pw.println(innerPrefix + "bounds1=" + mBounds1.toShortString());
+ pw.println(innerPrefix + "bounds1=" + getTopLeftBounds().toShortString());
pw.println(innerPrefix + "dividerBounds=" + mDividerBounds.toShortString());
- pw.println(innerPrefix + "bounds2=" + mBounds2.toShortString());
+ pw.println(innerPrefix + "bounds2=" + getBottomRightBounds().toShortString());
}
/** Handles layout change event. */
@@ -1274,15 +1374,16 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
final boolean topLeftShrink = isLeftRightSplit
- ? position < mWinBounds1.right : position < mWinBounds1.bottom;
+ ? position < getTopLeftContentBounds().right
+ : position < getTopLeftContentBounds().bottom;
if (topLeftShrink) {
mShrinkSide = isLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP;
- mContentBounds.set(mWinBounds1);
- mSurfaceBounds.set(mBounds1);
+ mContentBounds.set(getTopLeftContentBounds());
+ mSurfaceBounds.set(getTopLeftBounds());
} else {
mShrinkSide = isLeftRightSplit ? DOCKED_RIGHT : DOCKED_BOTTOM;
- mContentBounds.set(mWinBounds2);
- mSurfaceBounds.set(mBounds2);
+ mContentBounds.set(getBottomRightContentBounds());
+ mSurfaceBounds.set(getBottomRightBounds());
}
if (mDismissingSide != DOCKED_INVALID) {
@@ -1334,12 +1435,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
case DOCKED_TOP:
case DOCKED_LEFT:
targetLeash = leash1;
- mTempRect.set(mBounds1);
+ mTempRect.set(getTopLeftBounds());
break;
case DOCKED_BOTTOM:
case DOCKED_RIGHT:
targetLeash = leash2;
- mTempRect.set(mBounds2);
+ mTempRect.set(getBottomRightBounds());
break;
}
} else if (mParallaxType == PARALLAX_ALIGN_CENTER) {
@@ -1347,12 +1448,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
case DOCKED_TOP:
case DOCKED_LEFT:
targetLeash = leash1;
- mTempRect.set(mBounds1);
+ mTempRect.set(getTopLeftBounds());
break;
case DOCKED_BOTTOM:
case DOCKED_RIGHT:
targetLeash = leash2;
- mTempRect.set(mBounds2);
+ mTempRect.set(getBottomRightBounds());
break;
}
}
@@ -1530,7 +1631,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
private int getTargetYOffset() {
final int desireOffset = Math.abs(mEndImeTop - mStartImeTop);
// Make sure to keep at least 30% visible for the top split.
- final int maxOffset = (int) (mBounds1.height() * ADJUSTED_SPLIT_FRACTION_MAX);
+ final int maxOffset = (int) (getTopLeftBounds().height() * ADJUSTED_SPLIT_FRACTION_MAX);
return -Math.min(desireOffset, maxOffset);
}
@@ -1580,11 +1681,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
}
- getRefBounds1(mTempRect);
+ copyTopLeftRefBounds(mTempRect);
mTempRect.offset(0, mYOffsetForIme);
t.setPosition(leash1, mTempRect.left, mTempRect.top);
- getRefBounds2(mTempRect);
+ copyBottomRightRefBounds(mTempRect);
mTempRect.offset(0, mYOffsetForIme);
t.setPosition(leash2, mTempRect.left, mTempRect.top);
adjusted = true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index c5f19742c803..89573ccef24b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -67,6 +67,8 @@ public final class SplitWindowManager extends WindowlessWindowManager {
public interface ParentContainerCallbacks {
void attachToParentSurface(SurfaceControl.Builder b);
void onLeashReady(SurfaceControl leash);
+ /** Inflates the given touch zone on the appropriate stage root. */
+ void inflateOnStageRoot(OffscreenTouchZone touchZone);
}
public SplitWindowManager(String windowName, Context context, Configuration config,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt
new file mode 100644
index 000000000000..819b11095a9b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.content.Context
+import android.graphics.Color
+import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags
+import com.android.wm.shell.dagger.WMSingleton
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
+import com.android.wm.shell.sysui.ShellCommandHandler
+import com.android.wm.shell.sysui.ShellCommandHandler.ShellCommandActionHandler
+import com.android.wm.shell.sysui.ShellInit
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Handles the shell commands for the CompatUI.
+ *
+ * <p> Use with [adb shell dumpsys activity service SystemUIService WMShell letterbox
+ * &lt;command&gt;].
+ */
+@WMSingleton
+class LetterboxCommandHandler @Inject constructor(
+ private val context: Context,
+ shellInit: ShellInit,
+ shellCommandHandler: ShellCommandHandler,
+ private val letterboxConfiguration: LetterboxConfiguration
+) : ShellCommandActionHandler {
+
+ companion object {
+ @JvmStatic
+ private val TAG = "LetterboxCommandHandler"
+ }
+
+ init {
+ if (Flags.appCompatRefactoring()) {
+ ProtoLog.v(
+ WM_SHELL_APP_COMPAT,
+ "%s: %s",
+ TAG,
+ "Initializing LetterboxCommandHandler"
+ )
+ shellInit.addInitCallback({
+ shellCommandHandler.addCommandCallback("letterbox", this, this)
+ }, this)
+ }
+ }
+
+ override fun onShellCommand(args: Array<out String>?, pw: PrintWriter?): Boolean {
+ if (args == null || pw == null) {
+ pw!!.println("Missing arguments.")
+ return false
+ }
+ return when (args.size) {
+ 1 -> onShellDisplayCommand(args[0], pw)
+ 2 -> onShellUpdateCommand(args[0], args[1], pw)
+ else -> {
+ pw.println("Invalid command: " + args[0])
+ return false
+ }
+ }
+ }
+
+ override fun printShellCommandHelp(pw: PrintWriter?, prefix: String?) {
+ pw?.println(
+ """
+ $prefix backgroundColor color"
+ $prefix Color of letterbox which is to be used when letterbox background
+ $prefix type is 'solid-color'. See Color#parseColor for allowed color
+ $prefix formats (#RRGGBB and some colors by name, e.g. magenta or olive).
+ $prefix backgroundColorResource resource_name"
+ $prefix Color resource name of letterbox background which is used when
+ $prefix background type is 'solid-color'. Parameter is a color resource
+ $prefix name, for example, @android:color/system_accent2_50.
+ $prefix backgroundColorReset"
+ $prefix Resets the background color to the default value."
+ """.trimIndent()
+ )
+ }
+
+ private fun onShellUpdateCommand(command: String, value: String, pw: PrintWriter): Boolean {
+ when (command) {
+ "backgroundColor" -> {
+ return invokeWhenValid(
+ pw,
+ value,
+ ::strToColor,
+ { color ->
+ letterboxConfiguration.setLetterboxBackgroundColor(color)
+ },
+ { c -> "$c is not a valid color." }
+ )
+ }
+
+ "backgroundColorResource" -> return invokeWhenValid(
+ pw,
+ value,
+ ::nameToColorId,
+ { color ->
+ letterboxConfiguration.setLetterboxBackgroundColorResourceId(color)
+ },
+ { c ->
+ "$c is not a valid resource. Color in '@android:color/resource_name'" +
+ " format should be provided as an argument."
+ }
+ )
+
+ "backgroundColorReset" -> {
+ letterboxConfiguration.resetLetterboxBackgroundColor()
+ return true
+ }
+
+ else -> {
+ pw.println("Invalid command: $value")
+ return false
+ }
+ }
+ }
+
+ private fun onShellDisplayCommand(command: String, pw: PrintWriter): Boolean {
+ when (command) {
+ "backgroundColor" -> {
+ pw.println(
+ " Background color: " + Integer.toHexString(
+ letterboxConfiguration.getLetterboxBackgroundColor()
+ .toArgb()
+ )
+ )
+ return true
+ }
+
+ else -> {
+ pw.println("Invalid command: $command")
+ return false
+ }
+ }
+ }
+
+ private fun <T> invokeWhenValid(
+ pw: PrintWriter,
+ input: String,
+ converter: (String) -> T?,
+ consumer: (T) -> Unit,
+ errorMessage: (String) -> String = { value -> " Wrong input value: $value." }
+ ): Boolean {
+ converter(input)?.let {
+ consumer(it)
+ return true
+ }
+ pw.println(errorMessage(input))
+ return false
+ }
+
+ // Converts a String to Color if possible or it returns null otherwise.
+ private fun strToColor(str: String): Color? =
+ try {
+ Color.valueOf(Color.parseColor(str))
+ } catch (e: IllegalArgumentException) {
+ null
+ }
+
+ // Converts a resource id to Color if possible or it returns null otherwise.
+ private fun nameToColorId(str: String): Int? =
+ try {
+ context.resources.getIdentifier(str, "color", "com.android.internal")
+ } catch (e: IllegalArgumentException) {
+ null
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt
new file mode 100644
index 000000000000..83a8e3103e3f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.annotation.ColorRes
+import android.content.Context
+import android.graphics.Color
+import com.android.internal.R
+import com.android.wm.shell.dagger.WMSingleton
+import javax.inject.Inject
+
+/**
+ * Contains configuration properties for the letterbox implementation in Shell.
+ */
+@WMSingleton
+class LetterboxConfiguration @Inject constructor(
+ private val context: Context
+) {
+ // Color to use for the solid color letterbox background type.
+ private var letterboxBackgroundColorOverride: Color? = null
+
+ // Color resource id for the solid color letterbox background type.
+ private var letterboxBackgroundColorResourceIdOverride: Int? = null
+
+ /**
+ * Sets color of letterbox background which is used when using the solid background mode.
+ */
+ fun setLetterboxBackgroundColor(color: Color) {
+ letterboxBackgroundColorOverride = color
+ }
+
+ /**
+ * Sets color ID of letterbox background which is used when using the solid background mode.
+ */
+ fun setLetterboxBackgroundColorResourceId(@ColorRes colorId: Int) {
+ letterboxBackgroundColorResourceIdOverride = colorId
+ }
+
+ /**
+ * Gets color of letterbox background which is used when the solid color mode is active.
+ */
+ fun getLetterboxBackgroundColor(): Color {
+ if (letterboxBackgroundColorOverride != null) {
+ return letterboxBackgroundColorOverride!!
+ }
+ val colorId = if (letterboxBackgroundColorResourceIdOverride != null) {
+ letterboxBackgroundColorResourceIdOverride
+ } else {
+ R.color.config_letterboxBackgroundColor
+ }
+ // Query color dynamically because material colors extracted from wallpaper are updated
+ // when wallpaper is changed.
+ return Color.valueOf(context.getResources().getColor(colorId!!, /* theme */null))
+ }
+
+ /**
+ * Resets color of letterbox background to the default.
+ */
+ fun resetLetterboxBackgroundColor() {
+ letterboxBackgroundColorOverride = null
+ letterboxBackgroundColorResourceIdOverride = null
+ }
+
+ /**
+ * The background color for the Letterbox.
+ */
+ fun getBackgroundColorRgbArray(): FloatArray = getLetterboxBackgroundColor().components
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt
new file mode 100644
index 000000000000..0ac7aff306a0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.graphics.Rect
+import android.view.SurfaceControl
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.dagger.WMSingleton
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
+import javax.inject.Inject
+
+/**
+ * Component responsible for handling the lifecycle of the letterbox surfaces.
+ */
+@WMSingleton
+class LetterboxController @Inject constructor(
+ private val letterboxConfiguration: LetterboxConfiguration
+) {
+
+ companion object {
+ /*
+ * Letterbox surfaces need to stay below the activity layer which is 0.
+ */
+ // TODO(b/378673153): Consider adding this to [TaskConstants].
+ @JvmStatic
+ private val TASK_CHILD_LAYER_LETTERBOX_BACKGROUND = -1000
+ @JvmStatic
+ private val TAG = "LetterboxController"
+ }
+
+ private val letterboxMap = mutableMapOf<LetterboxKey, LetterboxItem>()
+
+ /**
+ * Creates a Letterbox Surface for a given displayId/taskId if it doesn't exist.
+ */
+ fun createLetterboxSurface(
+ key: LetterboxKey,
+ startTransaction: SurfaceControl.Transaction,
+ parentLeash: SurfaceControl
+ ) {
+ letterboxMap.runOnItem(key, onMissed = { k, m ->
+ m[k] = LetterboxItem(
+ SurfaceControl.Builder()
+ .setName("ShellLetterboxSurface-$key")
+ .setHidden(true)
+ .setColorLayer()
+ .setParent(parentLeash)
+ .setCallsite("LetterboxController-createLetterboxSurface")
+ .build().apply {
+ startTransaction.setLayer(
+ this,
+ TASK_CHILD_LAYER_LETTERBOX_BACKGROUND
+ ).setColorSpaceAgnostic(this, true)
+ .setColor(this, letterboxConfiguration.getBackgroundColorRgbArray())
+ }
+ )
+ })
+ }
+
+ /**
+ * Invoked to destroy the surfaces for a letterbox session for given displayId/taskId.
+ */
+ fun destroyLetterboxSurface(
+ key: LetterboxKey,
+ startTransaction: SurfaceControl.Transaction
+ ) {
+ letterboxMap.runOnItem(key, onFound = { item ->
+ item.fullWindowSurface?.run {
+ startTransaction.remove(this)
+ }
+ })
+ letterboxMap.remove(key)
+ }
+
+ /**
+ * Invoked to show/hide the letterbox surfaces for given displayId/taskId.
+ */
+ fun updateLetterboxSurfaceVisibility(
+ key: LetterboxKey,
+ startTransaction: SurfaceControl.Transaction,
+ visible: Boolean = true
+ ) {
+ letterboxMap.runOnItem(key, onFound = { item ->
+ item.fullWindowSurface?.run {
+ startTransaction.setVisibility(this, visible)
+ }
+ })
+ }
+
+ /**
+ * Updates the bounds for the letterbox surfaces for given displayId/taskId.
+ */
+ fun updateLetterboxSurfaceBounds(
+ key: LetterboxKey,
+ startTransaction: SurfaceControl.Transaction,
+ bounds: Rect
+ ) {
+ letterboxMap.runOnItem(key, onFound = { item ->
+ item.fullWindowSurface?.run {
+ startTransaction.moveAndCrop(this, bounds)
+ }
+ })
+ }
+
+ /*
+ * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present.
+ */
+ private fun MutableMap<LetterboxKey, LetterboxItem>.runOnItem(
+ key: LetterboxKey,
+ onFound: (LetterboxItem) -> Unit = { _ -> },
+ onMissed: (
+ LetterboxKey,
+ MutableMap<LetterboxKey, LetterboxItem>
+ ) -> Unit = { _, _ -> }
+ ) {
+ this[key]?.let {
+ return onFound(it)
+ }
+ return onMissed(key, this)
+ }
+
+ fun dump() {
+ ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}")
+ }
+
+ private fun SurfaceControl.Transaction.moveAndCrop(
+ surface: SurfaceControl,
+ rect: Rect
+ ): SurfaceControl.Transaction =
+ setPosition(surface, rect.left.toFloat(), rect.top.toFloat())
+ .setWindowCrop(
+ surface,
+ rect.width(),
+ rect.height()
+ )
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt
new file mode 100644
index 000000000000..98fd2472f1e4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.view.SurfaceControl
+
+// The key to use for identify the letterbox sessions.
+data class LetterboxKey(val displayId: Int, val taskId: Int)
+
+// Encapsulate the objects for the specific letterbox session.
+data class LetterboxItem(val fullWindowSurface: SurfaceControl?) \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt
new file mode 100644
index 000000000000..67429bdd112b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.graphics.Rect
+import android.os.IBinder
+import android.view.SurfaceControl
+import android.window.TransitionInfo
+import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags.appCompatRefactoring
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
+import com.android.wm.shell.shared.TransitionUtil.isClosingType
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.Transitions
+
+/**
+ * The [TransitionObserver] to handle Letterboxing events in Shell.
+ */
+class LetterboxTransitionObserver(
+ shellInit: ShellInit,
+ private val transitions: Transitions,
+ private val letterboxController: LetterboxController
+) : Transitions.TransitionObserver {
+
+ companion object {
+ @JvmStatic
+ private val TAG = "LetterboxTransitionObserver"
+ }
+
+ init {
+ if (appCompatRefactoring()) {
+ ProtoLog.v(
+ WM_SHELL_APP_COMPAT,
+ "%s: %s",
+ TAG,
+ "Initializing LetterboxTransitionObserver"
+ )
+ shellInit.addInitCallback({
+ transitions.registerObserver(this)
+ }, this)
+ }
+ }
+
+ override fun onTransitionReady(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction
+ ) {
+ // We recognise the operation to execute and delegate to the LetterboxController
+ // the related operation.
+ // TODO(b/377875151): Identify Desktop Windowing Transactions.
+ // TODO(b/377857898): Handling multiple surfaces
+ // TODO(b/371500295): Handle input events detection.
+ for (change in info.changes) {
+ change.taskInfo?.let { ti ->
+ val key = LetterboxKey(ti.displayId, ti.taskId)
+ if (isClosingType(change.mode)) {
+ letterboxController.destroyLetterboxSurface(
+ key,
+ startTransaction
+ )
+ } else {
+ val isTopActivityLetterboxed = ti.appCompatTaskInfo.isTopActivityLetterboxed
+ if (isTopActivityLetterboxed) {
+ letterboxController.createLetterboxSurface(
+ key,
+ startTransaction,
+ change.leash
+ )
+ letterboxController.updateLetterboxSurfaceBounds(
+ key,
+ startTransaction,
+ Rect(
+ change.endRelOffset.x,
+ change.endRelOffset.y,
+ change.endAbsBounds.width(),
+ change.endAbsBounds.height()
+ )
+ )
+ }
+ letterboxController.updateLetterboxSurfaceVisibility(
+ key,
+ startTransaction,
+ isTopActivityLetterboxed
+ )
+ }
+ letterboxController.dump()
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 77e041ee7cdb..60237502007d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -636,7 +636,7 @@ public abstract class WMShellBaseModule {
static Optional<FreeformComponents> provideFreeformComponents(
@DynamicOverride Optional<FreeformComponents> freeformComponents,
Context context) {
- if (FreeformComponents.isFreeformEnabled(context)) {
+ if (FreeformComponents.requiresFreeformComponents(context)) {
return freeformComponents;
}
return Optional.empty();
@@ -795,13 +795,14 @@ public abstract class WMShellBaseModule {
static KeyguardTransitionHandler provideKeyguardTransitionHandler(
ShellInit shellInit,
ShellController shellController,
+ DisplayController displayController,
Transitions transitions,
TaskStackListenerImpl taskStackListener,
@ShellMainThread Handler mainHandler,
@ShellMainThread ShellExecutor mainExecutor) {
return new KeyguardTransitionHandler(
- shellInit, shellController, transitions, taskStackListener, mainHandler,
- mainExecutor);
+ shellInit, shellController, displayController, transitions, taskStackListener,
+ mainHandler, mainExecutor);
}
@WMSingleton
@@ -991,7 +992,7 @@ public abstract class WMShellBaseModule {
// Lazy ensures that this provider will not be the cause the dependency is created
// when it will not be returned due to the condition below.
return desktopTasksController.flatMap((lazy) -> {
- if (DesktopModeStatus.canEnterDesktopMode(context)) {
+ if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) {
return Optional.of(lazy.get());
}
return Optional.empty();
@@ -1024,10 +1025,13 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static TaskStackTransitionObserver provideTaskStackTransitionObserver(
- Lazy<Transitions> transitions,
- ShellInit shellInit
+ ShellInit shellInit,
+ Lazy<ShellTaskOrganizer> shellTaskOrganizer,
+ ShellCommandHandler shellCommandHandler,
+ Lazy<Transitions> transitions
) {
- return new TaskStackTransitionObserver(transitions, shellInit);
+ return new TaskStackTransitionObserver(shellInit, shellTaskOrganizer, shellCommandHandler,
+ transitions);
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 601cf70b93ed..0f636588476a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -17,13 +17,19 @@
package com.android.wm.shell.dagger;
import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY;
import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
import static android.window.DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS;
+import static com.android.hardware.input.Flags.manageKeyGestures;
+import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.UserManager;
@@ -62,6 +68,9 @@ import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler;
+import com.android.wm.shell.compatui.letterbox.LetterboxController;
+import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver;
import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
import com.android.wm.shell.dagger.pip.PipModule;
import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler;
@@ -73,7 +82,9 @@ import com.android.wm.shell.desktopmode.DesktopImmersiveController;
import com.android.wm.shell.desktopmode.DesktopMixedTransitionHandler;
import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler;
import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
+import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler;
import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger;
import com.android.wm.shell.desktopmode.DesktopRepository;
import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -86,6 +97,7 @@ import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator;
import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler;
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
+import com.android.wm.shell.desktopmode.compatui.SystemModalsTransitionHandler;
import com.android.wm.shell.desktopmode.education.AppHandleEducationController;
import com.android.wm.shell.desktopmode.education.AppHandleEducationFilter;
import com.android.wm.shell.desktopmode.education.AppToWebEducationController;
@@ -278,57 +290,15 @@ public abstract class WMShellModule {
@ShellBackgroundThread ShellExecutor bgExecutor,
ShellInit shellInit,
IWindowManager windowManager,
- ShellCommandHandler shellCommandHandler,
ShellTaskOrganizer taskOrganizer,
- @DynamicOverride DesktopRepository desktopRepository,
DisplayController displayController,
- ShellController shellController,
- DisplayInsetsController displayInsetsController,
SyncTransactionQueue syncQueue,
Transitions transitions,
- Optional<DesktopTasksController> desktopTasksController,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
- InteractionJankMonitor interactionJankMonitor,
- AppToWebGenericLinksParser genericLinksParser,
- AssistContentRequester assistContentRequester,
- MultiInstanceHelper multiInstanceHelper,
- Optional<DesktopTasksLimiter> desktopTasksLimiter,
- AppHandleEducationController appHandleEducationController,
- AppToWebEducationController appToWebEducationController,
- WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
- Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler,
FocusTransitionObserver focusTransitionObserver,
- DesktopModeEventLogger desktopModeEventLogger) {
- if (DesktopModeStatus.canEnterDesktopMode(context)) {
- return new DesktopModeWindowDecorViewModel(
- context,
- mainExecutor,
- mainHandler,
- mainChoreographer,
- bgExecutor,
- shellInit,
- shellCommandHandler,
- windowManager,
- taskOrganizer,
- desktopRepository,
- displayController,
- shellController,
- displayInsetsController,
- syncQueue,
- transitions,
- desktopTasksController,
- rootTaskDisplayAreaOrganizer,
- interactionJankMonitor,
- genericLinksParser,
- assistContentRequester,
- multiInstanceHelper,
- desktopTasksLimiter,
- appHandleEducationController,
- appToWebEducationController,
- windowDecorCaptionHandleRepository,
- desktopActivityOrientationHandler,
- focusTransitionObserver,
- desktopModeEventLogger);
+ Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel) {
+ if (desktopModeWindowDecorViewModel.isPresent()) {
+ return desktopModeWindowDecorViewModel.get();
}
return new CaptionWindowDecorViewModel(
context,
@@ -398,7 +368,7 @@ public abstract class WMShellModule {
Optional<TaskChangeListener> taskChangeListener) {
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
// override for this controller from the base module
- ShellInit init = FreeformComponents.isFreeformEnabled(context) ? shellInit : null;
+ ShellInit init = FreeformComponents.requiresFreeformComponents(context) ? shellInit : null;
return new FreeformTaskListener(
context,
init,
@@ -733,6 +703,7 @@ public abstract class WMShellModule {
InputManager inputManager,
FocusTransitionObserver focusTransitionObserver,
DesktopModeEventLogger desktopModeEventLogger,
+ DesktopModeUiEventLogger desktopModeUiEventLogger,
DesktopTilingDecorViewModel desktopTilingDecorViewModel) {
return new DesktopTasksController(
context,
@@ -755,8 +726,6 @@ public abstract class WMShellModule {
dragToDesktopTransitionHandler,
desktopImmersiveController.get(),
desktopRepository,
- desktopModeLoggerTransitionObserver,
- launchAdjacentController,
recentsTransitionHandler,
multiInstanceHelper,
mainExecutor,
@@ -764,9 +733,8 @@ public abstract class WMShellModule {
recentTasksController.orElse(null),
interactionJankMonitor,
mainHandler,
- inputManager,
- focusTransitionObserver,
desktopModeEventLogger,
+ desktopModeUiEventLogger,
desktopTilingDecorViewModel);
}
@@ -843,7 +811,7 @@ public abstract class WMShellModule {
DisplayController displayController,
ShellTaskOrganizer shellTaskOrganizer,
ShellCommandHandler shellCommandHandler) {
- if (DesktopModeStatus.canEnterDesktopMode(context)) {
+ if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) {
return Optional.of(
new DesktopImmersiveController(
shellInit,
@@ -880,6 +848,93 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
+ static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler(
+ Context context,
+ Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel,
+ Optional<DesktopTasksController> desktopTasksController,
+ InputManager inputManager,
+ ShellTaskOrganizer shellTaskOrganizer,
+ FocusTransitionObserver focusTransitionObserver) {
+ if (DesktopModeStatus.canEnterDesktopMode(context) && useKeyGestureEventHandler()
+ && manageKeyGestures()
+ && (Flags.enableMoveToNextDisplayShortcut()
+ || Flags.enableTaskResizingKeyboardShortcuts())) {
+ return Optional.of(new DesktopModeKeyGestureHandler(context,
+ desktopModeWindowDecorViewModel, desktopTasksController,
+ inputManager, shellTaskOrganizer, focusTransitionObserver));
+ }
+ return Optional.empty();
+ }
+
+ @WMSingleton
+ @Provides
+ static Optional<DesktopModeWindowDecorViewModel> provideDesktopModeWindowDecorViewModel(
+ Context context,
+ @ShellMainThread ShellExecutor shellExecutor,
+ @ShellMainThread Handler mainHandler,
+ @ShellMainThread Choreographer mainChoreographer,
+ @ShellBackgroundThread ShellExecutor bgExecutor,
+ ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
+ IWindowManager windowManager,
+ ShellTaskOrganizer taskOrganizer,
+ @DynamicOverride DesktopRepository desktopRepository,
+ DisplayController displayController,
+ ShellController shellController,
+ DisplayInsetsController displayInsetsController,
+ SyncTransactionQueue syncQueue,
+ Transitions transitions,
+ Optional<DesktopTasksController> desktopTasksController,
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ InteractionJankMonitor interactionJankMonitor,
+ AppToWebGenericLinksParser genericLinksParser,
+ AssistContentRequester assistContentRequester,
+ MultiInstanceHelper multiInstanceHelper,
+ Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ AppHandleEducationController appHandleEducationController,
+ AppToWebEducationController appToWebEducationController,
+ WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
+ Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
+ FocusTransitionObserver focusTransitionObserver,
+ DesktopModeEventLogger desktopModeEventLogger,
+ DesktopModeUiEventLogger desktopModeUiEventLogger
+ ) {
+ if (!DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) {
+ return Optional.empty();
+ }
+ return Optional.of(new DesktopModeWindowDecorViewModel(context, shellExecutor, mainHandler,
+ mainChoreographer, bgExecutor, shellInit, shellCommandHandler, windowManager,
+ taskOrganizer, desktopRepository, displayController, shellController,
+ displayInsetsController, syncQueue, transitions, desktopTasksController,
+ rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
+ assistContentRequester, multiInstanceHelper, desktopTasksLimiter,
+ appHandleEducationController, appToWebEducationController,
+ windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
+ focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger));
+ }
+
+ @WMSingleton
+ @Provides
+ static Optional<SystemModalsTransitionHandler> provideSystemModalsTransitionHandler(
+ Context context,
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellAnimationThread ShellExecutor animExecutor,
+ ShellInit shellInit,
+ Transitions transitions,
+ @DynamicOverride DesktopRepository desktopRepository) {
+ if (!DesktopModeStatus.canEnterDesktopMode(context)
+ || !ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
+ || !Flags.enableDesktopSystemDialogsTransitions()) {
+ return Optional.empty();
+ }
+ return Optional.of(
+ new SystemModalsTransitionHandler(
+ context, mainExecutor, animExecutor, shellInit, transitions,
+ desktopRepository));
+ }
+
+ @WMSingleton
+ @Provides
static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler(
Transitions transitions,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
@@ -1004,7 +1059,8 @@ public abstract class WMShellModule {
ShellInit shellInit,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
) {
- if (!DesktopModeStatus.canEnterDesktopMode(context)) {
+ if (!DesktopModeStatus.canEnterDesktopMode(context)
+ && !DesktopModeStatus.overridesShowAppHandle(context)) {
return Optional.empty();
}
return Optional.of(
@@ -1179,6 +1235,15 @@ public abstract class WMShellModule {
mainScope);
}
+ @WMSingleton
+ @Provides
+ static DesktopModeUiEventLogger provideDesktopUiEventLogger(
+ UiEventLogger uiEventLogger,
+ PackageManager packageManager
+ ) {
+ return new DesktopModeUiEventLogger(uiEventLogger, packageManager);
+ }
+
//
// Drag and drop
//
@@ -1229,8 +1294,26 @@ public abstract class WMShellModule {
@Provides
static Object provideIndependentShellComponentsToCreate(
DragAndDropController dragAndDropController,
+ @NonNull LetterboxTransitionObserver letterboxTransitionObserver,
+ @NonNull LetterboxCommandHandler letterboxCommandHandler,
Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional,
- Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler) {
+ Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler,
+ Optional<DesktopModeKeyGestureHandler> desktopModeKeyGestureHandler,
+ Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler) {
return new Object();
}
+
+ //
+ // App Compat
+ //
+
+ @WMSingleton
+ @Provides
+ static LetterboxTransitionObserver provideLetterboxTransitionObserver(
+ @NonNull ShellInit shellInit,
+ @NonNull Transitions transitions,
+ @NonNull LetterboxController letterboxController
+ ) {
+ return new LetterboxTransitionObserver(shellInit, transitions, letterboxController);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
index 1acde73e68dc..4723eb273988 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
@@ -119,7 +119,8 @@ class DesktopImmersiveController(
)
}
- fun moveTaskToNonImmersive(taskInfo: RunningTaskInfo) {
+ /** Starts a transition to move an immersive task out of immersive. */
+ fun moveTaskToNonImmersive(taskInfo: RunningTaskInfo, reason: ExitReason) {
if (inProgress) {
logV(
"Cannot start exit because transition(s) already in progress: %s",
@@ -131,7 +132,7 @@ class DesktopImmersiveController(
val wct = WindowContainerTransaction().apply {
setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
}
- logV("Moving task ${taskInfo.taskId} out of immersive mode")
+ logV("Moving task %d out of immersive mode, reason: %s", taskInfo.taskId, reason)
val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ this)
state = TransitionState(
transition = transition,
@@ -151,10 +152,11 @@ class DesktopImmersiveController(
fun exitImmersiveIfApplicable(
transition: IBinder,
wct: WindowContainerTransaction,
- displayId: Int
+ displayId: Int,
+ reason: ExitReason,
) {
if (!Flags.enableFullyImmersiveInDesktop()) return
- val result = exitImmersiveIfApplicable(wct, displayId)
+ val result = exitImmersiveIfApplicable(wct, displayId, excludeTaskId = null, reason)
result.asExit()?.runOnTransitionStart?.invoke(transition)
}
@@ -170,6 +172,7 @@ class DesktopImmersiveController(
wct: WindowContainerTransaction,
displayId: Int,
excludeTaskId: Int? = null,
+ reason: ExitReason,
): ExitResult {
if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
val immersiveTask = desktopRepository.getTaskInFullImmersiveState(displayId)
@@ -179,7 +182,10 @@ class DesktopImmersiveController(
}
val taskInfo = shellTaskOrganizer.getRunningTaskInfo(immersiveTask)
?: return ExitResult.NoExit
- logV("Appending immersive exit for task: $immersiveTask in display: $displayId")
+ logV(
+ "Appending immersive exit for task: %d in display: %d for reason: %s",
+ immersiveTask, displayId, reason
+ )
wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
return ExitResult.Exit(
exitingTask = immersiveTask,
@@ -198,14 +204,15 @@ class DesktopImmersiveController(
*/
fun exitImmersiveIfApplicable(
wct: WindowContainerTransaction,
- taskInfo: RunningTaskInfo
+ taskInfo: RunningTaskInfo,
+ reason: ExitReason,
): ExitResult {
if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
// A full immersive task is being minimized, make sure the immersive state is broken
// (i.e. resize back to max bounds).
wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
- logV("Appending immersive exit for task: ${taskInfo.taskId}")
+ logV("Appending immersive exit for task: %d for reason: %s", taskInfo.taskId, reason)
return ExitResult.Exit(
exitingTask = taskInfo.taskId,
runOnTransitionStart = { transition ->
@@ -550,6 +557,15 @@ class DesktopImmersiveController(
ENTER, EXIT
}
+ /** The reason for moving the task out of desktop immersive mode. */
+ enum class ExitReason {
+ APP_NOT_IMMERSIVE, // The app stopped requesting immersive treatment.
+ USER_INTERACTION, // Explicit user intent request, e.g. a button click.
+ TASK_LAUNCH, // A task launched/moved on top of the immersive task.
+ MINIMIZED, // The immersive task was minimized.
+ CLOSED, // The immersive task was closed.
+ }
+
private fun logV(msg: String, vararg arguments: Any?) {
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
index 2001f9743094..82c2ebc7ec77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
@@ -23,6 +23,7 @@ import android.os.Handler
import android.os.IBinder
import android.view.SurfaceControl
import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_OPEN
import android.window.DesktopModeFlags
import android.window.TransitionInfo
import android.window.TransitionInfo.Change
@@ -95,7 +96,7 @@ class DesktopMixedTransitionHandler(
fun startLaunchTransition(
@WindowManager.TransitionType transitionType: Int,
wct: WindowContainerTransaction,
- taskId: Int,
+ taskId: Int?,
minimizingTaskId: Int? = null,
exitingImmersiveTask: Int? = null,
): IBinder {
@@ -216,12 +217,12 @@ class DesktopMixedTransitionHandler(
): Boolean {
// Check if there's also an immersive change during this launch.
val immersiveExitChange = pending.exitingImmersiveTask?.let { exitingTask ->
- findDesktopTaskChange(info, exitingTask)
+ findTaskChange(info, exitingTask)
}
val minimizeChange = pending.minimizingTask?.let { minimizingTask ->
- findDesktopTaskChange(info, minimizingTask)
+ findTaskChange(info, minimizingTask)
}
- val launchChange = findDesktopTaskChange(info, pending.launchingTask)
+ val launchChange = findDesktopTaskLaunchChange(info, pending.launchingTask)
if (launchChange == null) {
check(minimizeChange == null)
check(immersiveExitChange == null)
@@ -291,7 +292,7 @@ class DesktopMixedTransitionHandler(
): Boolean {
if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue) return false
- val minimizeChange = findDesktopTaskChange(info, pending.minimizingTask)
+ val minimizeChange = findTaskChange(info, pending.minimizingTask)
if (minimizeChange == null) {
logW("Should have minimizing desktop task")
return false
@@ -417,8 +418,24 @@ class DesktopMixedTransitionHandler(
}
}
- private fun findDesktopTaskChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? {
- return info.changes.firstOrNull { change -> change.taskInfo?.taskId == taskId }
+ private fun findTaskChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? =
+ info.changes.firstOrNull { change -> change.taskInfo?.taskId == taskId }
+
+ private fun findDesktopTaskLaunchChange(
+ info: TransitionInfo,
+ launchTaskId: Int?
+ ): TransitionInfo.Change? {
+ return if (launchTaskId != null) {
+ // Launching a known task (probably from background or moving to front), so
+ // specifically look for it.
+ findTaskChange(info, launchTaskId)
+ } else {
+ // Launching a new task, so the first opening freeform task.
+ info.changes.firstOrNull { change ->
+ change.mode == TRANSIT_OPEN
+ && change.taskInfo != null && change.taskInfo!!.isFreeform
+ }
+ }
}
private fun WindowContainerTransaction?.merge(
@@ -441,7 +458,7 @@ class DesktopMixedTransitionHandler(
/** A task is opening or moving to front. */
data class Launch(
override val transition: IBinder,
- val launchingTask: Int,
+ val launchingTask: Int?,
val minimizingTask: Int?,
val exitingImmersiveTask: Int?,
) : PendingMixedTransition()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
index 39586e39fdd4..dc23128b7b2a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -187,8 +187,10 @@ class DesktopModeEventLogger {
*/
fun logTaskResizingStarted(
resizeTrigger: ResizeTrigger,
- motionEvent: MotionEvent?,
+ inputMethod: InputMethod,
taskInfo: RunningTaskInfo,
+ taskWidth: Int? = null,
+ taskHeight: Int? = null,
displayController: DisplayController? = null,
displayLayoutSize: Size? = null,
) {
@@ -205,8 +207,10 @@ class DesktopModeEventLogger {
val taskSizeUpdate = createTaskSizeUpdate(
resizeTrigger,
- motionEvent,
+ inputMethod,
taskInfo,
+ taskWidth,
+ taskHeight,
displayController = displayController,
displayLayoutSize = displayLayoutSize,
)
@@ -228,10 +232,10 @@ class DesktopModeEventLogger {
*/
fun logTaskResizingEnded(
resizeTrigger: ResizeTrigger,
- motionEvent: MotionEvent?,
+ inputMethod: InputMethod,
taskInfo: RunningTaskInfo,
- taskHeight: Int? = null,
taskWidth: Int? = null,
+ taskHeight: Int? = null,
displayController: DisplayController? = null,
displayLayoutSize: Size? = null,
) {
@@ -248,10 +252,10 @@ class DesktopModeEventLogger {
val taskSizeUpdate = createTaskSizeUpdate(
resizeTrigger,
- motionEvent,
+ inputMethod,
taskInfo,
- taskHeight,
taskWidth,
+ taskHeight,
displayController,
displayLayoutSize,
)
@@ -271,10 +275,10 @@ class DesktopModeEventLogger {
private fun createTaskSizeUpdate(
resizeTrigger: ResizeTrigger,
- motionEvent: MotionEvent?,
+ inputMethod: InputMethod,
taskInfo: RunningTaskInfo,
- taskHeight: Int? = null,
taskWidth: Int? = null,
+ taskHeight: Int? = null,
displayController: DisplayController? = null,
displayLayoutSize: Size? = null,
): TaskSizeUpdate {
@@ -292,7 +296,7 @@ class DesktopModeEventLogger {
return TaskSizeUpdate(
resizeTrigger,
- getInputMethodFromMotionEvent(motionEvent),
+ inputMethod,
taskInfo.taskId,
taskInfo.effectiveUid,
height,
@@ -442,7 +446,8 @@ class DesktopModeEventLogger {
val displayArea: Int?,
)
- private fun getInputMethodFromMotionEvent(e: MotionEvent?): InputMethod {
+ @JvmStatic
+ fun getInputMethodFromMotionEvent(e: MotionEvent?): InputMethod {
if (e == null) return InputMethod.UNKNOWN_INPUT_METHOD
val toolType = e.getToolType(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
new file mode 100644
index 000000000000..6cb23b81f1e4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.hardware.input.KeyGestureEvent
+
+import android.hardware.input.InputManager
+import android.hardware.input.InputManager.KeyGestureEventHandler
+import android.os.IBinder
+import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
+import com.android.wm.shell.ShellTaskOrganizer
+import android.app.ActivityManager.RunningTaskInfo
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
+import com.android.internal.protolog.ProtoLog
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.Context
+import com.android.hardware.input.Flags.manageKeyGestures
+import com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.transition.FocusTransitionObserver
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import java.util.Optional
+
+/**
+ * Handles key gesture events (keyboard shortcuts) in Desktop Mode.
+ */
+class DesktopModeKeyGestureHandler(
+ private val context: Context,
+ private val desktopModeWindowDecorViewModel: Optional<DesktopModeWindowDecorViewModel>,
+ private val desktopTasksController: Optional<DesktopTasksController>,
+ inputManager: InputManager,
+ private val shellTaskOrganizer: ShellTaskOrganizer,
+ private val focusTransitionObserver: FocusTransitionObserver,
+ ) : KeyGestureEventHandler {
+
+ init {
+ inputManager.registerKeyGestureEventHandler(this)
+ }
+
+ override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?): Boolean {
+ if (!isKeyGestureSupported(event.keyGestureType) || !desktopTasksController.isPresent
+ || !desktopModeWindowDecorViewModel.isPresent) {
+ return false
+ }
+ when (event.keyGestureType) {
+ KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> {
+ logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
+ getGloballyFocusedFreeformTask()?.let {
+ desktopTasksController.get().moveToNextDisplay(
+ it.taskId
+ )
+ }
+ return true
+ }
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW -> {
+ logV("Key gesture SNAP_LEFT_FREEFORM_WINDOW is handled")
+ getGloballyFocusedFreeformTask()?.let {
+ desktopModeWindowDecorViewModel.get().onSnapResize(
+ it.taskId,
+ true,
+ DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
+ )
+ }
+ return true
+ }
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW -> {
+ logV("Key gesture SNAP_RIGHT_FREEFORM_WINDOW is handled")
+ getGloballyFocusedFreeformTask()?.let {
+ desktopModeWindowDecorViewModel.get().onSnapResize(
+ it.taskId,
+ false,
+ DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
+ )
+ }
+ return true
+ }
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW -> {
+ logV("Key gesture TOGGLE_MAXIMIZE_FREEFORM_WINDOW is handled")
+ getGloballyFocusedFreeformTask()?.let {
+ desktopTasksController.get().toggleDesktopTaskSize(
+ it,
+ ResizeTrigger.MAXIMIZE_MENU,
+ DesktopModeEventLogger.Companion.InputMethod.KEYBOARD,
+ )
+ }
+ return true
+ }
+ KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW -> {
+ logV("Key gesture MINIMIZE_FREEFORM_WINDOW is handled")
+ getGloballyFocusedFreeformTask()?.let {
+ desktopTasksController.get().minimizeTask(
+ it,
+ )
+ }
+ return true
+ }
+ else -> return false
+ }
+ }
+
+ override fun isKeyGestureSupported(gestureType: Int): Boolean = when (gestureType) {
+ KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY
+ -> enableMoveToNextDisplayShortcut()
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW
+ -> enableTaskResizingKeyboardShortcuts() && manageKeyGestures()
+ else -> false
+ }
+
+ // TODO: b/364154795 - wait for the completion of moveToNextDisplay transition, otherwise it
+ // will pick a wrong task when a user quickly perform other actions with keyboard shortcuts
+ // after moveToNextDisplay, and move this to FocusTransitionObserver class.
+ private fun getGloballyFocusedFreeformTask(): RunningTaskInfo? =
+ shellTaskOrganizer.getRunningTasks().find { taskInfo ->
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
+ focusTransitionObserver.hasGlobalFocus(taskInfo)
+ }
+
+ private fun logV(msg: String, vararg arguments: Any?) {
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
+ companion object {
+ private const val TAG = "DesktopModeKeyGestureHandler"
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
index a9d4e5f3216e..d0e01625a3aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
@@ -16,22 +16,23 @@
package com.android.wm.shell.desktopmode
-import android.util.Log
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.pm.PackageManager
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
-import com.android.wm.shell.dagger.WMSingleton
-import javax.inject.Inject
+import com.android.internal.logging.UiEventLogger.UiEventEnum
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
/** Log Aster UIEvents for desktop windowing mode. */
-@WMSingleton
-class DesktopModeUiEventLogger
-@Inject
-constructor(
- private val mUiEventLogger: UiEventLogger,
- private val mInstanceIdSequence: InstanceIdSequence
+class DesktopModeUiEventLogger(
+ private val uiEventLogger: UiEventLogger,
+ private val packageManager: PackageManager,
) {
+ private val instanceIdSequence = InstanceIdSequence(Integer.MAX_VALUE)
+
/**
* Logs an event for a CUI, on a particular package.
*
@@ -41,14 +42,25 @@ constructor(
*/
fun log(uid: Int, packageName: String, event: DesktopUiEventEnum) {
if (packageName.isEmpty() || uid < 0) {
- Log.d(TAG, "Skip logging since package name is empty or bad uid")
+ logD("Skip logging since package name is empty or bad uid")
return
}
- mUiEventLogger.log(event, uid, packageName)
+ uiEventLogger.log(event, uid, packageName)
+ }
+
+ /** Logs an event for a CUI on a particular task. */
+ fun log(taskInfo: RunningTaskInfo, event: DesktopUiEventEnum) {
+ val packageName = taskInfo.baseActivity?.packageName
+ if (packageName == null) {
+ logD("Skip logging due to null base activity")
+ return
+ }
+ val uid = getUid(packageName, taskInfo.userId)
+ log(uid, packageName, event)
}
/** Retrieves a new instance id for a new interaction. */
- fun getNewInstanceId(): InstanceId = mInstanceIdSequence.newInstanceId()
+ fun getNewInstanceId(): InstanceId = instanceIdSequence.newInstanceId()
/**
* Logs an event as part of a particular CUI, on a particular package.
@@ -66,28 +78,59 @@ constructor(
event: DesktopUiEventEnum
) {
if (packageName.isEmpty() || uid < 0) {
- Log.d(TAG, "Skip logging since package name is empty or bad uid")
+ logD("Skip logging since package name is empty or bad uid")
return
}
- mUiEventLogger.logWithInstanceId(event, uid, packageName, instanceId)
+ uiEventLogger.logWithInstanceId(event, uid, packageName, instanceId)
}
- companion object {
- /** Enums for logging desktop windowing mode UiEvents. */
- enum class DesktopUiEventEnum(private val mId: Int) : UiEventLogger.UiEventEnum {
+ private fun getUid(packageName: String, userId: Int): Int = try {
+ packageManager.getApplicationInfoAsUser(packageName, /* flags= */ 0, userId).uid
+ } catch (e: PackageManager.NameNotFoundException) {
+ INVALID_PACKAGE_UID
+ }
- @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the edge")
- DESKTOP_WINDOW_EDGE_DRAG_RESIZE(1721),
- @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the corner")
- DESKTOP_WINDOW_CORNER_DRAG_RESIZE(1722),
- @UiEvent(doc = "Tap on the window header maximize button in desktop windowing mode")
- DESKTOP_WINDOW_MAXIMIZE_BUTTON_TAP(1723),
- @UiEvent(doc = "Double tap on window header to maximize it in desktop windowing mode")
- DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE(1724);
+ private fun logD(msg: String, vararg arguments: Any?) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
- override fun getId(): Int = mId
- }
+ /** Enums for logging desktop windowing mode UiEvents. */
+ enum class DesktopUiEventEnum(private val mId: Int) : UiEventEnum {
+
+ @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the edge")
+ DESKTOP_WINDOW_EDGE_DRAG_RESIZE(1721),
+ @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the corner")
+ DESKTOP_WINDOW_CORNER_DRAG_RESIZE(1722),
+ @UiEvent(doc = "Tap on the window header maximize button in desktop windowing mode")
+ DESKTOP_WINDOW_MAXIMIZE_BUTTON_TAP(1723),
+ @UiEvent(doc = "Double tap on window header to maximize it in desktop windowing mode")
+ DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE(1724),
+ @UiEvent(doc = "Tap on the window Handle to open the Handle Menu")
+ DESKTOP_WINDOW_APP_HANDLE_TAP(1998),
+ @UiEvent(doc = "Tap on the desktop mode option under app handle menu")
+ DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_DESKTOP_MODE(1999),
+ @UiEvent(doc = "Tap on the split screen option under app handle menu")
+ DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_SPLIT_SCREEN(2000),
+ @UiEvent(doc = "Tap on the full screen option under app handle menu")
+ DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_FULL_SCREEN(2001),
+ @UiEvent(doc = "When user successfully drags the app handle to desktop mode")
+ DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_DESKTOP_MODE(2002),
+ @UiEvent(doc = "When user successfully drags the app handle to split screen")
+ DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN(2003),
+ @UiEvent(doc = "When user successfully drags the app handle to full screen")
+ DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_FULL_SCREEN(2004),
+ @UiEvent(doc = "Drag the window header to the top to switch to full screen mode")
+ DESKTOP_WINDOW_APP_HEADER_DRAG_TO_FULL_SCREEN(2005),
+ @UiEvent(doc = "Drag the window header to an edge to tile it to the left side")
+ DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_LEFT(2006),
+ @UiEvent(doc = "Drag the window header to an edge to tile it to the right side")
+ DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_RIGHT(2007);
+ override fun getId(): Int = mId
+ }
+
+ companion object {
private const val TAG = "DesktopModeUiEventLogger"
+ private const val INVALID_PACKAGE_UID = -1
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 09e77fee7527..80d8ecc127fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -120,6 +120,7 @@ public class DesktopModeVisualIndicator {
private View mView;
private IndicatorType mCurrentType;
private DragStartState mDragStartState;
+ private boolean mIsReleased;
public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue,
ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController,
@@ -240,6 +241,7 @@ public class DesktopModeVisualIndicator {
* Create a fullscreen indicator with no animation
*/
private void createView() {
+ if (mIsReleased) return;
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
final Resources resources = mContext.getResources();
final DisplayMetrics metrics = resources.getDisplayMetrics();
@@ -295,6 +297,12 @@ public class DesktopModeVisualIndicator {
* @param finishCallback called when animation ends or gets cancelled
*/
void fadeOutIndicator(@Nullable Runnable finishCallback) {
+ if (mCurrentType == NO_INDICATOR) {
+ // In rare cases, fade out can be requested before the indicator has determined its
+ // initial type and started animating in. In this case, no animator is needed.
+ finishCallback.run();
+ return;
+ }
final VisualIndicatorAnimator animator = VisualIndicatorAnimator
.fadeBoundsOut(mView, mCurrentType,
mDisplayController.getDisplayLayout(mTaskInfo.displayId));
@@ -335,6 +343,7 @@ public class DesktopModeVisualIndicator {
* Release the indicator and its components when it is no longer needed.
*/
public void releaseVisualIndicator(SurfaceControl.Transaction t) {
+ mIsReleased = true;
if (mViewHost == null) return;
if (mViewHost != null) {
mViewHost.release();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 08ca55f93e3f..7fcb7678f6af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -411,6 +411,12 @@ class DesktopRepository (
desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder?.toDumpString())
// Remove task from unminimized task if it is minimized.
unminimizeTask(displayId, taskId)
+ // Mark task as not in immersive if it was immersive.
+ setTaskInFullImmersiveState(
+ displayId = displayId,
+ taskId = taskId,
+ immersive = false
+ )
removeActiveTask(taskId)
removeVisibleTask(taskId)
if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
@@ -487,6 +493,9 @@ class DesktopRepository (
mainCoroutineScope.launch {
try {
persistentRepository.addOrUpdateDesktop(
+ // Use display id as desktop id for now since only once desktop per display
+ // is supported.
+ desktopId = displayId,
visibleTasks = desktopTaskDataByDisplayIdCopy.visibleTasks,
minimizedTasks = desktopTaskDataByDisplayIdCopy.minimizedTasks,
freeformTasksInZOrder = desktopTaskDataByDisplayIdCopy.freeformTasksInZOrder
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 7446b88e2507..3e3dd74ae4b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -35,9 +35,6 @@ import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.Region
-import android.hardware.input.InputManager
-import android.hardware.input.InputManager.KeyGestureEventHandler
-import android.hardware.input.KeyGestureEvent
import android.os.Binder
import android.os.Handler
import android.os.IBinder
@@ -46,7 +43,6 @@ import android.os.UserHandle
import android.util.Size
import android.view.Display.DEFAULT_DISPLAY
import android.view.DragEvent
-import android.view.KeyEvent
import android.view.MotionEvent
import android.view.SurfaceControl
import android.view.SurfaceControl.Transaction
@@ -66,7 +62,6 @@ import android.window.TransitionInfo.Change
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
import androidx.annotation.BinderThread
-import com.android.hardware.input.Flags.useKeyGestureEventHandler
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
@@ -75,13 +70,13 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
-import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
+import com.android.wm.shell.Flags.enableFlexibleSplit
+import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.common.ExternalInterfaceBinder
-import com.android.wm.shell.common.LaunchAdjacentController
import com.android.wm.shell.common.MultiInstanceHelper
import com.android.wm.shell.common.MultiInstanceHelper.Companion.getComponent
import com.android.wm.shell.common.RemoteCallable
@@ -89,7 +84,6 @@ import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SingleInstanceRemoteListener
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
-import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
import com.android.wm.shell.desktopmode.DesktopRepository.VisibleTasksListener
@@ -109,6 +103,7 @@ import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useDesktopOverrideDensity
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
import com.android.wm.shell.splitscreen.SplitScreenController
@@ -117,7 +112,6 @@ import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.sysui.UserChangeListener
-import com.android.wm.shell.transition.FocusTransitionObserver
import com.android.wm.shell.transition.OneShotRemoteHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback
@@ -134,7 +128,15 @@ import java.io.PrintWriter
import java.util.Optional
import java.util.concurrent.Executor
import java.util.function.Consumer
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
+import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
+import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
+import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
+import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransitionState
+import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING
+
/** Handles moving tasks in and out of desktop */
class DesktopTasksController(
private val context: Context,
@@ -157,8 +159,6 @@ class DesktopTasksController(
private val dragToDesktopTransitionHandler: DragToDesktopTransitionHandler,
private val desktopImmersiveController: DesktopImmersiveController,
private val taskRepository: DesktopRepository,
- private val desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver,
- private val launchAdjacentController: LaunchAdjacentController,
private val recentsTransitionHandler: RecentsTransitionHandler,
private val multiInstanceHelper: MultiInstanceHelper,
@ShellMainThread private val mainExecutor: ShellExecutor,
@@ -166,16 +166,14 @@ class DesktopTasksController(
private val recentTasksController: RecentTasksController?,
private val interactionJankMonitor: InteractionJankMonitor,
@ShellMainThread private val handler: Handler,
- private val inputManager: InputManager,
- private val focusTransitionObserver: FocusTransitionObserver,
private val desktopModeEventLogger: DesktopModeEventLogger,
+ private val desktopModeUiEventLogger: DesktopModeUiEventLogger,
private val desktopTilingDecorViewModel: DesktopTilingDecorViewModel,
) :
RemoteCallable<DesktopTasksController>,
Transitions.TransitionHandler,
DragAndDropController.DragAndDropListener,
- UserChangeListener,
- KeyGestureEventHandler {
+ UserChangeListener {
private val desktopMode: DesktopModeImpl
private var visualIndicator: DesktopModeVisualIndicator? = null
@@ -208,11 +206,16 @@ class DesktopTasksController(
@VisibleForTesting
var taskbarDesktopTaskListener: TaskbarDesktopTaskListener? = null
+ @VisibleForTesting
+ var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener? = null
+
/** Task id of the task currently being dragged from fullscreen/split. */
val draggingTaskId
get() = dragToDesktopTransitionHandler.draggingTaskId
- private var recentsAnimationRunning = false
+ @RecentsTransitionState
+ private var recentsTransitionState = TRANSITION_STATE_NOT_RUNNING
+
private lateinit var splitScreenController: SplitScreenController
lateinit var freeformTaskTransitionStarter: FreeformTaskTransitionStarter
// Launch cookie used to identify a drag and drop transition to fullscreen after it has begun.
@@ -241,17 +244,19 @@ class DesktopTasksController(
dragToDesktopTransitionHandler.dragToDesktopStateListener = dragToDesktopStateListener
recentsTransitionHandler.addTransitionStateListener(
object : RecentsTransitionStateListener {
- override fun onAnimationStateChanged(running: Boolean) {
- logV("Recents animation state changed running=%b", running)
- recentsAnimationRunning = running
- desktopTilingDecorViewModel.onOverviewAnimationStateChange(running)
+ override fun onTransitionStateChanged(@RecentsTransitionState state: Int) {
+ logV(
+ "Recents transition state changed: %s",
+ RecentsTransitionStateListener.stateToString(state)
+ )
+ recentsTransitionState = state
+ desktopTilingDecorViewModel.onOverviewAnimationStateChange(
+ RecentsTransitionStateListener.isAnimating(state)
+ )
}
}
)
dragAndDropController.addListener(this)
- if (useKeyGestureEventHandler() && enableMoveToNextDisplayShortcut()) {
- inputManager.registerKeyGestureEventHandler(this)
- }
}
@VisibleForTesting
@@ -387,6 +392,7 @@ class DesktopTasksController(
wct = wct,
displayId = DEFAULT_DISPLAY,
excludeTaskId = taskId,
+ reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
)
wct.startTask(
taskId,
@@ -396,6 +402,7 @@ class DesktopTasksController(
)
// TODO(343149901): Add DPI changes for task launch
val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
+ desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
return true
@@ -418,6 +425,7 @@ class DesktopTasksController(
wct = wct,
displayId = task.displayId,
excludeTaskId = task.taskId,
+ reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
)
// Bring other apps to front first
val taskIdToMinimize =
@@ -425,6 +433,7 @@ class DesktopTasksController(
addMoveToDesktopChanges(wct, task)
val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
+ desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
}
@@ -464,8 +473,15 @@ class DesktopTasksController(
bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId)
addMoveToDesktopChanges(wct, taskInfo)
val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
- wct, taskInfo.displayId)
+ wct = wct,
+ displayId = taskInfo.displayId,
+ excludeTaskId = null,
+ reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH
+ )
val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct)
+ desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
+ DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS.toInt()
+ )
transition?.let {
taskIdToMinimize?.let { taskId -> addPendingMinimizeTransition(it, taskId) }
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
@@ -501,9 +517,7 @@ class DesktopTasksController(
): ((IBinder) -> Unit)? {
val taskId = taskInfo.taskId
desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId)
- if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
- removeWallpaperActivity(wct)
- }
+ performDesktopExitCleanupIfNeeded(taskId, wct)
taskRepository.addClosingTask(displayId, taskId)
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
doesAnyTaskRequireTaskbarRounding(
@@ -511,21 +525,24 @@ class DesktopTasksController(
taskId
)
)
- return desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo).asExit()
- ?.runOnTransitionStart
+ return desktopImmersiveController.exitImmersiveIfApplicable(
+ wct = wct,
+ taskInfo = taskInfo,
+ reason = DesktopImmersiveController.ExitReason.CLOSED
+ ).asExit()?.runOnTransitionStart
}
fun minimizeTask(taskInfo: RunningTaskInfo) {
val taskId = taskInfo.taskId
val displayId = taskInfo.displayId
val wct = WindowContainerTransaction()
- if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
- // Perform clean up of the desktop wallpaper activity if the minimized window task is
- // the last active task.
- removeWallpaperActivity(wct)
- }
+ performDesktopExitCleanupIfNeeded(taskId, wct)
// Notify immersive handler as it might need to exit immersive state.
- val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo)
+ val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
+ wct = wct,
+ taskInfo = taskInfo,
+ reason = DesktopImmersiveController.ExitReason.MINIMIZED
+ )
wct.reorder(taskInfo.token, false)
val transition = freeformTaskTransitionStarter.startMinimizedModeTransition(wct)
@@ -592,6 +609,11 @@ class DesktopTasksController(
position,
mOnAnimationFinishedCallback
)
+
+ // handles case where we are moving to full screen without closing all DW tasks.
+ if (!taskRepository.isOnlyVisibleNonClosingTask(task.taskId)) {
+ desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+ }
}
/**
@@ -618,25 +640,18 @@ class DesktopTasksController(
private fun moveBackgroundTaskToFront(taskId: Int, remoteTransition: RemoteTransition?) {
logV("moveBackgroundTaskToFront taskId=%s", taskId)
val wct = WindowContainerTransaction()
- // TODO: b/342378842 - Instead of using default display, support multiple displays
- val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
- wct = wct,
- displayId = DEFAULT_DISPLAY,
- excludeTaskId = taskId,
- )
wct.startTask(
taskId,
ActivityOptions.makeBasic().apply {
launchWindowingMode = WINDOWING_MODE_FREEFORM
}.toBundle(),
)
- val transition = startLaunchTransition(
+ startLaunchTransition(
TRANSIT_OPEN,
wct,
taskId,
remoteTransition = remoteTransition
)
- exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
}
/**
@@ -655,47 +670,54 @@ class DesktopTasksController(
}
val wct = WindowContainerTransaction()
wct.reorder(taskInfo.token, true /* onTop */, true /* includingParents */)
- val result = desktopImmersiveController.exitImmersiveIfApplicable(
- wct = wct,
- displayId = taskInfo.displayId,
- excludeTaskId = taskInfo.taskId,
- )
- val exitResult = if (result is ExitResult.Exit) { result } else { null }
- val transition = startLaunchTransition(
+ startLaunchTransition(
transitionType = TRANSIT_TO_FRONT,
wct = wct,
- taskId = taskInfo.taskId,
- exitingImmersiveTask = exitResult?.exitingTask,
+ launchingTaskId = taskInfo.taskId,
remoteTransition = remoteTransition,
displayId = taskInfo.displayId,
)
- exitResult?.runOnTransitionStart?.invoke(transition)
}
private fun startLaunchTransition(
transitionType: Int,
wct: WindowContainerTransaction,
- taskId: Int,
- exitingImmersiveTask: Int? = null,
+ launchingTaskId: Int?,
remoteTransition: RemoteTransition? = null,
displayId: Int = DEFAULT_DISPLAY,
): IBinder {
- val taskIdToMinimize = addAndGetMinimizeChanges(displayId, wct, taskId)
+ val taskIdToMinimize = if (launchingTaskId != null) {
+ addAndGetMinimizeChanges(displayId, wct, newTaskId = launchingTaskId)
+ } else {
+ logW("Starting desktop task launch without checking the task-limit")
+ // TODO(b/378920066): This currently does not respect the desktop window limit.
+ // It's possible that |launchingTaskId| is null when launching using an intent, and
+ // the task-limit should be respected then too.
+ null
+ }
+ val exitImmersiveResult = desktopImmersiveController.exitImmersiveIfApplicable(
+ wct = wct,
+ displayId = displayId,
+ excludeTaskId = launchingTaskId,
+ reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
+ )
if (remoteTransition == null) {
val t = desktopMixedTransitionHandler.startLaunchTransition(
transitionType = transitionType,
wct = wct,
- taskId = taskId,
+ taskId = launchingTaskId,
minimizingTaskId = taskIdToMinimize,
- exitingImmersiveTask = exitingImmersiveTask,
+ exitingImmersiveTask = exitImmersiveResult.asExit()?.exitingTask,
)
taskIdToMinimize?.let { addPendingMinimizeTransition(t, it) }
+ exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
return t
}
if (taskIdToMinimize == null) {
val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition)
val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
remoteTransitionHandler.setTransition(t)
+ exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
return t
}
val remoteTransitionHandler =
@@ -704,6 +726,7 @@ class DesktopTasksController(
val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
remoteTransitionHandler.setTransition(t)
taskIdToMinimize.let { addPendingMinimizeTransition(t, it) }
+ exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
return t
}
@@ -768,7 +791,10 @@ class DesktopTasksController(
/** Moves a task in/out of full immersive state within the desktop. */
fun toggleDesktopTaskFullImmersiveState(taskInfo: RunningTaskInfo) {
if (taskRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
- exitDesktopTaskFromFullImmersive(taskInfo)
+ exitDesktopTaskFromFullImmersive(
+ taskInfo,
+ DesktopImmersiveController.ExitReason.USER_INTERACTION,
+ )
} else {
moveDesktopTaskToFullImmersive(taskInfo)
}
@@ -779,9 +805,12 @@ class DesktopTasksController(
desktopImmersiveController.moveTaskToImmersive(taskInfo)
}
- private fun exitDesktopTaskFromFullImmersive(taskInfo: RunningTaskInfo) {
+ private fun exitDesktopTaskFromFullImmersive(
+ taskInfo: RunningTaskInfo,
+ reason: DesktopImmersiveController.ExitReason,
+ ) {
check(taskInfo.isFreeform) { "Task must already be in freeform" }
- desktopImmersiveController.moveTaskToNonImmersive(taskInfo)
+ desktopImmersiveController.moveTaskToNonImmersive(taskInfo, reason)
}
/**
@@ -792,12 +821,21 @@ class DesktopTasksController(
fun toggleDesktopTaskSize(
taskInfo: RunningTaskInfo,
resizeTrigger: ResizeTrigger,
- motionEvent: MotionEvent?,
+ inputMethod: InputMethod,
) {
+ val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
+ desktopModeEventLogger.logTaskResizingStarted(
+ resizeTrigger,
+ inputMethod,
+ taskInfo,
+ currentTaskBounds.width(),
+ currentTaskBounds.height(),
+ displayController
+ )
+
val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
- val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
val destinationBounds = Rect()
val isMaximized = isTaskMaximized(taskInfo, stableBounds)
@@ -841,8 +879,9 @@ class DesktopTasksController(
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding)
val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
desktopModeEventLogger.logTaskResizingEnded(
- resizeTrigger, motionEvent, taskInfo, destinationBounds.height(),
- destinationBounds.width(), displayController
+ resizeTrigger, inputMethod,
+ taskInfo, destinationBounds.width(),
+ destinationBounds.height(), displayController
)
toggleResizeDesktopTaskTransitionHandler.startTransition(wct)
}
@@ -872,10 +911,11 @@ class DesktopTasksController(
return
}
- desktopModeEventLogger.logTaskResizingStarted(
- ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent, taskInfo, displayController
+ toggleDesktopTaskSize(
+ taskInfo,
+ ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER,
+ DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent)
)
- toggleDesktopTaskSize(taskInfo, ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent)
}
private fun getMaximizeBounds(taskInfo: RunningTaskInfo, stableBounds: Rect): Rect {
@@ -962,13 +1002,32 @@ class DesktopTasksController(
*/
fun snapToHalfScreen(
taskInfo: RunningTaskInfo,
- taskSurface: SurfaceControl,
+ taskSurface: SurfaceControl?,
currentDragBounds: Rect,
position: SnapPosition,
resizeTrigger: ResizeTrigger,
- motionEvent: MotionEvent?,
+ inputMethod: InputMethod,
desktopWindowDecoration: DesktopModeWindowDecoration,
) {
+ desktopModeEventLogger.logTaskResizingStarted(
+ resizeTrigger,
+ inputMethod,
+ taskInfo,
+ currentDragBounds.width(),
+ currentDragBounds.height(),
+ displayController
+ )
+
+ val destinationBounds = getSnapBounds(taskInfo, position)
+ desktopModeEventLogger.logTaskResizingEnded(
+ resizeTrigger,
+ inputMethod,
+ taskInfo,
+ destinationBounds.width(),
+ destinationBounds.height(),
+ displayController,
+ )
+
if (DesktopModeFlags.ENABLE_TILE_RESIZING.isTrue()) {
val isTiled = desktopTilingDecorViewModel.snapToHalfScreen(
taskInfo,
@@ -981,20 +1040,12 @@ class DesktopTasksController(
}
return
}
- val destinationBounds = getSnapBounds(taskInfo, position)
- desktopModeEventLogger.logTaskResizingEnded(
- resizeTrigger,
- motionEvent,
- taskInfo,
- destinationBounds.height(),
- destinationBounds.width(),
- displayController,
- )
+
if (destinationBounds == taskInfo.configuration.windowConfiguration.bounds) {
// Handle the case where we attempt to snap resize when already snap resized: the task
// position won't need to change but we want to animate the surface going back to the
// snapped position from the "dragged-to-the-edge" position.
- if (destinationBounds != currentDragBounds) {
+ if (destinationBounds != currentDragBounds && taskSurface != null) {
returnToDragStartAnimator.start(
taskInfo.taskId,
taskSurface,
@@ -1011,8 +1062,40 @@ class DesktopTasksController(
toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds)
}
+ /**
+ * Handles snap resizing a [taskInfo] to [position] instantaneously, for example when the
+ * [resizeTrigger] is the snap resize menu using any [motionEvent] or a keyboard shortcut.
+ */
+ fun handleInstantSnapResizingTask(
+ taskInfo: RunningTaskInfo,
+ position: SnapPosition,
+ resizeTrigger: ResizeTrigger,
+ inputMethod: InputMethod,
+ desktopModeWindowDecoration: DesktopModeWindowDecoration,
+ ) {
+ if (!isSnapResizingAllowed(taskInfo)) {
+ Toast.makeText(
+ getContext(),
+ R.string.desktop_mode_non_resizable_snap_text,
+ Toast.LENGTH_SHORT
+ ).show()
+ return
+ }
+
+ snapToHalfScreen(
+ taskInfo,
+ null,
+ taskInfo.configuration.windowConfiguration.bounds,
+ position,
+ resizeTrigger,
+ inputMethod,
+ desktopModeWindowDecoration
+ )
+ }
+
+
@VisibleForTesting
- fun handleSnapResizingTask(
+ fun handleSnapResizingTaskOnDrag(
taskInfo: RunningTaskInfo,
position: SnapPosition,
taskSurface: SurfaceControl,
@@ -1022,7 +1105,7 @@ class DesktopTasksController(
desktopModeWindowDecoration: DesktopModeWindowDecoration,
) {
releaseVisualIndicator()
- if (!taskInfo.isResizeable && DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
+ if (!isSnapResizingAllowed(taskInfo)) {
interactionJankMonitor.begin(
taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_non_resizable"
)
@@ -1047,9 +1130,6 @@ class DesktopTasksController(
} else {
ResizeTrigger.DRAG_RIGHT
}
- desktopModeEventLogger.logTaskResizingStarted(
- resizeTrigger, motionEvent, taskInfo, displayController
- )
interactionJankMonitor.begin(
taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable"
)
@@ -1059,12 +1139,15 @@ class DesktopTasksController(
currentDragBounds,
position,
resizeTrigger,
- motionEvent,
+ DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent),
desktopModeWindowDecoration,
)
}
}
+ private fun isSnapResizingAllowed(taskInfo: RunningTaskInfo) =
+ taskInfo.isResizeable || !DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()
+
private fun getSnapBounds(taskInfo: RunningTaskInfo, position: SnapPosition): Rect {
val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return Rect()
@@ -1179,7 +1262,7 @@ class DesktopTasksController(
val userContext =
context.createContextAsUser(userHandle, /* flags= */ 0)
val intent = Intent(userContext, DesktopWallpaperActivity::class.java)
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId)
val options =
ActivityOptions.makeBasic().apply {
launchWindowingMode = WINDOWING_MODE_FULLSCREEN
@@ -1205,6 +1288,21 @@ class DesktopTasksController(
}
}
+ /**
+ * Remove wallpaper activity if task provided is last task and wallpaper activity token is not
+ * null
+ */
+ private fun performDesktopExitCleanupIfNeeded(taskId: Int, wct: WindowContainerTransaction) {
+ if (!taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
+ return
+ }
+ desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+ if (taskRepository.wallpaperActivityToken != null) {
+ removeWallpaperActivity(wct)
+ }
+ }
+
+
fun releaseVisualIndicator() {
val t = SurfaceControl.Transaction()
visualIndicator?.releaseVisualIndicator(t)
@@ -1242,6 +1340,8 @@ class DesktopTasksController(
// Check if we should skip handling this transition
var reason = ""
val triggerTask = request.triggerTask
+ val recentsAnimationRunning =
+ RecentsTransitionStateListener.isAnimating(recentsTransitionState)
var shouldHandleMidRecentsFreeformLaunch =
recentsAnimationRunning && isFreeformRelaunch(triggerTask, request)
val isDragAndDropFullscreenTransition = taskContainsDragAndDropCookie(triggerTask)
@@ -1429,6 +1529,7 @@ class DesktopTasksController(
wct = wct,
displayId = callingTask.displayId,
excludeTaskId = requestedTaskId,
+ reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
)
val transition = transitions.startTransition(TRANSIT_OPEN, wct, null)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
@@ -1465,17 +1566,25 @@ class DesktopTasksController(
WINDOWING_MODE_MULTI_WINDOW -> {
val splitPosition = splitScreenController
.determineNewInstancePosition(callingTaskInfo)
+ // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+ // specific cases in the future.
+ val splitIndex = if (enableFlexibleSplit())
+ splitScreenController.determineNewInstanceIndex(callingTaskInfo) else
+ SPLIT_INDEX_UNDEFINED
splitScreenController.startIntent(
launchIntent, context.userId, fillIn, splitPosition,
options.toBundle(), null /* hideTaskToken */,
- true /* forceLaunchNewTask */
- )
+ true /* forceLaunchNewTask */, splitIndex)
}
WINDOWING_MODE_FREEFORM -> {
- // TODO(b/336289597): This currently does not respect the desktop window limit.
val wct = WindowContainerTransaction()
wct.sendPendingIntent(launchIntent, fillIn, options.toBundle())
- transitions.startTransition(TRANSIT_OPEN, wct, null)
+ startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ launchingTaskId = null,
+ displayId = callingTaskInfo.displayId
+ )
}
}
}
@@ -1570,7 +1679,12 @@ class DesktopTasksController(
}
// Desktop Mode is showing and we're launching a new Task:
// 1) Exit immersive if needed.
- desktopImmersiveController.exitImmersiveIfApplicable(transition, wct, task.displayId)
+ desktopImmersiveController.exitImmersiveIfApplicable(
+ transition = transition,
+ wct = wct,
+ displayId = task.displayId,
+ reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
+ )
// 2) minimize a Task if needed.
val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
@@ -1595,8 +1709,11 @@ class DesktopTasksController(
return WindowContainerTransaction().also { wct ->
addMoveToDesktopChanges(wct, task)
// In some launches home task is moved behind new task being launched. Make sure
- // that's not the case for launches in desktop.
- if (task.baseIntent.flags.and(Intent.FLAG_ACTIVITY_TASK_ON_HOME) != 0) {
+ // that's not the case for launches in desktop. Also, if this launch is the first
+ // one to trigger the desktop mode (e.g., when [forceEnterDesktop()]), activate the
+ // desktop mode here.
+ if (task.baseIntent.flags.and(Intent.FLAG_ACTIVITY_TASK_ON_HOME) != 0
+ || !isDesktopModeShowing(task.displayId)) {
bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
wct.reorder(task.token, true)
}
@@ -1607,9 +1724,19 @@ class DesktopTasksController(
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
desktopImmersiveController.exitImmersiveIfApplicable(
- transition, wct, task.displayId
+ transition,
+ wct,
+ task.displayId,
+ reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH
)
}
+ } else if (taskRepository.isActiveTask(task.taskId)) {
+ // If a freeform task receives a request for a fullscreen launch, apply the same
+ // changes we do for similar transitions. The task not having WINDOWING_MODE_UNDEFINED
+ // set when needed can interfere with future split / multi-instance transitions.
+ return WindowContainerTransaction().also { wct ->
+ addMoveToFullscreenChanges(wct, task)
+ }
}
return null
}
@@ -1637,12 +1764,7 @@ class DesktopTasksController(
return null
val wct = WindowContainerTransaction()
- if (taskRepository.isOnlyVisibleNonClosingTask(task.taskId)
- && taskRepository.wallpaperActivityToken != null
- ) {
- // Remove wallpaper activity when the last active task is removed
- removeWallpaperActivity(wct)
- }
+ performDesktopExitCleanupIfNeeded(task.taskId, wct)
if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) {
taskRepository.addClosingTask(task.displayId, task.taskId)
@@ -1733,10 +1855,8 @@ class DesktopTasksController(
if (useDesktopOverrideDensity()) {
wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
}
- if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
- // Remove wallpaper activity when leaving desktop mode
- removeWallpaperActivity(wct)
- }
+
+ performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
}
private fun cascadeWindow(bounds: Rect, displayLayout: DisplayLayout, displayId: Int) {
@@ -1765,10 +1885,8 @@ class DesktopTasksController(
// The task's density may have been overridden in freeform; revert it here as we don't
// want it overridden in multi-window.
wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
- if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
- // Remove wallpaper activity when leaving desktop mode
- removeWallpaperActivity(wct)
- }
+
+ performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
}
/** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */
@@ -1832,26 +1950,12 @@ class DesktopTasksController(
getFocusedFreeformTask(displayId)?.let { requestSplit(it, leftOrTop) }
}
- /** Move the focused desktop task in given `displayId` to next display. */
- fun moveFocusedTaskToNextDisplay(displayId: Int) {
- getFocusedFreeformTask(displayId)?.let { moveToNextDisplay(it.taskId) }
- }
-
private fun getFocusedFreeformTask(displayId: Int): RunningTaskInfo? {
return shellTaskOrganizer.getRunningTasks(displayId).find { taskInfo ->
taskInfo.isFocused && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
}
}
- // TODO(b/364154795): wait for the completion of moveToNextDisplay transition, otherwise it will
- // pick a wrong task when a user quickly perform other actions with keyboard shortcuts after
- // moveToNextDisplay.
- private fun getGloballyFocusedFreeformTask(): RunningTaskInfo? =
- shellTaskOrganizer.getRunningTasks().find { taskInfo ->
- taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
- focusTransitionObserver.hasGlobalFocus(taskInfo)
- }
-
/**
* Requests a task be transitioned from desktop to split select. Applies needed windowing
* changes if this transition is enabled.
@@ -1985,6 +2089,10 @@ class DesktopTasksController(
if (DesktopModeStatus.shouldMaximizeWhenDragToTopEdge(context)) {
dragToMaximizeDesktopTask(taskInfo, taskSurface, currentDragBounds, motionEvent)
} else {
+ desktopModeUiEventLogger.log(
+ taskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_FULL_SCREEN
+ )
moveToFullscreenWithAnimation(
taskInfo,
position,
@@ -1993,7 +2101,11 @@ class DesktopTasksController(
}
}
IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
- handleSnapResizingTask(
+ desktopModeUiEventLogger.log(
+ taskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_LEFT
+ )
+ handleSnapResizingTaskOnDrag(
taskInfo,
SnapPosition.LEFT,
taskSurface,
@@ -2004,7 +2116,11 @@ class DesktopTasksController(
)
}
IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
- handleSnapResizingTask(
+ desktopModeUiEventLogger.log(
+ taskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_RIGHT
+ )
+ handleSnapResizingTaskOnDrag(
taskInfo,
SnapPosition.RIGHT,
taskSurface,
@@ -2090,16 +2206,32 @@ class DesktopTasksController(
// Start a new jank interaction for the drag release to desktop window animation.
interactionJankMonitor.begin(taskSurface, context, handler,
CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE, "to_desktop")
+ desktopModeUiEventLogger.log(
+ taskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_DESKTOP_MODE
+ )
finalizeDragToDesktop(taskInfo)
}
IndicatorType.NO_INDICATOR,
IndicatorType.TO_FULLSCREEN_INDICATOR -> {
+ desktopModeUiEventLogger.log(
+ taskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_FULL_SCREEN
+ )
cancelDragToDesktop(taskInfo)
}
IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+ desktopModeUiEventLogger.log(
+ taskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN
+ )
requestSplit(taskInfo, leftOrTop = true)
}
IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+ desktopModeUiEventLogger.log(
+ taskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN
+ )
requestSplit(taskInfo, leftOrTop = false)
}
}
@@ -2240,9 +2372,13 @@ class DesktopTasksController(
if (!Flags.enableFullyImmersiveInDesktop()) return
val inImmersive = taskRepository.isTaskInFullImmersiveState(taskInfo.taskId)
val requestingImmersive = taskInfo.requestingImmersive
- if (inImmersive && !requestingImmersive) {
+ if (inImmersive && !requestingImmersive
+ && !RecentsTransitionStateListener.isRunning(recentsTransitionState)) {
// Exit immersive if the app is no longer requesting it.
- exitDesktopTaskFromFullImmersive(taskInfo)
+ exitDesktopTaskFromFullImmersive(
+ taskInfo,
+ DesktopImmersiveController.ExitReason.APP_NOT_IMMERSIVE
+ )
}
}
@@ -2253,31 +2389,6 @@ class DesktopTasksController(
taskRepository.dump(pw, innerPrefix)
}
- override fun handleKeyGestureEvent(
- event: KeyGestureEvent,
- focusedToken: IBinder?
- ): Boolean {
- if (!isKeyGestureSupported(event.keyGestureType)) return false
- when (event.keyGestureType) {
- KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> {
- if (event.keycodes.contains(KeyEvent.KEYCODE_D) &&
- event.hasModifiers(KeyEvent.META_CTRL_ON or KeyEvent.META_META_ON)) {
- logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
- getGloballyFocusedFreeformTask()?.let { moveToNextDisplay(it.taskId) }
- return true
- }
- return false
- }
- else -> return false
- }
- }
-
- override fun isKeyGestureSupported(gestureType: Int): Boolean = when (gestureType) {
- KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY
- -> enableMoveToNextDisplayShortcut()
- else -> false
- }
-
/** The interface for calls from outside the shell, within the host process. */
@ExternalThread
private inner class DesktopModeImpl : DesktopMode {
@@ -2345,7 +2456,7 @@ class DesktopTasksController(
}
}
- private val mTaskbarDesktopTaskListener: TaskbarDesktopTaskListener =
+ private val taskbarDesktopTaskListener: TaskbarDesktopTaskListener =
object : TaskbarDesktopTaskListener {
override fun onTaskbarCornerRoundingUpdate(
hasTasksRequiringTaskbarRounding: Boolean) {
@@ -2362,6 +2473,27 @@ class DesktopTasksController(
}
}
+ private val desktopModeEntryExitTransitionListener: DesktopModeEntryExitTransitionListener =
+ object : DesktopModeEntryExitTransitionListener {
+ override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) {
+ ProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: onEnterDesktopModeTransitionStarted transitionTime=%s",
+ transitionDuration
+ )
+ remoteListener.call { l -> l.onEnterDesktopModeTransitionStarted(transitionDuration) }
+ }
+
+ override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {
+ ProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: onExitDesktopModeTransitionStarted transitionTime=%s",
+ transitionDuration
+ )
+ remoteListener.call { l -> l.onExitDesktopModeTransitionStarted(transitionDuration) }
+ }
+ }
+
init {
remoteListener =
SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>(
@@ -2369,13 +2501,16 @@ class DesktopTasksController(
{ c ->
run {
c.taskRepository.addVisibleTasksListener(listener, c.mainExecutor)
- c.taskbarDesktopTaskListener = mTaskbarDesktopTaskListener
+ c.taskbarDesktopTaskListener = taskbarDesktopTaskListener
+ c.desktopModeEnterExitTransitionListener =
+ desktopModeEntryExitTransitionListener
}
},
{ c ->
run {
c.taskRepository.removeVisibleTasksListener(listener)
c.taskbarDesktopTaskListener = null
+ c.desktopModeEnterExitTransitionListener = null
}
}
)
@@ -2482,6 +2617,15 @@ class DesktopTasksController(
fun onTaskbarCornerRoundingUpdate(hasTasksRequiringTaskbarRounding: Boolean)
}
+ /** Defines interface for entering and exiting desktop windowing mode. */
+ interface DesktopModeEntryExitTransitionListener {
+ /** [transitionDuration] time it takes to run enter desktop mode transition */
+ fun onEnterDesktopModeTransitionStarted(transitionDuration: Int)
+
+ /** [transitionDuration] time it takes to run exit desktop mode transition */
+ fun onExitDesktopModeTransitionStarted(transitionDuration: Int)
+ }
+
/** The positions on a screen that a task can snap to. */
enum class SnapPosition {
RIGHT,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt
index e835b2fec232..909a06604382 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt
@@ -17,12 +17,10 @@
package com.android.wm.shell.desktopmode
import android.app.Activity
-import android.app.ActivityManager
+import android.app.TaskInfo
import android.content.ComponentName
import android.os.Bundle
import android.view.WindowManager
-import com.android.internal.protolog.ProtoLog
-import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
/**
* A transparent activity used in the desktop mode to show the wallpaper under the freeform windows.
@@ -42,11 +40,12 @@ class DesktopWallpaperActivity : Activity() {
companion object {
private const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
- private val wallpaperActivityComponent =
+ @JvmStatic
+ val wallpaperActivityComponent =
ComponentName(SYSTEM_UI_PACKAGE_NAME, DesktopWallpaperActivity::class.java.name)
@JvmStatic
- fun isWallpaperTask(taskInfo: ActivityManager.RunningTaskInfo) =
+ fun isWallpaperTask(taskInfo: TaskInfo) =
taskInfo.baseIntent.component?.let(::isWallpaperComponent) ?: false
@JvmStatic
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index d537da802efd..b902bb4394b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -60,8 +60,7 @@ import java.util.function.Supplier;
* entering and exiting freeform.
*/
public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionHandler {
- @VisibleForTesting
- static final int FULLSCREEN_ANIMATION_DURATION = 336;
+ public static final int FULLSCREEN_ANIMATION_DURATION = 336;
private final Context mContext;
private final Transitions mTransitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
index c2acb87222d1..6002a4dfe0d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
@@ -33,4 +33,10 @@ interface IDesktopTaskListener {
* [hasTasksRequiringTaskbarRounding] is true.
*/
oneway void onTaskbarCornerRoundingUpdate(boolean hasTasksRequiringTaskbarRounding);
+
+ /** Entering desktop mode transition is started, send the signal with transition duration. */
+ oneway void onEnterDesktopModeTransitionStarted(int transitionDuration);
+
+ /** Exiting desktop mode transition is started, send the signal with transition duration. */
+ oneway void onExitDesktopModeTransitionStarted(int transitionDuration);
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt
new file mode 100644
index 000000000000..826de08557bd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode.compatui
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.os.IBinder
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.SurfaceControl
+import android.window.TransitionInfo
+import android.window.TransitionRequestInfo
+import android.window.WindowContainerTransaction
+import androidx.core.animation.addListener
+import com.android.app.animation.Interpolators
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
+import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.shared.TransitionUtil.isClosingMode
+import com.android.wm.shell.shared.TransitionUtil.isClosingType
+import com.android.wm.shell.shared.TransitionUtil.isOpeningMode
+import com.android.wm.shell.shared.TransitionUtil.isOpeningType
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TransitionHandler
+
+/** Handles transitions related to system modals, e.g. launch and close transitions. */
+class SystemModalsTransitionHandler(
+ private val context: Context,
+ private val mainExecutor: ShellExecutor,
+ private val animExecutor: ShellExecutor,
+ private val shellInit: ShellInit,
+ private val transitions: Transitions,
+ private val desktopRepository: DesktopRepository,
+) : TransitionHandler {
+
+ private val showingSystemModalsIds = mutableSetOf<Int>()
+
+ init {
+ shellInit.addInitCallback({ transitions.addHandler(this) }, this)
+ }
+
+ override fun startAnimation(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: Transitions.TransitionFinishCallback,
+ ): Boolean {
+ if (!isDesktopModeShowing(DEFAULT_DISPLAY)) return false
+ if (isOpeningType(info.type)) {
+ val launchChange = getLaunchingSystemModal(info) ?: return false
+ val taskInfo = launchChange.taskInfo
+ requireNotNull(taskInfo)
+ logV("Animating system modal launch: taskId=%d", taskInfo.taskId)
+ showingSystemModalsIds.add(taskInfo.taskId)
+ animateSystemModal(
+ launchChange.leash,
+ startTransaction,
+ finishTransaction,
+ finishCallback,
+ /* toShow= */ true,
+ )
+ return true
+ }
+ if (isClosingType(info.type)) {
+ val closeChange = getClosingSystemModal(info) ?: return false
+ val taskInfo = closeChange.taskInfo
+ requireNotNull(taskInfo)
+ logV("Animating system modal close: taskId=%d", taskInfo.taskId)
+ showingSystemModalsIds.remove(taskInfo.taskId)
+ animateSystemModal(
+ closeChange.leash,
+ startTransaction,
+ finishTransaction,
+ finishCallback,
+ /* toShow= */ false,
+ )
+ return true
+ }
+ return false
+ }
+
+ private fun animateSystemModal(
+ leash: SurfaceControl,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: Transitions.TransitionFinishCallback,
+ toShow: Boolean, // Whether to show or to hide the system modal
+ ) {
+ val startAlpha = if (toShow) 0f else 1f
+ val endAlpha = if (toShow) 1f else 0f
+ val animator =
+ createAlphaAnimator(SurfaceControl.Transaction(), leash, startAlpha, endAlpha)
+ animator.addListener(
+ onEnd = { _ ->
+ mainExecutor.execute { finishCallback.onTransitionFinished(/* wct= */ null) }
+ }
+ )
+ if (toShow) {
+ finishTransaction.show(leash)
+ } else {
+ finishTransaction.hide(leash)
+ }
+ startTransaction.setAlpha(leash, startAlpha)
+ startTransaction.apply()
+ animExecutor.execute { animator.start() }
+ }
+
+ private fun getLaunchingSystemModal(info: TransitionInfo): TransitionInfo.Change? =
+ info.changes.find { change ->
+ if (!isOpeningMode(change.mode)) {
+ return@find false
+ }
+ val taskInfo = change.taskInfo ?: return@find false
+ return@find isTopActivityExemptFromDesktopWindowing(context, taskInfo)
+ }
+
+ private fun getClosingSystemModal(info: TransitionInfo): TransitionInfo.Change? =
+ info.changes.find { change ->
+ if (!isClosingMode(change.mode)) {
+ return@find false
+ }
+ val taskInfo = change.taskInfo ?: return@find false
+ return@find isTopActivityExemptFromDesktopWindowing(context, taskInfo) ||
+ showingSystemModalsIds.contains(taskInfo.taskId)
+ }
+
+ private fun createAlphaAnimator(
+ transaction: SurfaceControl.Transaction,
+ leash: SurfaceControl,
+ startVal: Float,
+ endVal: Float,
+ ): ValueAnimator =
+ ValueAnimator.ofFloat(startVal, endVal).apply {
+ duration = LAUNCH_ANIM_ALPHA_DURATION_MS
+ interpolator = Interpolators.LINEAR
+ addUpdateListener { animation ->
+ transaction.setAlpha(leash, animation.animatedValue as Float).apply()
+ }
+ }
+
+ private fun isDesktopModeShowing(displayId: Int): Boolean =
+ desktopRepository.getVisibleTaskCount(displayId) > 0
+
+ override fun handleRequest(
+ transition: IBinder,
+ request: TransitionRequestInfo,
+ ): WindowContainerTransaction? = null
+
+ private fun logV(msg: String, vararg arguments: Any?) {
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
+ companion object {
+ private const val TAG = "SystemModalsTransitionHandler"
+ private const val LAUNCH_ANIM_ALPHA_DURATION_MS = 150L
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
index e01c448be8e5..de9c79ab34fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
@@ -82,9 +82,9 @@ class AppHandleEducationController(
runIfEducationFeatureEnabled {
applicationCoroutineScope.launch {
// Central block handling the app handle's educational flow end-to-end.
- isEducationViewedFlow()
- .flatMapLatest { isEducationViewed ->
- if (isEducationViewed) {
+ isAppHandleHintViewedFlow()
+ .flatMapLatest { isAppHandleHintViewed ->
+ if (isAppHandleHintViewed) {
// If the education is viewed then return emptyFlow() that completes immediately.
// This will help us to not listen to [captionHandleStateFlow] after the education
// has been viewed already.
@@ -106,12 +106,12 @@ class AppHandleEducationController(
showEducation(captionState, tooltipColorScheme)
// After showing first tooltip, mark education as viewed
- appHandleEducationDatastoreRepository.updateEducationViewedTimestampMillis(true)
+ appHandleEducationDatastoreRepository.updateAppHandleHintViewedTimestampMillis(true)
}
}
applicationCoroutineScope.launch {
- if (isFeatureUsed()) return@launch
+ if (isAppHandleHintUsed()) return@launch
windowDecorCaptionHandleRepository.captionStateFlow
.filter { captionState ->
captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded
@@ -119,8 +119,8 @@ class AppHandleEducationController(
.take(1)
.flowOn(backgroundDispatcher)
.collect {
- // If user expands app handle, mark user has used the feature
- appHandleEducationDatastoreRepository.updateFeatureUsedTimestampMillis(true)
+ // If user expands app handle, mark user has used the app handle hint
+ appHandleEducationDatastoreRepository.updateAppHandleHintUsedTimestampMillis(true)
}
}
}
@@ -323,25 +323,25 @@ class AppHandleEducationController(
}
/**
- * Listens to the changes to [WindowingEducationProto#hasEducationViewedTimestampMillis()] in
+ * Listens to the changes to [WindowingEducationProto#hasAppHandleHintViewedTimestampMillis()] in
* datastore proto object.
*
* If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this flow will always emit false. That means
- * it will emit education has not been viewed yet always.
+ * it will always emit app handle hint has not been viewed yet.
*/
- private fun isEducationViewedFlow(): Flow<Boolean> =
+ private fun isAppHandleHintViewedFlow(): Flow<Boolean> =
appHandleEducationDatastoreRepository.dataStoreFlow
.map { preferences ->
- preferences.hasEducationViewedTimestampMillis() && !SHOULD_OVERRIDE_EDUCATION_CONDITIONS
+ preferences.hasAppHandleHintViewedTimestampMillis() && !SHOULD_OVERRIDE_EDUCATION_CONDITIONS
}
.distinctUntilChanged()
/**
- * Listens to the changes to [WindowingEducationProto#hasFeatureUsedTimestampMillis()] in
+ * Listens to the changes to [WindowingEducationProto#hasAppHandleHintUsedTimestampMillis()] in
* datastore proto object.
*/
- private suspend fun isFeatureUsed(): Boolean =
- appHandleEducationDatastoreRepository.dataStoreFlow.first().hasFeatureUsedTimestampMillis()
+ private suspend fun isAppHandleHintUsed(): Boolean =
+ appHandleEducationDatastoreRepository.dataStoreFlow.first().hasAppHandleHintUsedTimestampMillis()
private fun getSize(@DimenRes resourceId: Int): Int {
if (resourceId == Resources.ID_NULL) return 0
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt
index 144370d76060..7a7829334fb6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt
@@ -54,8 +54,8 @@ class AppHandleEducationFilter(
return isFocusAppInAllowlist(focusAppPackageName) &&
!isOtherEducationShowing() &&
hasSufficientTimeSinceSetup() &&
- !isEducationViewedBefore(windowingEducationProto) &&
- !isFeatureUsedBefore(windowingEducationProto) &&
+ !isAppHandleHintViewedBefore(windowingEducationProto) &&
+ !isAppHandleHintUsedBefore(windowingEducationProto) &&
hasMinAppUsage(windowingEducationProto, focusAppPackageName)
}
@@ -76,11 +76,11 @@ class AppHandleEducationFilter(
convertIntegerResourceToDuration(
R.integer.desktop_windowing_education_required_time_since_setup_seconds)
- private fun isEducationViewedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
- windowingEducationProto.hasEducationViewedTimestampMillis()
+ private fun isAppHandleHintViewedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
+ windowingEducationProto.hasAppHandleHintViewedTimestampMillis()
- private fun isFeatureUsedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
- windowingEducationProto.hasFeatureUsedTimestampMillis()
+ private fun isAppHandleHintUsedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
+ windowingEducationProto.hasAppHandleHintUsedTimestampMillis()
private suspend fun hasMinAppUsage(
windowingEducationProto: WindowingEducationProto,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt
index d21b208df482..5e0c0007e2eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt
@@ -71,32 +71,34 @@ constructor(private val dataStore: DataStore<WindowingEducationProto>) {
suspend fun windowingEducationProto(): WindowingEducationProto = dataStoreFlow.first()
/**
- * Updates [WindowingEducationProto.educationViewedTimestampMillis_] field in datastore with
- * current timestamp if [isViewed] is true, if not then clears the field.
+ * Updates [WindowingEducationProto.appHandleHintViewedTimestampMillis_] field
+ * in datastore with current timestamp if [isViewed] is true, if not then
+ * clears the field.
*/
- suspend fun updateEducationViewedTimestampMillis(isViewed: Boolean) {
+ suspend fun updateAppHandleHintViewedTimestampMillis(isViewed: Boolean) {
dataStore.updateData { preferences ->
if (isViewed) {
preferences
.toBuilder()
- .setEducationViewedTimestampMillis(System.currentTimeMillis())
+ .setAppHandleHintViewedTimestampMillis(System.currentTimeMillis())
.build()
} else {
- preferences.toBuilder().clearEducationViewedTimestampMillis().build()
+ preferences.toBuilder().clearAppHandleHintViewedTimestampMillis().build()
}
}
}
/**
- * Updates [WindowingEducationProto.featureUsedTimestampMillis_] field in datastore with current
- * timestamp if [isViewed] is true, if not then clears the field.
+ * Updates [WindowingEducationProto.appHandleHintUsedTimestampMillis_] field
+ * in datastore with current timestamp if [isViewed] is true, if not then
+ * clears the field.
*/
- suspend fun updateFeatureUsedTimestampMillis(isViewed: Boolean) {
+ suspend fun updateAppHandleHintUsedTimestampMillis(isViewed: Boolean) {
dataStore.updateData { preferences ->
if (isViewed) {
- preferences.toBuilder().setFeatureUsedTimestampMillis(System.currentTimeMillis()).build()
+ preferences.toBuilder().setAppHandleHintUsedTimestampMillis(System.currentTimeMillis()).build()
} else {
- preferences.toBuilder().clearFeatureUsedTimestampMillis().build()
+ preferences.toBuilder().clearAppHandleHintUsedTimestampMillis().build()
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto
index 4cddd01ee96b..0c4d562b8d55 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto
@@ -22,9 +22,19 @@ option java_multiple_files = true;
// Desktop Windowing education data
message WindowingEducationProto {
// Timestamp in milliseconds of when the education was last viewed.
- optional int64 education_viewed_timestamp_millis = 1;
+ optional int64 education_viewed_timestamp_millis = 1 [deprecated=true];
// Timestamp in milliseconds of when the feature was last used.
- optional int64 feature_used_timestamp_millis = 2;
+ optional int64 feature_used_timestamp_millis = 2 [deprecated=true];
+
+ // Timestamp in milliseconds of when the app handle hint was last viewed.
+ optional int64 app_handle_hint_viewed_timestamp_millis = 5;
+ // Timestamp in milliseconds of when the app handle hint was last used.
+ optional int64 app_handle_hint_used_timestamp_millis = 6;
+ // Timestamp in milliseconds of when the enter desktop mode hint was last viewed.
+ optional int64 enter_desktop_mode_hint_viewed_timestamp_millis = 7;
+ // Timestamp in milliseconds of when the exit desktop mode hint was last viewed.
+ optional int64 exit_desktop_mode_hint_viewed_timestamp_millis = 8;
+
oneof education_data {
// Fields specific to app handle education
AppHandleEducation app_handle_education = 3;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
index 5d22c1edf8fe..ae9d21f621de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
@@ -41,6 +41,9 @@ import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -81,6 +84,7 @@ import com.android.wm.shell.draganddrop.anim.HoverAnimProps;
import com.android.wm.shell.draganddrop.anim.TwoFiftyFiftyTargetAnimator;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.split.SplitScreenConstants;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex;
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -219,8 +223,10 @@ public class SplitDragPolicy implements DropTarget {
displayRegion.splitHorizontally(startHitRegion, endHitRegion);
}
- mTargets.add(new Target(TYPE_SPLIT_LEFT, startHitRegion, startBounds, -1));
- mTargets.add(new Target(TYPE_SPLIT_RIGHT, endHitRegion, endBounds, -1));
+ mTargets.add(new Target(TYPE_SPLIT_LEFT, startHitRegion, startBounds,
+ SPLIT_INDEX_0));
+ mTargets.add(new Target(TYPE_SPLIT_RIGHT, endHitRegion, endBounds,
+ SPLIT_INDEX_1));
} else {
// TODO(b/349828130), move this into init function and/or the insets updating
// callback
@@ -287,9 +293,10 @@ public class SplitDragPolicy implements DropTarget {
displayRegion.splitVertically(leftHitRegion, rightHitRegion);
}
- mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, topOrLeftBounds, -1));
+ mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, topOrLeftBounds,
+ SPLIT_INDEX_UNDEFINED));
mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, bottomOrRightBounds,
- -1));
+ SPLIT_INDEX_UNDEFINED));
} else {
final Rect topHitRegion = new Rect();
final Rect bottomHitRegion = new Rect();
@@ -308,9 +315,10 @@ public class SplitDragPolicy implements DropTarget {
displayRegion.splitHorizontally(topHitRegion, bottomHitRegion);
}
- mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topOrLeftBounds, -1));
+ mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topOrLeftBounds,
+ SPLIT_INDEX_UNDEFINED));
mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomOrRightBounds,
- -1));
+ SPLIT_INDEX_UNDEFINED));
}
}
} else {
@@ -378,9 +386,9 @@ public class SplitDragPolicy implements DropTarget {
? mFullscreenStarter
: mSplitscreenStarter;
if (mSession.appData != null) {
- launchApp(mSession, starter, position, hideTaskToken);
+ launchApp(mSession, starter, position, hideTaskToken, target.index);
} else {
- launchIntent(mSession, starter, position, hideTaskToken);
+ launchIntent(mSession, starter, position, hideTaskToken, target.index);
}
if (enableFlexibleSplit()) {
@@ -392,9 +400,10 @@ public class SplitDragPolicy implements DropTarget {
* Launches an app provided by SysUI.
*/
private void launchApp(DragSession session, Starter starter, @SplitPosition int position,
- @Nullable WindowContainerToken hideTaskToken) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching app data at position=%d",
- position);
+ @Nullable WindowContainerToken hideTaskToken, @SplitIndex int splitIndex) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+ "Launching app data at position=%d index=%d",
+ position, splitIndex);
final ClipDescription description = session.getClipDescription();
final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
@@ -429,7 +438,7 @@ public class SplitDragPolicy implements DropTarget {
}
}
starter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */,
- position, opts, hideTaskToken);
+ position, opts, hideTaskToken, splitIndex);
}
}
@@ -437,7 +446,7 @@ public class SplitDragPolicy implements DropTarget {
* Launches an intent sender provided by an application.
*/
private void launchIntent(DragSession session, Starter starter, @SplitPosition int position,
- @Nullable WindowContainerToken hideTaskToken) {
+ @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching intent at position=%d",
position);
final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
@@ -452,7 +461,7 @@ public class SplitDragPolicy implements DropTarget {
final Bundle opts = baseActivityOpts.toBundle();
starter.startIntent(session.launchableIntent,
session.launchableIntent.getCreatorUserHandle().getIdentifier(),
- null /* fillIntent */, position, opts, hideTaskToken);
+ null /* fillIntent */, position, opts, hideTaskToken, index);
}
@Override
@@ -541,7 +550,7 @@ public class SplitDragPolicy implements DropTarget {
@Nullable Bundle options, UserHandle user);
void startIntent(PendingIntent intent, int userId, Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options,
- @Nullable WindowContainerToken hideTaskToken);
+ @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index);
void enterSplitScreen(int taskId, boolean leftOrTop);
/**
@@ -592,7 +601,7 @@ public class SplitDragPolicy implements DropTarget {
@Override
public void startIntent(PendingIntent intent, int userId, @Nullable Intent fillInIntent,
int position, @Nullable Bundle options,
- @Nullable WindowContainerToken hideTaskToken) {
+ @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
if (hideTaskToken != null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
"Default starter does not support hide task token");
@@ -641,13 +650,13 @@ public class SplitDragPolicy implements DropTarget {
final Rect hitRegion;
// The approximate visual region for where the task will start
final Rect drawRegion;
- int index;
+ @SplitIndex int index;
/**
* @param index 0-indexed, represents which position of drop target this object represents,
* 0 to N for left to right, top to bottom
*/
- public Target(@Type int t, Rect hit, Rect draw, int index) {
+ public Target(@Type int t, Rect hit, Rect draw, @SplitIndex int index) {
type = t;
hitRegion = hit;
drawRegion = draw;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
index 9f532f57961d..54619528f2bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
@@ -22,6 +22,10 @@ import android.graphics.Rect
import com.android.wm.shell.R
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.draganddrop.SplitDragPolicy.Target
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_2
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_3
/**
* Represents Drop Zone targets and animations for when the system is currently in a 2 app 50/50
@@ -98,7 +102,7 @@ class TwoFiftyFiftyTargetAnimator : DropTargetAnimSupplier {
farStartBounds.right + halfDividerWidth,
farStartBounds.bottom
),
- farStartBounds, 0
+ farStartBounds, SPLIT_INDEX_0
)
)
targets.add(
@@ -110,7 +114,7 @@ class TwoFiftyFiftyTargetAnimator : DropTargetAnimSupplier {
startBounds.right + halfDividerWidth,
startBounds.bottom
),
- startBounds, 1
+ startBounds, SPLIT_INDEX_1
)
)
targets.add(
@@ -120,7 +124,7 @@ class TwoFiftyFiftyTargetAnimator : DropTargetAnimSupplier {
endBounds.left - halfDividerWidth,
endBounds.top, endBounds.right, endBounds.bottom
),
- endBounds, 2
+ endBounds, SPLIT_INDEX_2
)
)
targets.add(
@@ -130,7 +134,7 @@ class TwoFiftyFiftyTargetAnimator : DropTargetAnimSupplier {
farEndBounds.left - halfDividerWidth,
farEndBounds.top, farEndBounds.right, farEndBounds.bottom
),
- farEndBounds, 3
+ farEndBounds, SPLIT_INDEX_3
)
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformComponents.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformComponents.java
index 3379ff2a8c30..24b74c636630 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformComponents.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformComponents.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.provider.Settings;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -59,4 +60,12 @@ public class FreeformComponents {
|| Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
}
+
+ /**
+ * Freeform is enabled or we need the components to enable the app handle when desktop mode is
+ * not enabled
+ */
+ public static boolean requiresFreeformComponents(Context context) {
+ return isFreeformEnabled(context) || DesktopModeStatus.overridesShowAppHandle(context);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index e848b889b314..2ae9828ca0db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -254,8 +254,13 @@ public class FreeformTaskTransitionHandler
finishT.hide(sc);
final Rect startBounds = new Rect(change.getStartAbsBounds());
animator.addUpdateListener(animation -> {
- t.setPosition(sc, startBounds.left,
- startBounds.top + (animation.getAnimatedFraction() * screenHeight));
+ final float newTop = startBounds.top + (animation.getAnimatedFraction() * screenHeight);
+ t.setPosition(sc, startBounds.left, newTop);
+ if (newTop > screenHeight) {
+ // At this point the task surface is off-screen, so hide it to prevent flicker
+ // failures. See b/377651666.
+ t.hide(sc);
+ }
t.apply();
});
animator.addListener(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index 18f9cc758e38..b6d19b657705 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -69,7 +69,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
mWindowDecorViewModel = windowDecorViewModel;
mTaskChangeListener = taskChangeListener;
mFocusTransitionObserver = focusTransitionObserver;
- if (FreeformComponents.isFreeformEnabled(context)) {
+ if (FreeformComponents.requiresFreeformComponents(context)) {
shellInit.addInitCallback(this::onInit, this);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index b618bf1215ac..e4f83333edbf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -42,6 +42,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
+import android.view.Display;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.IRemoteTransition;
@@ -54,6 +55,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -80,6 +82,8 @@ public class KeyguardTransitionHandler
private final Transitions mTransitions;
private final ShellController mShellController;
+
+ private final DisplayController mDisplayController;
private final Handler mMainHandler;
private final ShellExecutor mMainExecutor;
@@ -121,12 +125,14 @@ public class KeyguardTransitionHandler
public KeyguardTransitionHandler(
@NonNull ShellInit shellInit,
@NonNull ShellController shellController,
+ @NonNull DisplayController displayController,
@NonNull Transitions transitions,
@NonNull TaskStackListenerImpl taskStackListener,
@NonNull Handler mainHandler,
@NonNull ShellExecutor mainExecutor) {
mTransitions = transitions;
mShellController = shellController;
+ mDisplayController = displayController;
mMainHandler = mainHandler;
mMainExecutor = mainExecutor;
mTaskStackListener = taskStackListener;
@@ -167,6 +173,10 @@ public class KeyguardTransitionHandler
return mKeyguardShowing;
}
+ public boolean isKeyguardAnimating() {
+ return !mStartedTransitions.isEmpty();
+ }
+
@Override
public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
mDreamToken = taskInfo.getActivityType() == ACTIVITY_TYPE_DREAM ? taskInfo.token : null;
@@ -429,10 +439,10 @@ public class KeyguardTransitionHandler
@Override
public void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- final KeyguardState keyguardState =
- new KeyguardState.Builder(android.view.Display.DEFAULT_DISPLAY)
- .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build();
- wct.addKeyguardState(keyguardState);
+ for (Display display : mDisplayController.getDisplays()) {
+ wct.addKeyguardState(new KeyguardState.Builder(display.getDisplayId())
+ .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build());
+ }
mMainExecutor.execute(() -> {
mTransitions.startTransition(keyguardShowing ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK,
wct, KeyguardTransitionHandler.this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index f7aed4401247..72c1ef06806a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -73,6 +73,7 @@ import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.pip.PipContentOverlay;
@@ -1346,6 +1347,13 @@ public class PipTransition extends PipTransitionController {
return true;
}
+ @Override
+ public boolean isPackageActiveInPip(@Nullable String packageName) {
+ final TaskInfo inPipTask = mPipOrganizer.getTaskInfo();
+ return packageName != null && inPipTask != null && mPipOrganizer.isInPip()
+ && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+ }
+
private void updatePipForUnhandledTransition(@NonNull TransitionInfo.Change pipChange,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 5ffc64f412f1..a273822759f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -47,7 +47,6 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipMenuController;
-import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.DefaultMixedHandler;
@@ -312,10 +311,9 @@ public abstract class PipTransitionController implements Transitions.TransitionH
}
/** Whether a particular package is same as current pip package. */
- public boolean isPackageActiveInPip(String packageName) {
- final TaskInfo inPipTask = mPipOrganizer.getTaskInfo();
- return packageName != null && inPipTask != null && mPipOrganizer.isInPip()
- && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+ public boolean isPackageActiveInPip(@Nullable String packageName) {
+ // No-op, to be handled differently in PIP1 and PIP2
+ return false;
}
/** Add PiP-related changes to `outWCT` for the given request. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
index eb33ff4c1c8e..35c90acd306f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
@@ -52,6 +52,9 @@ public class PipEnterAnimator extends ValueAnimator {
private final SurfaceControl.Transaction mStartTransaction;
private final SurfaceControl.Transaction mFinishTransaction;
+ private final int mCornerRadius;
+ private final int mShadowRadius;
+
// Bounds updated by the evaluator as animator is running.
private final Rect mAnimatedRect = new Rect();
@@ -128,6 +131,8 @@ public class PipEnterAnimator extends ValueAnimator {
final int enterAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipEnterAnimationDuration);
+ mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+ mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
setDuration(enterAnimationDuration);
setFloatValues(0f, 1f);
setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
@@ -177,6 +182,8 @@ public class PipEnterAnimator extends ValueAnimator {
mTransformTensor.postRotate(degrees);
tx.setMatrix(mLeash, mTransformTensor, mMatrixTmp);
+ tx.setCornerRadius(mLeash, mCornerRadius).setShadowRadius(mLeash, mShadowRadius);
+
if (mContentOverlay != null) {
mContentOverlay.onAnimationUpdate(tx, 1f / scaleX, fraction, mEndBounds);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
index 4558a9f141c8..06e8349259b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
@@ -29,6 +29,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.shared.animation.Interpolators;
@@ -50,6 +51,9 @@ public class PipResizeAnimator extends ValueAnimator {
private Runnable mAnimationEndCallback;
private RectEvaluator mRectEvaluator;
+ private final int mCornerRadius;
+ private final int mShadowRadius;
+
// Bounds relative to which scaling/cropping must be done.
private final Rect mBaseBounds = new Rect();
@@ -74,7 +78,8 @@ public class PipResizeAnimator extends ValueAnimator {
mAnimationStartCallback.run();
}
if (mStartTx != null) {
- setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta);
+ setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta,
+ mCornerRadius, mShadowRadius);
mStartTx.apply();
}
}
@@ -83,7 +88,8 @@ public class PipResizeAnimator extends ValueAnimator {
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (mFinishTx != null) {
- setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f);
+ setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f,
+ mCornerRadius, mShadowRadius);
}
if (mAnimationEndCallback != null) {
mAnimationEndCallback.run();
@@ -99,7 +105,8 @@ public class PipResizeAnimator extends ValueAnimator {
mSurfaceControlTransactionFactory.getTransaction();
final float fraction = getAnimatedFraction();
final float degrees = (1.0f - fraction) * mDelta;
- setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees);
+ setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees,
+ mCornerRadius, mShadowRadius);
tx.apply();
}
};
@@ -128,6 +135,9 @@ public class PipResizeAnimator extends ValueAnimator {
mRectEvaluator = new RectEvaluator(mAnimatedRect);
+ mCornerRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+ mShadowRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
+
setObjectValues(startBounds, endBounds);
setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
addListener(mAnimatorListener);
@@ -152,7 +162,7 @@ public class PipResizeAnimator extends ValueAnimator {
* @param degrees degrees of rotation - counter-clockwise is positive by convention.
*/
private static void setBoundsAndRotation(SurfaceControl.Transaction tx, SurfaceControl leash,
- Rect baseBounds, Rect targetBounds, float degrees) {
+ Rect baseBounds, Rect targetBounds, float degrees, int cornerRadius, int shadowRadius) {
Matrix transformTensor = new Matrix();
final float[] mMatrixTmp = new float[9];
final float scaleX = (float) targetBounds.width() / baseBounds.width();
@@ -162,7 +172,9 @@ public class PipResizeAnimator extends ValueAnimator {
transformTensor.postTranslate(targetBounds.left, targetBounds.top);
transformTensor.postRotate(degrees, targetBounds.centerX(), targetBounds.centerY());
- tx.setMatrix(leash, transformTensor, mMatrixTmp);
+ tx.setMatrix(leash, transformTensor, mMatrixTmp)
+ .setCornerRadius(leash, cornerRadius)
+ .setShadowRadius(leash, shadowRadius);
}
@VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index bc0918331168..6d2df952ee58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip2.phone;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
@@ -293,6 +294,11 @@ public class PipController implements ConfigurationChangeListener,
// Update the display layout caches even if we are not in PiP.
setDisplayLayout(mDisplayController.getDisplayLayout(displayId));
+ if (toRotation != ROTATION_UNDEFINED) {
+ // Make sure we rotate to final rotation ourselves in case display change is coming
+ // from the remote rotation as a part of an already collecting transition.
+ mPipDisplayLayoutState.rotateTo(toRotation);
+ }
if (!mPipTransitionState.isInPip()) {
// Skip the PiP-relevant updates if we aren't in a valid PiP state.
@@ -322,7 +328,7 @@ public class PipController implements ConfigurationChangeListener,
mPipBoundsAlgorithm.applySnapFraction(toBounds, snapFraction);
mPipBoundsState.setBounds(toBounds);
}
- t.setBounds(mPipTransitionState.mPipTaskToken, mPipBoundsState.getBounds());
+ t.setBounds(mPipTransitionState.getPipTaskToken(), mPipBoundsState.getBounds());
}
private void setDisplayLayout(DisplayLayout layout) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 3738353dd0a3..fd387d1811fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -785,8 +785,16 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private void handleFlingTransition(SurfaceControl.Transaction startTx,
SurfaceControl.Transaction finishTx, Rect destinationBounds) {
- startTx.setPosition(mPipTransitionState.getPinnedTaskLeash(),
- destinationBounds.left, destinationBounds.top);
+ SurfaceControl pipLeash = mPipTransitionState.getPinnedTaskLeash();
+ int cornerRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+ int shadowRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
+
+ // merge transactions so everything is done on startTx
+ startTx.merge(finishTx);
+
+ startTx.setPosition(pipLeash, destinationBounds.left, destinationBounds.top)
+ .setCornerRadius(pipLeash, cornerRadius)
+ .setShadowRadius(pipLeash, shadowRadius);
startTx.apply();
// All motion operations have actually finished, so make bounds cache updates.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 607de0eccd77..5438a014af00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -25,10 +25,13 @@ import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.SurfaceControl;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsState;
@@ -48,11 +51,13 @@ public class PipScheduler {
private final ShellExecutor mMainExecutor;
private final PipTransitionState mPipTransitionState;
private PipTransitionController mPipTransitionController;
- private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+ private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@Nullable private Runnable mUpdateMovementBoundsRunnable;
+ private PipAlphaAnimatorSupplier mPipAlphaAnimatorSupplier;
+
public PipScheduler(Context context,
PipBoundsState pipBoundsState,
ShellExecutor mainExecutor,
@@ -64,10 +69,7 @@ public class PipScheduler {
mSurfaceControlTransactionFactory =
new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
- }
-
- ShellExecutor getMainExecutor() {
- return mMainExecutor;
+ mPipAlphaAnimatorSupplier = PipAlphaAnimator::new;
}
void setPipTransitionController(PipTransitionController pipTransitionController) {
@@ -76,27 +78,29 @@ public class PipScheduler {
@Nullable
private WindowContainerTransaction getExitPipViaExpandTransaction() {
- if (mPipTransitionState.mPipTaskToken == null) {
+ WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken();
+ if (pipTaskToken == null) {
return null;
}
WindowContainerTransaction wct = new WindowContainerTransaction();
// final expanded bounds to be inherited from the parent
- wct.setBounds(mPipTransitionState.mPipTaskToken, null);
+ wct.setBounds(pipTaskToken, null);
// if we are hitting a multi-activity case
// windowing mode change will reparent to original host task
- wct.setWindowingMode(mPipTransitionState.mPipTaskToken, WINDOWING_MODE_UNDEFINED);
+ wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED);
return wct;
}
@Nullable
private WindowContainerTransaction getRemovePipTransaction() {
- if (mPipTransitionState.mPipTaskToken == null) {
+ WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken();
+ if (pipTaskToken == null) {
return null;
}
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mPipTransitionState.mPipTaskToken, null);
- wct.setWindowingMode(mPipTransitionState.mPipTaskToken, WINDOWING_MODE_UNDEFINED);
- wct.reorder(mPipTransitionState.mPipTaskToken, false);
+ wct.setBounds(pipTaskToken, null);
+ wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED);
+ wct.reorder(pipTaskToken, false);
return wct;
}
@@ -117,7 +121,7 @@ public class PipScheduler {
/** Runs remove PiP animation and schedules remove PiP transition after the animation ends. */
public void removePipAfterAnimation() {
SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
- PipAlphaAnimator animator = new PipAlphaAnimator(mContext,
+ PipAlphaAnimator animator = mPipAlphaAnimatorSupplier.get(mContext,
mPipTransitionState.getPinnedTaskLeash(), tx, PipAlphaAnimator.FADE_OUT);
animator.setAnimationEndCallback(this::scheduleRemovePipImmediately);
animator.start();
@@ -159,13 +163,14 @@ public class PipScheduler {
* for running the animator will get this as an extra.
*/
public void scheduleAnimateResizePip(Rect toBounds, boolean configAtEnd, int duration) {
- if (mPipTransitionState.mPipTaskToken == null || !mPipTransitionState.isInPip()) {
+ WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken();
+ if (pipTaskToken == null || !mPipTransitionState.isInPip()) {
return;
}
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mPipTransitionState.mPipTaskToken, toBounds);
+ wct.setBounds(pipTaskToken, toBounds);
if (configAtEnd) {
- wct.deferConfigToTransitionEnd(mPipTransitionState.mPipTaskToken);
+ wct.deferConfigToTransitionEnd(pipTaskToken);
}
mPipTransitionController.startResizeTransition(wct, duration);
}
@@ -204,7 +209,7 @@ public class PipScheduler {
return;
}
SurfaceControl leash = mPipTransitionState.getPinnedTaskLeash();
- final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
Matrix transformTensor = new Matrix();
final float[] mMatrixTmp = new float[9];
@@ -218,7 +223,7 @@ public class PipScheduler {
tx.apply();
}
- void setUpdateMovementBoundsRunnable(Runnable updateMovementBoundsRunnable) {
+ void setUpdateMovementBoundsRunnable(@Nullable Runnable updateMovementBoundsRunnable) {
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
}
@@ -235,4 +240,23 @@ public class PipScheduler {
mPipBoundsState.setBounds(newBounds);
maybeUpdateMovementBounds();
}
+
+ @VisibleForTesting
+ void setSurfaceControlTransactionFactory(
+ @NonNull PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
+ mSurfaceControlTransactionFactory = factory;
+ }
+
+ @VisibleForTesting
+ interface PipAlphaAnimatorSupplier {
+ PipAlphaAnimator get(@NonNull Context context,
+ SurfaceControl leash,
+ SurfaceControl.Transaction tx,
+ @PipAlphaAnimator.Fade int direction);
+ }
+
+ @VisibleForTesting
+ void setPipAlphaAnimatorSupplier(@NonNull PipAlphaAnimatorSupplier supplier) {
+ mPipAlphaAnimatorSupplier = supplier;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 3caad0966b1f..1ba29a238474 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -31,6 +31,7 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_RESIZE_PIP;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
@@ -120,6 +121,8 @@ public class PipTransition extends PipTransitionController implements
@Nullable
private Transitions.TransitionFinishCallback mFinishCallback;
+ private ValueAnimator mTransitionAnimator;
+
public PipTransition(
Context context,
@NonNull ShellInit shellInit,
@@ -209,7 +212,12 @@ public class PipTransition extends PipTransitionController implements
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
- @NonNull Transitions.TransitionFinishCallback finishCallback) {}
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ // Just jump-cut the current animation if any, but do not merge.
+ if (info.getType() == TRANSIT_EXIT_PIP) {
+ end();
+ }
+ }
@Override
public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
@@ -241,7 +249,7 @@ public class PipTransition extends PipTransitionController implements
extra.putParcelable(PIP_TASK_LEASH, pipChange.getLeash());
mPipTransitionState.setState(PipTransitionState.ENTERING_PIP, extra);
- if (mPipTransitionState.isInSwipePipToHomeTransition()) {
+ if (isInSwipePipToHomeTransition()) {
// If this is the second transition as a part of swipe PiP to home cuj,
// handle this transition as a special case with no-op animation.
return handleSwipePipToHomeTransition(info, startTransaction, finishTransaction,
@@ -271,6 +279,14 @@ public class PipTransition extends PipTransitionController implements
return false;
}
+ @Override
+ public void end() {
+ if (mTransitionAnimator != null && mTransitionAnimator.isRunning()) {
+ mTransitionAnimator.end();
+ mTransitionAnimator = null;
+ }
+ }
+
//
// Animation schedulers and entry points
//
@@ -355,7 +371,9 @@ public class PipTransition extends PipTransitionController implements
// Update the src-rect-hint in params in place, to set up initial animator transform.
Rect sourceRectHint = getAdjustedSourceRectHint(info, pipChange, pipActivityChange);
- pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint().set(sourceRectHint);
+ final PictureInPictureParams params = getPipParams(pipChange);
+ params.copyOnlySet(
+ new PictureInPictureParams.Builder().setSourceRectHint(sourceRectHint).build());
// Config-at-end transitions need to have their activities transformed before starting
// the animation; this makes the buffer seem like it's been updated to final size.
@@ -400,7 +418,7 @@ public class PipTransition extends PipTransitionController implements
final SurfaceControl pipLeash = getLeash(pipChange);
final Rect startBounds = pipChange.getStartAbsBounds();
final Rect endBounds = pipChange.getEndAbsBounds();
- final PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams;
+ final PictureInPictureParams params = getPipParams(pipChange);
final Rect adjustedSourceRectHint = getAdjustedSourceRectHint(info, pipChange,
pipActivityChange);
@@ -420,7 +438,8 @@ public class PipTransition extends PipTransitionController implements
}
// Update the src-rect-hint in params in place, to set up initial animator transform.
- params.getSourceRectHint().set(adjustedSourceRectHint);
+ params.copyOnlySet(new PictureInPictureParams.Builder()
+ .setSourceRectHint(adjustedSourceRectHint).build());
// Config-at-end transitions need to have their activities transformed before starting
// the animation; this makes the buffer seem like it's been updated to final size.
@@ -435,7 +454,7 @@ public class PipTransition extends PipTransitionController implements
}
finishTransition();
});
- animator.start();
+ cacheAndStartTransitionAnimator(animator);
return true;
}
@@ -535,7 +554,7 @@ public class PipTransition extends PipTransitionController implements
PipAlphaAnimator.FADE_IN);
// This should update the pip transition state accordingly after we stop playing.
animator.setAnimationEndCallback(this::finishTransition);
- animator.start();
+ cacheAndStartTransitionAnimator(animator);
return true;
}
@@ -543,7 +562,7 @@ public class PipTransition extends PipTransitionController implements
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- WindowContainerToken pipToken = mPipTransitionState.mPipTaskToken;
+ WindowContainerToken pipToken = mPipTransitionState.getPipTaskToken();
TransitionInfo.Change pipChange = getChangeByToken(info, pipToken);
if (pipChange == null) {
@@ -579,10 +598,10 @@ public class PipTransition extends PipTransitionController implements
PictureInPictureParams params = null;
if (pipChange.getTaskInfo() != null) {
// single activity
- params = pipChange.getTaskInfo().pictureInPictureParams;
+ params = getPipParams(pipChange);
} else if (parentBeforePip != null && parentBeforePip.getTaskInfo() != null) {
// multi activity
- params = parentBeforePip.getTaskInfo().pictureInPictureParams;
+ params = getPipParams(parentBeforePip);
}
final Rect sourceRectHint = PipBoundsAlgorithm.getValidSourceHintRect(params, endBounds,
startBounds);
@@ -605,7 +624,7 @@ public class PipTransition extends PipTransitionController implements
}
finishTransition();
});
- animator.start();
+ cacheAndStartTransitionAnimator(animator);
return true;
}
@@ -701,6 +720,13 @@ public class PipTransition extends PipTransitionController implements
@NonNull TransitionInfo.Change pipChange) {
TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
int startRotation = pipChange.getStartRotation();
+ if (pipChange.getEndRotation() != ROTATION_UNDEFINED
+ && startRotation != pipChange.getEndRotation()) {
+ // If PiP change was collected along with the display change and the orientation change
+ // happened in sync with the PiP change, then do not treat this as fixed-rotation case.
+ return ROTATION_0;
+ }
+
int endRotation = fixedRotationChange != null
? fixedRotationChange.getEndFixedRotation() : mPipDisplayLayoutState.getRotation();
int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
@@ -773,11 +799,11 @@ public class PipTransition extends PipTransitionController implements
}
private boolean isRemovePipTransition(@NonNull TransitionInfo info) {
- if (mPipTransitionState.mPipTaskToken == null) {
+ if (mPipTransitionState.getPipTaskToken() == null) {
// PiP removal makes sense if enter-PiP has cached a valid pinned task token.
return false;
}
- TransitionInfo.Change pipChange = info.getChange(mPipTransitionState.mPipTaskToken);
+ TransitionInfo.Change pipChange = info.getChange(mPipTransitionState.getPipTaskToken());
if (pipChange == null) {
// Search for the PiP change by token since the windowing mode might be FULLSCREEN now.
return false;
@@ -816,9 +842,20 @@ public class PipTransition extends PipTransitionController implements
initActivityPos.y);
}
}
+ void cacheAndStartTransitionAnimator(@NonNull ValueAnimator animator) {
+ mTransitionAnimator = animator;
+ mTransitionAnimator.start();
+ }
@NonNull
- private SurfaceControl getLeash(TransitionInfo.Change change) {
+ private static PictureInPictureParams getPipParams(@NonNull TransitionInfo.Change pipChange) {
+ return pipChange.getTaskInfo().pictureInPictureParams != null
+ ? pipChange.getTaskInfo().pictureInPictureParams
+ : new PictureInPictureParams.Builder().build();
+ }
+
+ @NonNull
+ private static SurfaceControl getLeash(TransitionInfo.Change change) {
SurfaceControl leash = change.getLeash();
Preconditions.checkNotNull(leash, "Leash is null for change=" + change);
return leash;
@@ -830,11 +867,6 @@ public class PipTransition extends PipTransitionController implements
@Override
public void finishTransition() {
- if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null /* finishWct */);
- mFinishCallback = null;
- }
-
final int currentState = mPipTransitionState.getState();
int nextState = PipTransitionState.UNDEFINED;
switch (currentState) {
@@ -849,6 +881,14 @@ public class PipTransition extends PipTransitionController implements
break;
}
mPipTransitionState.setState(nextState);
+
+ if (mFinishCallback != null) {
+ // Need to unset mFinishCallback first because onTransitionFinished can re-enter this
+ // handler if there is a pending PiP animation.
+ final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
+ mFinishCallback = null;
+ finishCallback.onTransitionFinished(null /* finishWct */);
+ }
}
@Override
@@ -859,20 +899,27 @@ public class PipTransition extends PipTransitionController implements
Preconditions.checkState(extra != null,
"No extra bundle for " + mPipTransitionState);
- mPipTransitionState.mPipTaskToken = extra.getParcelable(
- PIP_TASK_TOKEN, WindowContainerToken.class);
+ mPipTransitionState.setPipTaskToken(extra.getParcelable(
+ PIP_TASK_TOKEN, WindowContainerToken.class));
mPipTransitionState.setPinnedTaskLeash(extra.getParcelable(
PIP_TASK_LEASH, SurfaceControl.class));
- boolean hasValidTokenAndLeash = mPipTransitionState.mPipTaskToken != null
+ boolean hasValidTokenAndLeash = mPipTransitionState.getPipTaskToken() != null
&& mPipTransitionState.getPinnedTaskLeash() != null;
Preconditions.checkState(hasValidTokenAndLeash,
"Unexpected bundle for " + mPipTransitionState);
break;
case PipTransitionState.EXITED_PIP:
- mPipTransitionState.mPipTaskToken = null;
+ mPipTransitionState.setPipTaskToken(null);
mPipTransitionState.setPinnedTaskLeash(null);
break;
}
}
+
+ @Override
+ public boolean isPackageActiveInPip(@Nullable String packageName) {
+ return packageName != null
+ && mPipBoundsState.getLastPipComponentName() != null
+ && packageName.equals(mPipBoundsState.getLastPipComponentName().getPackageName());
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 03e06f906015..8e90bfee2636 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -138,7 +138,7 @@ public class PipTransitionState {
// pinned PiP task's WC token
@Nullable
- WindowContainerToken mPipTaskToken;
+ private WindowContainerToken mPipTaskToken;
// pinned PiP task's leash
@Nullable
@@ -304,6 +304,14 @@ public class PipTransitionState {
mSwipePipToHomeAppBounds.setEmpty();
}
+ @Nullable WindowContainerToken getPipTaskToken() {
+ return mPipTaskToken;
+ }
+
+ public void setPipTaskToken(@Nullable WindowContainerToken token) {
+ mPipTaskToken = token;
+ }
+
@Nullable SurfaceControl getPinnedTaskLeash() {
return mPinnedTaskLeash;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 49cf8ae81aa8..35e6c8dd6580 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -46,6 +46,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
"ShellBackPreview"),
WM_SHELL_RECENT_TASKS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
+ WM_SHELL_TASK_OBSERVER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ Consts.TAG_WM_SHELL),
// TODO(b/282232877): turn logToLogcat to false.
WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
index b58f0681c571..68dc0f27bca1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
@@ -45,9 +45,15 @@ oneway interface IRecentTasksListener {
*/
void onRunningTaskChanged(in RunningTaskInfo taskInfo);
- /** A task has moved to front. */
- void onTaskMovedToFront(in GroupedTaskInfo[] visibleTasks);
+ /** A task has moved to front. Only used if enableShellTopTaskTracking() is disabled. */
+ void onTaskMovedToFront(in GroupedTaskInfo taskToFront);
- /** A task info has changed. */
+ /** A task info has changed. Only used if enableShellTopTaskTracking() is disabled. */
void onTaskInfoChanged(in RunningTaskInfo taskInfo);
+
+ /**
+ * If enableShellTopTaskTracking() is enabled, this reports the set of all visible tasks.
+ * Otherwise, this reports only the new top most visible task.
+ */
+ void onVisibleTasksChanged(in GroupedTaskInfo[] visibleTasks);
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 9911669d2cb8..363c95fcf010 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -17,14 +17,20 @@
package com.android.wm.shell.recents;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.PackageManager.FEATURE_PC;
+import static android.view.Display.INVALID_DISPLAY;
+import static com.android.wm.shell.Flags.enableShellTopTaskTracking;
+import static com.android.wm.shell.desktopmode.DesktopWallpaperActivity.isWallpaperTask;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
import android.Manifest;
import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.app.IApplicationThread;
import android.app.KeyguardManager;
@@ -49,6 +55,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
+import com.android.launcher3.Flags;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -65,7 +72,6 @@ import com.android.wm.shell.shared.split.SplitBounds;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -111,6 +117,11 @@ public class RecentTasksController implements TaskStackListenerCallback,
private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>();
/**
+ * Cached list of the visible tasks, sorted from top most to bottom most.
+ */
+ private final List<RunningTaskInfo> mVisibleTasks = new ArrayList<>();
+
+ /**
* Creates {@link RecentTasksController}, returns {@code null} if the feature is not
* supported.
*/
@@ -170,10 +181,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
mShellCommandHandler.addDumpCallback(this::dump, this);
mTaskStackListener.addListener(this);
mDesktopRepository.ifPresent(it -> it.addActiveTaskListener(this));
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
- mMainExecutor);
- }
+ mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
+ mMainExecutor);
mContext.getSystemService(KeyguardManager.class).addKeyguardLockedStateListener(
mMainExecutor, isKeyguardLocked -> notifyRecentTasksChanged());
}
@@ -205,7 +214,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
mTaskSplitBoundsMap.put(taskId1, splitBounds);
mTaskSplitBoundsMap.put(taskId2, splitBounds);
notifyRecentTasksChanged();
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Add split pair: %d, %d, %s",
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Add split pair: %d, %d, %s",
taskId1, taskId2, splitBounds);
return true;
}
@@ -221,7 +230,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
mTaskSplitBoundsMap.remove(taskId);
mTaskSplitBoundsMap.remove(pairedTaskId);
notifyRecentTasksChanged();
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Remove split pair: %d, %d",
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Remove split pair: %d, %d",
taskId, pairedTaskId);
}
}
@@ -234,7 +243,17 @@ public class RecentTasksController implements TaskStackListenerCallback,
// We could do extra verification of requiring both taskIds of a pair and verifying that
// the same split bounds object is returned... but meh. Seems unnecessary.
- return mTaskSplitBoundsMap.get(taskId);
+ SplitBounds splitBounds = mTaskSplitBoundsMap.get(taskId);
+ if (splitBounds != null) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "getSplitBoundsForTaskId: taskId=%d splitBoundsTasks=[%d, %d]", taskId,
+ splitBounds.leftTopTaskId, splitBounds.rightBottomTaskId);
+ } else {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "getSplitBoundsForTaskId: expected split bounds for taskId=%d but not found",
+ taskId);
+ }
+ return splitBounds;
}
@Override
@@ -249,7 +268,10 @@ public class RecentTasksController implements TaskStackListenerCallback,
@Override
public void onTaskStackChanged() {
- notifyRecentTasksChanged();
+ if (!enableShellTopTaskTracking()) {
+ // Skip notifying recent tasks changed whenever task stack changes
+ notifyRecentTasksChanged();
+ }
}
@Override
@@ -263,15 +285,29 @@ public class RecentTasksController implements TaskStackListenerCallback,
notifyRecentTasksChanged();
}
- public void onTaskAdded(ActivityManager.RunningTaskInfo taskInfo) {
+ /**
+ * This method only gets notified when a task is removed from recents as a result of another
+ * task being added to recent tasks.
+ */
+ @Override
+ public void onRecentTaskRemovedForAddTask(int taskId) {
+ mDesktopRepository.ifPresent(
+ repo -> repo.removeFreeformTask(INVALID_DISPLAY, taskId)
+ );
+ }
+
+ public void onTaskAdded(RunningTaskInfo taskInfo) {
notifyRunningTaskAppeared(taskInfo);
}
- public void onTaskRemoved(ActivityManager.RunningTaskInfo taskInfo) {
+ public void onTaskRemoved(RunningTaskInfo taskInfo) {
// Remove any split pairs associated with this task
removeSplitPair(taskInfo.taskId);
- notifyRecentTasksChanged();
notifyRunningTaskVanished(taskInfo);
+ if (!enableShellTopTaskTracking()) {
+ // Only notify recent tasks changed if we aren't already notifying the visible tasks
+ notifyRecentTasksChanged();
+ }
}
/**
@@ -279,7 +315,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
*
* This currently includes windowing mode and visibility.
*/
- public void onTaskRunningInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ public void onTaskRunningInfoChanged(RunningTaskInfo taskInfo) {
notifyRecentTasksChanged();
notifyRunningTaskChanged(taskInfo);
}
@@ -290,14 +326,21 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
@Override
+ public void onTaskMovedToFrontThroughTransition(RunningTaskInfo runningTaskInfo) {
+ notifyTaskMovedToFront(runningTaskInfo);
+ }
+
+ @Override
public void onTaskChangedThroughTransition(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
notifyTaskInfoChanged(taskInfo);
}
@Override
- public void onTaskMovedToFrontThroughTransition(
- ActivityManager.RunningTaskInfo runningTaskInfo) {
- notifyTaskMovedToFront(runningTaskInfo);
+ public void onVisibleTasksChanged(@NonNull List<? extends RunningTaskInfo> visibleTasks) {
+ mVisibleTasks.clear();
+ mVisibleTasks.addAll(visibleTasks);
+ // Notify with all the info and not just the running task info
+ notifyVisibleTasksChanged(visibleTasks);
}
@VisibleForTesting
@@ -316,7 +359,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
/**
* Notify the running task listener that a task appeared on desktop environment.
*/
- private void notifyRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
+ private void notifyRunningTaskAppeared(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
|| taskInfo.realActivity == null) {
@@ -330,9 +373,25 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
/**
+ * Notify the running task listener that a task was changed on desktop environment.
+ */
+ private void notifyRunningTaskChanged(RunningTaskInfo taskInfo) {
+ if (mListener == null
+ || !shouldEnableRunningTasksForDesktopMode()
+ || taskInfo.realActivity == null) {
+ return;
+ }
+ try {
+ mListener.onRunningTaskChanged(taskInfo);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed call onRunningTaskChanged", e);
+ }
+ }
+
+ /**
* Notify the running task listener that a task was removed on desktop environment.
*/
- private void notifyRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ private void notifyRunningTaskVanished(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
|| taskInfo.realActivity == null) {
@@ -346,25 +405,30 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
/**
- * Notify the running task listener that a task was changed on desktop environment.
+ * Notify the recents task listener that a task moved to front via a transition.
*/
- private void notifyRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
if (mListener == null
- || !shouldEnableRunningTasksForDesktopMode()
- || taskInfo.realActivity == null) {
+ || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
+ || taskInfo.realActivity == null
+ || enableShellTopTaskTracking()) {
return;
}
try {
- mListener.onRunningTaskChanged(taskInfo);
+ mListener.onTaskMovedToFront(GroupedTaskInfo.forFullscreenTasks(taskInfo));
} catch (RemoteException e) {
- Slog.w(TAG, "Failed call onRunningTaskChanged", e);
+ Slog.w(TAG, "Failed call onTaskMovedToFront", e);
}
}
+ /**
+ * Notify the recents task listener that a task changed via a transition.
+ */
private void notifyTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
if (mListener == null
|| !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
- || taskInfo.realActivity == null) {
+ || taskInfo.realActivity == null
+ || enableShellTopTaskTracking()) {
return;
}
try {
@@ -374,17 +438,21 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
}
- private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ /**
+ * Notifies that the test of visible tasks have changed.
+ */
+ private void notifyVisibleTasksChanged(@NonNull List<? extends RunningTaskInfo> visibleTasks) {
if (mListener == null
|| !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
- || taskInfo.realActivity == null) {
+ || !enableShellTopTaskTracking()) {
return;
}
try {
- GroupedTaskInfo runningTask = GroupedTaskInfo.forFullscreenTasks(taskInfo);
- mListener.onTaskMovedToFront(new GroupedTaskInfo[]{ runningTask });
+ // Compute the visible recent tasks in order, and move the task to the top
+ mListener.onVisibleTasksChanged(generateList(visibleTasks)
+ .toArray(new GroupedTaskInfo[0]));
} catch (RemoteException e) {
- Slog.w(TAG, "Failed call onTaskMovedToFront", e);
+ Slog.w(TAG, "Failed call onVisibleTasksChanged", e);
}
}
@@ -397,6 +465,11 @@ public class RecentTasksController implements TaskStackListenerCallback,
@VisibleForTesting
void registerRecentTasksListener(IRecentTasksListener listener) {
mListener = listener;
+ if (enableShellTopTaskTracking()) {
+ ProtoLog.v(WM_SHELL_TASK_OBSERVER, "registerRecentTasksListener");
+ // Post a notification for the current set of visible tasks
+ mMainExecutor.executeDelayed(() -> notifyVisibleTasksChanged(mVisibleTasks), 0);
+ }
}
@VisibleForTesting
@@ -411,14 +484,18 @@ public class RecentTasksController implements TaskStackListenerCallback,
@VisibleForTesting
ArrayList<GroupedTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
- // Note: the returned task list is from the most-recent to least-recent order
- final List<RecentTaskInfo> rawList = mActivityTaskManager.getRecentTasks(
- maxNum, flags, userId);
+ // Note: the returned task list is ordered from the most-recent to least-recent order
+ return generateList(mActivityTaskManager.getRecentTasks(maxNum, flags, userId));
+ }
+ /**
+ * Generates a list of GroupedTaskInfos for the given list of tasks.
+ */
+ private <T extends TaskInfo> ArrayList<GroupedTaskInfo> generateList(@NonNull List<T> tasks) {
// Make a mapping of task id -> task info
final SparseArray<TaskInfo> rawMapping = new SparseArray<>();
- for (int i = 0; i < rawList.size(); i++) {
- final TaskInfo taskInfo = rawList.get(i);
+ for (int i = 0; i < tasks.size(); i++) {
+ final TaskInfo taskInfo = tasks.get(i);
rawMapping.put(taskInfo.taskId, taskInfo);
}
@@ -427,10 +504,10 @@ public class RecentTasksController implements TaskStackListenerCallback,
int mostRecentFreeformTaskIndex = Integer.MAX_VALUE;
+ ArrayList<GroupedTaskInfo> groupedTasks = new ArrayList<>();
// Pull out the pairs as we iterate back in the list
- ArrayList<GroupedTaskInfo> recentTasks = new ArrayList<>();
- for (int i = 0; i < rawList.size(); i++) {
- final RecentTaskInfo taskInfo = rawList.get(i);
+ for (int i = 0; i < tasks.size(); i++) {
+ final TaskInfo taskInfo = tasks.get(i);
if (!rawMapping.contains(taskInfo.taskId)) {
// If it's not in the mapping, then it was already paired with another task
continue;
@@ -441,7 +518,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
&& mDesktopRepository.get().isActiveTask(taskInfo.taskId)) {
// Freeform tasks will be added as a separate entry
if (mostRecentFreeformTaskIndex == Integer.MAX_VALUE) {
- mostRecentFreeformTaskIndex = recentTasks.size();
+ mostRecentFreeformTaskIndex = groupedTasks.size();
}
// If task has their app bounds set to null which happens after reboot, set the
// app bounds to persisted lastFullscreenBounds. Also set the position in parent
@@ -461,36 +538,38 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
final int pairedTaskId = mSplitTasks.get(taskInfo.taskId, INVALID_TASK_ID);
- if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(
- pairedTaskId)) {
+ if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) {
final TaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
rawMapping.remove(pairedTaskId);
- recentTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
+ groupedTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
mTaskSplitBoundsMap.get(pairedTaskId)));
} else {
- recentTasks.add(GroupedTaskInfo.forFullscreenTasks(taskInfo));
+ if (Flags.enableRefactorTaskThumbnail() && isWallpaperTask(taskInfo)) {
+ // Don't add the wallpaper task as an entry in grouped tasks
+ continue;
+ }
+ // TODO(346588978): Consolidate multiple visible fullscreen tasks into the same
+ // grouped task
+ groupedTasks.add(GroupedTaskInfo.forFullscreenTasks(taskInfo));
}
}
// Add a special entry for freeform tasks
if (!freeformTasks.isEmpty()) {
- recentTasks.add(mostRecentFreeformTaskIndex,
+ groupedTasks.add(mostRecentFreeformTaskIndex,
GroupedTaskInfo.forFreeformTasks(
freeformTasks,
minimizedFreeformTasks));
}
- return recentTasks;
- }
+ if (enableShellTopTaskTracking()) {
+ // We don't current send pinned tasks as a part of recent or running tasks, so remove
+ // them from the list here
+ groupedTasks.removeIf(
+ gti -> gti.getTaskInfo1().getWindowingMode() == WINDOWING_MODE_PINNED);
+ }
- /**
- * Returns the top running leaf task.
- */
- @Nullable
- public ActivityManager.RunningTaskInfo getTopRunningTask() {
- List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1,
- false /* filterOnlyVisibleRecents */);
- return tasks.isEmpty() ? null : tasks.get(0);
+ return groupedTasks;
}
/**
@@ -498,12 +577,13 @@ public class RecentTasksController implements TaskStackListenerCallback,
* NOTE: This path currently makes assumptions that ignoreTaskToken is for the top task.
*/
@Nullable
- public ActivityManager.RunningTaskInfo getTopRunningTask(
+ public RunningTaskInfo getTopRunningTask(
@Nullable WindowContainerToken ignoreTaskToken) {
- List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(2,
- false /* filterOnlyVisibleRecents */);
+ final List<RunningTaskInfo> tasks = enableShellTopTaskTracking()
+ ? mVisibleTasks
+ : mActivityTaskManager.getTasks(2, false /* filterOnlyVisibleRecents */);
for (int i = 0; i < tasks.size(); i++) {
- final ActivityManager.RunningTaskInfo task = tasks.get(i);
+ final RunningTaskInfo task = tasks.get(i);
if (task.token.equals(ignoreTaskToken)) {
continue;
}
@@ -541,7 +621,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
/**
- * Find the background task that match the given taskId.
+ * Find the background task (in the recent tasks list) that matches the given taskId.
*/
@Nullable
public RecentTaskInfo findTaskInBackground(int taskId) {
@@ -603,8 +683,10 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
mTransitionHandler.addTransitionStateListener(new RecentsTransitionStateListener() {
@Override
- public void onAnimationStateChanged(boolean running) {
- executor.execute(() -> listener.accept(running));
+ public void onTransitionStateChanged(@RecentsTransitionState int state) {
+ executor.execute(() -> {
+ listener.accept(RecentsTransitionStateListener.isAnimating(state));
+ });
}
});
});
@@ -638,29 +720,34 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
@Override
- public void onRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
+ public void onRunningTaskAppeared(RunningTaskInfo taskInfo) {
mListener.call(l -> l.onRunningTaskAppeared(taskInfo));
}
@Override
- public void onRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ public void onRunningTaskVanished(RunningTaskInfo taskInfo) {
mListener.call(l -> l.onRunningTaskVanished(taskInfo));
}
@Override
- public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ public void onRunningTaskChanged(RunningTaskInfo taskInfo) {
mListener.call(l -> l.onRunningTaskChanged(taskInfo));
}
@Override
- public void onTaskMovedToFront(GroupedTaskInfo[] taskInfo) {
- mListener.call(l -> l.onTaskMovedToFront(taskInfo));
+ public void onTaskMovedToFront(GroupedTaskInfo taskToFront) {
+ mListener.call(l -> l.onTaskMovedToFront(taskToFront));
}
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
mListener.call(l -> l.onTaskInfoChanged(taskInfo));
}
+
+ @Override
+ public void onVisibleTasksChanged(GroupedTaskInfo[] visibleTasks) {
+ mListener.call(l -> l.onVisibleTasksChanged(visibleTasks));
+ }
};
public IRecentTasksImpl(RecentTasksController controller) {
@@ -714,12 +801,12 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
@Override
- public ActivityManager.RunningTaskInfo[] getRunningTasks(int maxNum) {
- final ActivityManager.RunningTaskInfo[][] tasks =
- new ActivityManager.RunningTaskInfo[][]{null};
+ public RunningTaskInfo[] getRunningTasks(int maxNum) {
+ final RunningTaskInfo[][] tasks =
+ new RunningTaskInfo[][]{null};
executeRemoteCallWithTaskPermission(mController, "getRunningTasks",
(controller) -> tasks[0] = ActivityTaskManager.getInstance().getTasks(maxNum)
- .toArray(new ActivityManager.RunningTaskInfo[0]),
+ .toArray(new RunningTaskInfo[0]),
true /* blocking */);
return tasks[0];
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 9016c45e8197..032dac9ff3a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -32,6 +32,9 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
+import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_ANIMATING;
+import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING;
+import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
import static com.android.wm.shell.shared.split.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_END_RECENTS_TRANSITION;
@@ -166,13 +169,19 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
// only care about latest one.
mAnimApp = appThread;
+ for (int i = 0; i < mStateListeners.size(); i++) {
+ mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_REQUESTED);
+ }
// TODO(b/366021931): Formalize this later
- final boolean isSyntheticRequest = options.containsKey("is_synthetic_recents_transition");
+ final boolean isSyntheticRequest = options.getBoolean(
+ "is_synthetic_recents_transition", /* defaultValue= */ false);
+ final IBinder transition;
if (isSyntheticRequest) {
- return startSyntheticRecentsTransition(listener);
+ transition = startSyntheticRecentsTransition(listener);
} else {
- return startRealRecentsTransition(intent, fillIn, options, listener);
+ transition = startRealRecentsTransition(intent, fillIn, options, listener);
}
+ return transition;
}
/**
@@ -542,7 +551,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
mPendingFinishTransition = null;
mControllers.remove(this);
for (int i = 0; i < mStateListeners.size(); i++) {
- mStateListeners.get(i).onAnimationStateChanged(false);
+ mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_NOT_RUNNING);
}
}
@@ -578,7 +587,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
new RemoteAnimationTarget[0],
new Rect(0, 0, 0, 0), new Rect(), new Bundle());
for (int i = 0; i < mStateListeners.size(); i++) {
- mStateListeners.get(i).onAnimationStateChanged(true);
+ mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_ANIMATING);
}
} catch (RemoteException e) {
Slog.e(TAG, "Error starting recents animation", e);
@@ -809,7 +818,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]),
new Rect(0, 0, 0, 0), new Rect(), b);
for (int i = 0; i < mStateListeners.size(); i++) {
- mStateListeners.get(i).onAnimationStateChanged(true);
+ mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_ANIMATING);
}
} catch (RemoteException e) {
Slog.e(TAG, "Error starting recents animation", e);
@@ -1286,6 +1295,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
if (mFinishCB == null
|| (Flags.enableShellTopTaskTracking() && mPendingFinishTransition != null)) {
Slog.e(TAG, "Duplicate call to finish");
+ if (runnerFinishCb != null) {
+ try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "[%d] RecentsController.finishInner: calling finish callback",
+ mInstanceId);
+ runnerFinishCb.send(0, null);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to report transition finished", e);
+ }
+ }
return;
}
@@ -1298,6 +1317,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
// otherwise a new transition will notify the relevant observers
if (returningToApp && allAppsAreTranslucent(mPausingTasks)) {
mHomeTransitionObserver.notifyHomeVisibilityChanged(true);
+ } else if (!toHome && mState == STATE_NEW_TASK
+ && allAppsAreTranslucent(mOpeningTasks)) {
+ // We are opening a translucent app. Launcher is still visible so we do nothing.
} else if (!toHome) {
// For some transitions, we may have notified home activity that it became
// visible. We need to notify the observer that we are no longer going home.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java
index 95874c8193c9..ea7cfd374f71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java
@@ -16,12 +16,47 @@
package com.android.wm.shell.recents;
-import android.os.IBinder;
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/** The listener for the events from {@link RecentsTransitionHandler}. */
public interface RecentsTransitionStateListener {
- /** Notifies whether the recents animation is running. */
- default void onAnimationStateChanged(boolean running) {
+ @IntDef(prefix = { "TRANSITION_STATE_" }, value = {
+ TRANSITION_STATE_NOT_RUNNING,
+ TRANSITION_STATE_REQUESTED,
+ TRANSITION_STATE_ANIMATING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RecentsTransitionState {}
+
+ int TRANSITION_STATE_NOT_RUNNING = 1;
+ int TRANSITION_STATE_REQUESTED = 2;
+ int TRANSITION_STATE_ANIMATING = 3;
+
+ /** Notifies whether the recents transition state changes. */
+ default void onTransitionStateChanged(@RecentsTransitionState int state) {
+ }
+
+ /** Returns whether the recents transition is running. */
+ static boolean isRunning(@RecentsTransitionState int state) {
+ return state >= TRANSITION_STATE_REQUESTED;
+ }
+
+ /** Returns whether the recents transition is animating. */
+ static boolean isAnimating(@RecentsTransitionState int state) {
+ return state >= TRANSITION_STATE_ANIMATING;
+ }
+
+ /** Returns a string representation of the given state. */
+ static String stateToString(@RecentsTransitionState int state) {
+ return switch (state) {
+ case TRANSITION_STATE_NOT_RUNNING -> "TRANSITION_STATE_NOT_RUNNING";
+ case TRANSITION_STATE_REQUESTED -> "TRANSITION_STATE_REQUESTED";
+ case TRANSITION_STATE_ANIMATING -> "TRANSITION_STATE_ANIMATING";
+ default -> "UNKNOWN";
+ };
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
index d28a462546f9..93f2e4cf0e45 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -17,37 +17,162 @@
package com.android.wm.shell.recents
import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
import android.os.IBinder
import android.util.ArrayMap
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.window.DesktopModeFlags
import android.window.TransitionInfo
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.Flags.enableShellTopTaskTracking
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER
import com.android.wm.shell.shared.TransitionUtil
+import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import dagger.Lazy
+import java.io.PrintWriter
+import java.util.StringJoiner
import java.util.concurrent.Executor
/**
- * A [Transitions.TransitionObserver] that observes shell transitions and sends updates to listeners
- * about task stack changes.
+ * A [Transitions.TransitionObserver] that observes shell transitions, tracks the visible tasks
+ * and notifies listeners whenever the visible tasks change (at the start and end of a transition).
*
- * TODO(346588978) Move split/pip signals here as well so that launcher don't need to handle it
+ * This can be replaced once we have a generalized task repository tracking visible tasks.
*/
class TaskStackTransitionObserver(
+ shellInit: ShellInit,
+ private val shellTaskOrganizer: Lazy<ShellTaskOrganizer>,
+ private val shellCommandHandler: ShellCommandHandler,
private val transitions: Lazy<Transitions>,
- shellInit: ShellInit
-) : Transitions.TransitionObserver {
+) : Transitions.TransitionObserver, ShellTaskOrganizer.TaskVanishedListener {
+
+ // List of currently visible tasks sorted in z-order from top-most to bottom-most, only used
+ // when Flags.enableShellTopTaskTracking() is enabled.
+ private var visibleTasks: MutableList<RunningTaskInfo> = mutableListOf()
+ private val pendingCloseTasks: MutableList<RunningTaskInfo> = mutableListOf()
+ // Set of listeners to notify when the visible tasks change
private val taskStackTransitionObserverListeners =
ArrayMap<TaskStackTransitionObserverListener, Executor>()
+ // Used to filter out leaf-tasks
+ private val leafTaskFilter: TransitionUtil.LeafTaskFilter = TransitionUtil.LeafTaskFilter()
init {
shellInit.addInitCallback(::onInit, this)
}
fun onInit() {
+ shellTaskOrganizer.get().addTaskVanishedListener(this)
+ shellCommandHandler.addDumpCallback(::dump, this)
transitions.get().registerObserver(this)
+
+ // TODO(346588978): We need to update the running tasks once the ShellTaskOrganizer is
+ // registered since there is no existing transition (yet) corresponding for the already
+ // visible tasks
+ }
+
+ /**
+ * This method handles transition ready when only
+ * DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL is set.
+ */
+ private fun onDesktopOnlyFlagTransitionReady(info: TransitionInfo) {
+ for (change in info.changes) {
+ if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
+ continue
+ }
+
+ val taskInfo = change.taskInfo
+ if (taskInfo == null || taskInfo.taskId == -1) {
+ continue
+ }
+
+ // Find the first task that is opening, this should be the one at the front after
+ // the transition
+ if (TransitionUtil.isOpeningType(change.mode)) {
+ notifyOnTaskMovedToFront(taskInfo)
+ break
+ } else if (change.mode == TRANSIT_CHANGE) {
+ notifyOnTaskChanged(taskInfo)
+ }
+ }
+ }
+
+ /**
+ * This method handles transition ready when Flags.enableShellTopTaskTracking() is set.
+ */
+ private fun onShellTopTaskTrackerFlagTransitionReady(info: TransitionInfo) {
+ ProtoLog.v(WM_SHELL_TASK_OBSERVER, "Transition ready: %d", info.debugId)
+
+ // Filter out non-leaf tasks (we will likely need them later, but visible task tracking
+ // is currently used only for visible leaf tasks)
+ val changesReversed = mutableListOf<TransitionInfo.Change>()
+ for (change in info.changes) {
+ if (!leafTaskFilter.test(change)) {
+ // Not a leaf task
+ continue
+ }
+ changesReversed.add(0, change)
+ }
+
+ // We iterate the change list in reverse order because changes are sorted top to bottom and
+ // we want to update the lists such that the top most tasks are inserted at the front last
+ var notifyChanges = false
+ for (change in changesReversed) {
+ val taskInfo = change.taskInfo
+ if (taskInfo == null || taskInfo.taskId == -1) {
+ // Not a valid task
+ continue
+ }
+
+ if (TransitionUtil.isClosingMode(change.mode)) {
+ ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tClosing task=%d", taskInfo.taskId)
+
+ // Closing task's visibilities are not committed until after the transition
+ // completes, so track such tasks so that we can notify on finish
+ if (!pendingCloseTasks.any { it.taskId == taskInfo.taskId }) {
+ pendingCloseTasks.add(taskInfo)
+ }
+ } else if (TransitionUtil.isOpeningMode(change.mode)
+ || TransitionUtil.isOrderOnly(change)) {
+ ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tOpening task=%d", taskInfo.taskId)
+
+ // Remove from pending close tasks list if it's being opened again
+ pendingCloseTasks.removeIf { it.taskId == taskInfo.taskId }
+ // Move the task to the front of the visible tasks list
+ visibleTasks.removeIf { it.taskId == taskInfo.taskId }
+ visibleTasks.add(0, taskInfo)
+ notifyChanges = true
+ }
+ }
+
+ // TODO(346588978): We should verify the task list has actually changed before notifying
+ // (ie. starting an activity that's already top-most would result in no visible change)
+ if (notifyChanges) {
+ updateVisibleTasksList("transition-start")
+ }
+ }
+
+ private fun updateVisibleTasksList(reason: String) {
+ // This simply constructs a list of visible tasks, where the always-on-top tasks are moved
+ // to the front of the list in-order, to ensure that they match the visible z order
+ val orderedVisibleTasks = mutableListOf<RunningTaskInfo>()
+ var numAlwaysOnTop = 0
+ for (info in visibleTasks) {
+ if (info.windowingMode == WINDOWING_MODE_PINNED
+ || info.configuration.windowConfiguration.isAlwaysOnTop) {
+ orderedVisibleTasks.add(numAlwaysOnTop, info)
+ numAlwaysOnTop++
+ } else {
+ orderedVisibleTasks.add(info)
+ }
+ }
+ visibleTasks = orderedVisibleTasks
+
+ dumpVisibleTasks(reason)
+ notifyVisibleTasksChanged(visibleTasks)
}
override fun onTransitionReady(
@@ -56,26 +181,10 @@ class TaskStackTransitionObserver(
startTransaction: SurfaceControl.Transaction,
finishTransaction: SurfaceControl.Transaction
) {
- if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) {
- for (change in info.changes) {
- if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
- continue
- }
-
- val taskInfo = change.taskInfo
- if (taskInfo == null || taskInfo.taskId == -1) {
- continue
- }
-
- // Find the first task that is opening, this should be the one at the front after
- // the transition
- if (TransitionUtil.isOpeningType(change.mode)) {
- notifyOnTaskMovedToFront(taskInfo)
- break
- } else if (change.mode == TRANSIT_CHANGE) {
- notifyOnTaskChanged(taskInfo)
- }
- }
+ if (enableShellTopTaskTracking()) {
+ onShellTopTaskTrackerFlagTransitionReady(info)
+ } else if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) {
+ onDesktopOnlyFlagTransitionReady(info)
}
}
@@ -83,8 +192,35 @@ class TaskStackTransitionObserver(
override fun onTransitionMerged(merged: IBinder, playing: IBinder) {}
- override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {}
+ override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
+ if (enableShellTopTaskTracking()) {
+ if (pendingCloseTasks.isNotEmpty()) {
+ // Update the visible task list based on the pending close tasks
+ for (change in pendingCloseTasks) {
+ visibleTasks.removeIf {
+ it.taskId == change.taskId
+ }
+ }
+ updateVisibleTasksList("transition-finished")
+ }
+ }
+ }
+ override fun onTaskVanished(taskInfo: RunningTaskInfo?) {
+ if (!enableShellTopTaskTracking()) {
+ return
+ }
+ ProtoLog.v(WM_SHELL_TASK_OBSERVER, "Task vanished: task=%d", taskInfo?.taskId)
+ pendingCloseTasks.removeIf { it.taskId == taskInfo?.taskId }
+ if (visibleTasks.any { it.taskId == taskInfo?.taskId }) {
+ visibleTasks.removeIf { it.taskId == taskInfo?.taskId }
+ updateVisibleTasksList("task-vanished")
+ }
+ }
+
+ /**
+ * Adds a new task stack observer.
+ */
fun addTaskStackTransitionObserverListener(
taskStackTransitionObserverListener: TaskStackTransitionObserverListener,
executor: Executor
@@ -92,6 +228,9 @@ class TaskStackTransitionObserver(
taskStackTransitionObserverListeners[taskStackTransitionObserverListener] = executor
}
+ /**
+ * Removes an existing task stack observer.
+ */
fun removeTaskStackTransitionObserverListener(
taskStackTransitionObserverListener: TaskStackTransitionObserverListener
) {
@@ -99,22 +238,66 @@ class TaskStackTransitionObserver(
}
private fun notifyOnTaskMovedToFront(taskInfo: RunningTaskInfo) {
+ if (enableShellTopTaskTracking()) {
+ return
+ }
taskStackTransitionObserverListeners.forEach { (listener, executor) ->
executor.execute { listener.onTaskMovedToFrontThroughTransition(taskInfo) }
}
}
private fun notifyOnTaskChanged(taskInfo: RunningTaskInfo) {
+ if (enableShellTopTaskTracking()) {
+ return
+ }
taskStackTransitionObserverListeners.forEach { (listener, executor) ->
executor.execute { listener.onTaskChangedThroughTransition(taskInfo) }
}
}
+ private fun notifyVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) {
+ taskStackTransitionObserverListeners.forEach { (listener, executor) ->
+ executor.execute { listener.onVisibleTasksChanged(visibleTasks) }
+ }
+ }
+
+ fun dump(pw: PrintWriter, prefix: String) {
+ pw.println("${prefix}$TAG:")
+
+ if (visibleTasks.isEmpty()) {
+ pw.println("$prefix visibleTasks=[]")
+ } else {
+ val stringJoiner = StringJoiner(",\n\t", "[\n\t", "\n]")
+ visibleTasks.forEach {
+ stringJoiner.add("id=${it.taskId} cmp=${it.baseIntent.component}")
+ }
+ pw.println("$prefix visibleTasks=$stringJoiner")
+ }
+ }
+
+ /** Dumps the set of visible tasks to protolog */
+ private fun dumpVisibleTasks(reason: String) {
+ if (!WM_SHELL_TASK_OBSERVER.isEnabled) {
+ return
+ }
+ ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tVisible tasks (%s)", reason)
+ for (task in visibleTasks) {
+ ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\t\ttaskId=%d package=%s", task.taskId,
+ task.baseIntent.component?.packageName)
+ }
+ }
+
/** Listener to use to get updates regarding task stack from this observer */
interface TaskStackTransitionObserverListener {
/** Called when a task is moved to front. */
fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {}
+ /** Called when the set of visible tasks have changed. */
+ fun onVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) {}
/** Called when a task info has changed. */
fun onTaskChangedThroughTransition(taskInfo: RunningTaskInfo) {}
}
+
+ companion object {
+ const val TAG = "TaskStackTransitionObserver"
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 3e6d36ce0ca3..39ed9abcfd26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -54,10 +54,27 @@ public interface SplitScreen {
*/
int STAGE_TYPE_SIDE = 1;
+ /**
+ * Position independent stage identifier for a given Stage
+ */
+ int STAGE_TYPE_A = 2;
+ /**
+ * Position independent stage identifier for a given Stage
+ */
+ int STAGE_TYPE_B = 3;
+ /**
+ * Position independent stage identifier for a given Stage
+ */
+ int STAGE_TYPE_C = 4;
+
@IntDef(prefix = { "STAGE_TYPE_" }, value = {
STAGE_TYPE_UNDEFINED,
STAGE_TYPE_MAIN,
- STAGE_TYPE_SIDE
+ STAGE_TYPE_SIDE,
+ // Used for flexible split
+ STAGE_TYPE_A,
+ STAGE_TYPE_B,
+ STAGE_TYPE_C
})
@interface StageType {}
@@ -128,6 +145,9 @@ public interface SplitScreen {
case STAGE_TYPE_UNDEFINED: return "UNDEFINED";
case STAGE_TYPE_MAIN: return "MAIN";
case STAGE_TYPE_SIDE: return "SIDE";
+ case STAGE_TYPE_A: return "STAGE_A";
+ case STAGE_TYPE_B: return "STAGE_B";
+ case STAGE_TYPE_C: return "STAGE_C";
default: return "UNKNOWN(" + stage + ")";
}
}
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 6398d31b4f82..4f0f6760a951 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
@@ -24,6 +24,7 @@ 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;
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.common.MultiInstanceHelper.getComponent;
import static com.android.wm.shell.common.MultiInstanceHelper.getShortcutComponent;
import static com.android.wm.shell.common.MultiInstanceHelper.samePackage;
@@ -33,6 +34,9 @@ import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMes
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -98,6 +102,7 @@ import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.annotations.ExternalThread;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex;
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.sysui.KeyguardChangeListener;
@@ -325,7 +330,6 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
/**
* @return an Array of RunningTaskInfo's ordered by leftToRight or topTopBottom
*/
- @Nullable
public ActivityManager.RunningTaskInfo[] getAllTaskInfos() {
// TODO(b/349828130) Add the third stage task info and not rely on positions
ActivityManager.RunningTaskInfo topLeftTask = getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
@@ -335,7 +339,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
return new ActivityManager.RunningTaskInfo[]{topLeftTask, bottomRightTask};
}
- return null;
+ return new ActivityManager.RunningTaskInfo[0];
}
/** Check task is under split or not by taskId. */
@@ -405,7 +409,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
public void prepareEnterSplitScreen(WindowContainerTransaction wct,
ActivityManager.RunningTaskInfo taskInfo, int startPosition) {
mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition,
- false /* resizeAnim */);
+ false /* resizeAnim */, SPLIT_INDEX_UNDEFINED);
}
/**
@@ -451,6 +455,24 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
}
}
+ /**
+ * Determines which split index a new instance of a task should take.
+ * @param callingTask The task requesting a new instance.
+ * @return the split index of the new instance
+ */
+ @SplitIndex
+ public int determineNewInstanceIndex(@NonNull ActivityManager.RunningTaskInfo callingTask) {
+ if (!enableFlexibleSplit()) {
+ throw new IllegalStateException("Use determineNewInstancePosition");
+ }
+ if (callingTask.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ || getSplitPosition(callingTask.taskId) == SPLIT_POSITION_TOP_OR_LEFT) {
+ return SPLIT_INDEX_1;
+ } else {
+ return SPLIT_INDEX_0;
+ }
+ }
+
public void enterSplitScreen(int taskId, boolean leftOrTop) {
enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
}
@@ -685,7 +707,10 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startIntentWithInstanceId: reason=%d",
ENTER_REASON_LAUNCHER);
mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
- startIntent(intent, userId, fillInIntent, position, options, null /* hideTaskToken */);
+ // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+ // specific cases in the future. Only focusing on parity with starting intent/task
+ startIntent(intent, userId, fillInIntent, position, options, null /* hideTaskToken */,
+ SPLIT_INDEX_UNDEFINED);
}
private void startIntentAndTask(PendingIntent pendingIntent, int userId1,
@@ -775,9 +800,9 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
@Override
public void startIntent(PendingIntent intent, int userId1, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options,
- @Nullable WindowContainerToken hideTaskToken) {
+ @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
startIntent(intent, userId1, fillInIntent, position, options, hideTaskToken,
- false /* forceLaunchNewTask */);
+ false /* forceLaunchNewTask */, index);
}
/**
@@ -790,7 +815,8 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
*/
public void startIntent(PendingIntent intent, int userId1, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options,
- @Nullable WindowContainerToken hideTaskToken, boolean forceLaunchNewTask) {
+ @Nullable WindowContainerToken hideTaskToken, boolean forceLaunchNewTask,
+ @SplitIndex int index) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"startIntent(): intent=%s user=%d fillInIntent=%s position=%d", intent, userId1,
fillInIntent, position);
@@ -816,7 +842,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
if (taskInfo != null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Found suitable background task=%s", taskInfo);
- mStageCoordinator.startTask(taskInfo.taskId, position, options, hideTaskToken);
+ mStageCoordinator.startTask(taskInfo.taskId, position, options, hideTaskToken, index);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Start task in background");
return;
@@ -841,7 +867,8 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
}
}
- mStageCoordinator.startIntent(intent, fillInIntent, position, options, hideTaskToken);
+ mStageCoordinator.startIntent(intent, fillInIntent, position, options, hideTaskToken,
+ index);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 840049412db4..3091be574a53 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -21,6 +21,7 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_IN;
@@ -55,6 +56,9 @@ import com.android.wm.shell.transition.OneShotRemoteHandler;
import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Executor;
/** Manages transition animations for split-screen. */
@@ -268,22 +272,21 @@ class SplitScreenTransitions {
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
- @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
- @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
+ @NonNull Map<WindowContainerToken, SplitDecorManager> rootDecorMap) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "playResizeAnimation: transition=%d", info.getDebugId());
initTransition(transition, finishTransaction, finishCallback);
+ Set<WindowContainerToken> rootDecorKeys = rootDecorMap.keySet();
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (mainRoot.equals(change.getContainer()) || sideRoot.equals(change.getContainer())) {
+ if (rootDecorKeys.contains(change.getContainer())) {
final SurfaceControl leash = change.getLeash();
startTransaction.setPosition(leash, change.getEndAbsBounds().left,
change.getEndAbsBounds().top);
startTransaction.setWindowCrop(leash, change.getEndAbsBounds().width(),
change.getEndAbsBounds().height());
- SplitDecorManager decor = mainRoot.equals(change.getContainer())
- ? mainDecor : sideDecor;
+ SplitDecorManager decor = rootDecorMap.get(change.getContainer());
// This is to ensure onFinished be called after all animations ended.
ValueAnimator va = new ValueAnimator();
@@ -433,15 +436,22 @@ class SplitScreenTransitions {
Transitions.TransitionHandler handler,
@Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishCallback,
- @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
+ @Nullable SplitDecorManager mainDecor, @Nullable SplitDecorManager sideDecor,
+ @Nullable List<SplitDecorManager> decorManagers) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
" splitTransition deduced Resize split screen.");
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setResizeTransition: hasPendingResize=%b",
mPendingResize != null);
if (mPendingResize != null) {
mPendingResize.cancel(null);
- mainDecor.cancelRunningAnimations();
- sideDecor.cancelRunningAnimations();
+ if (enableFlexibleSplit()) {
+ for (SplitDecorManager stage : decorManagers) {
+ stage.cancelRunningAnimations();
+ }
+ } else {
+ mainDecor.cancelRunningAnimations();
+ sideDecor.cancelRunningAnimations();
+ }
mAnimations.clear();
onFinish(null /* wct */);
}
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 cc0e1df115c2..88a95660f098 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
@@ -33,16 +33,16 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
-import static com.android.wm.shell.common.split.SplitScreenUtils.isPartiallyOffscreen;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
-import static com.android.wm.shell.shared.TransitionUtil.isOrderOnly;
import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
@@ -51,11 +51,13 @@ import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.shared.split.SplitScreenConstants.splitPositionToString;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_A;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_B;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_LAUNCHER;
-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_CHILD_TASK_ENTER_PIP;
@@ -133,6 +135,7 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.split.OffscreenTouchZone;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenUtils;
@@ -143,6 +146,7 @@ import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.split.SplitBounds;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex;
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
@@ -154,11 +158,15 @@ import dalvik.annotation.optimization.NeverCompile;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Coordinates the staging (visibility, sizing, ...) of the split-screen stages.
@@ -179,10 +187,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// entered
private static final int DISABLE_LAUNCH_ADJACENT_AFTER_ENTER_TIMEOUT_MS = 1000;
- private final StageTaskListener mMainStage;
- private final StageTaskListener mSideStage;
+ private StageTaskListener mMainStage;
+ private StageTaskListener mSideStage;
@SplitPosition
private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
+ private StageOrderOperator mStageOrderOperator;
private final int mDisplayId;
private SplitLayout mSplitLayout;
@@ -312,6 +321,20 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSyncQueue.runInSync(t -> applyDividerVisibility(t));
}
}
+
+ @Override
+ public void inflateOnStageRoot(OffscreenTouchZone touchZone) {
+ SurfaceControl topLeftLeash =
+ mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+ ? mMainStage.mRootLeash : mSideStage.mRootLeash;
+ SurfaceControl bottomRightLeash =
+ mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+ ? mSideStage.mRootLeash : mMainStage.mRootLeash;
+ touchZone.inflate(
+ mContext.createConfigurationContext(mRootTaskInfo.configuration),
+ mRootTaskInfo.configuration, mSyncQueue,
+ touchZone.isTopLeft() ? topLeftLeash : bottomRightLeash);
+ }
};
protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
@@ -336,22 +359,32 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Creating main/side root task");
- mMainStage = new StageTaskListener(
- mContext,
- mTaskOrganizer,
- mDisplayId,
- this /*stageListenerCallbacks*/,
- mSyncQueue,
- iconProvider,
- mWindowDecorViewModel);
- mSideStage = new StageTaskListener(
- mContext,
- mTaskOrganizer,
- mDisplayId,
- this /*stageListenerCallbacks*/,
- mSyncQueue,
- iconProvider,
- mWindowDecorViewModel);
+ if (enableFlexibleSplit()) {
+ mStageOrderOperator = new StageOrderOperator(mContext,
+ mTaskOrganizer,
+ mDisplayId,
+ this /*stageListenerCallbacks*/,
+ mSyncQueue,
+ iconProvider,
+ mWindowDecorViewModel);
+ } else {
+ mMainStage = new StageTaskListener(
+ mContext,
+ mTaskOrganizer,
+ mDisplayId,
+ this /*stageListenerCallbacks*/,
+ mSyncQueue,
+ iconProvider,
+ mWindowDecorViewModel, STAGE_TYPE_MAIN);
+ mSideStage = new StageTaskListener(
+ mContext,
+ mTaskOrganizer,
+ mDisplayId,
+ this /*stageListenerCallbacks*/,
+ mSyncQueue,
+ iconProvider,
+ mWindowDecorViewModel, STAGE_TYPE_SIDE);
+ }
mDisplayController = displayController;
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
@@ -423,24 +456,70 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
public boolean isSplitScreenVisible() {
- return mSideStage.mVisible && mMainStage.mVisible;
+ if (enableFlexibleSplit()) {
+ return runForActiveStagesAllMatch((stage) -> stage.mVisible);
+ } else {
+ return mSideStage.mVisible && mMainStage.mVisible;
+ }
}
- private void activateSplit(WindowContainerTransaction wct, boolean includingTopTask) {
- mMainStage.activate(wct, includingTopTask);
+ /**
+ * @param includingTopTask reparents the current top task into the stage defined by index
+ * (or mainStage in legacy split)
+ * @param index the index to move the current visible task into, if undefined will arbitrarily
+ * choose a stage to launch into
+ */
+ private void activateSplit(WindowContainerTransaction wct, boolean includingTopTask,
+ int index) {
+ if (enableFlexibleSplit()) {
+ mStageOrderOperator.onEnteringSplit(SNAP_TO_2_50_50);
+ if (index == SPLIT_INDEX_UNDEFINED || !includingTopTask) {
+ // If we aren't includingTopTask, then the call to activate on the stage is
+ // effectively a no-op. Previously the stage kept track of the "isActive" state,
+ // but now that gets set in the "onEnteringSplit" call above.
+ //
+ // index == UNDEFINED case might change, but as of now no use case where we activate
+ // without an index specified.
+ return;
+ }
+ @SplitIndex int oppositeIndex = index == SPLIT_INDEX_0 ? SPLIT_INDEX_1 : SPLIT_INDEX_0;
+ StageTaskListener activatingStage = mStageOrderOperator.getStageForIndex(oppositeIndex);
+ activatingStage.activate(wct, includingTopTask);
+ } else {
+ mMainStage.activate(wct, includingTopTask);
+ }
}
public boolean isSplitActive() {
- return mMainStage.isActive();
+ if (enableFlexibleSplit()) {
+ return mStageOrderOperator.isActive();
+ } else {
+ return mMainStage.isActive();
+ }
}
/**
* Deactivates main stage by removing the stage from the top level split root (usually when a
* task underneath gets removed from the stage root).
- * @param reparentToTop whether we want to put the stage root back on top
+ * @param stageToTop stage which we want to put on top
*/
- private void deactivateSplit(WindowContainerTransaction wct, boolean reparentToTop) {
- mMainStage.deactivate(wct, reparentToTop);
+ private void deactivateSplit(WindowContainerTransaction wct, @StageType int stageToTop) {
+ if (enableFlexibleSplit()) {
+ StageTaskListener stageToDeactivate = mStageOrderOperator.getAllStages().stream()
+ .filter(stage -> stage.getId() == stageToTop)
+ .findFirst().orElse(null);
+ if (stageToDeactivate != null) {
+ stageToDeactivate.deactivate(wct, true /*toTop*/);
+ } else {
+ // If no one stage is meant to go to the top, deactivate all stages to move any
+ // child tasks out from under their respective stage root tasks.
+ mStageOrderOperator.getAllStages().forEach(stage ->
+ stage.deactivate(wct, false /*reparentTasksToTop*/));
+ }
+ mStageOrderOperator.onExitingSplit();
+ } else {
+ mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
+ }
}
/** @return whether this transition-request has the launch-adjacent flag. */
@@ -464,11 +543,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// If one of the splitting tasks support auto-pip, wm-core might reparent the task to TDA
// and file a TRANSIT_PIP transition when finishing transitions.
// @see com.android.server.wm.RootWindowContainer#moveActivityToPinnedRootTask
- if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
- return true;
+ if (enableFlexibleSplit()) {
+ return mStageOrderOperator.getActiveStages().stream()
+ .anyMatch(stage -> stage.getChildCount() == 0);
+ } else {
+ return mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0;
}
-
- return false;
}
/** Checks if `transition` is a pending enter-split transition. */
@@ -478,10 +558,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@StageType
int getStageOfTask(int taskId) {
- if (mMainStage.containsTask(taskId)) {
- return STAGE_TYPE_MAIN;
- } else if (mSideStage.containsTask(taskId)) {
- return STAGE_TYPE_SIDE;
+ if (enableFlexibleSplit()) {
+ StageTaskListener stageTaskListener = mStageOrderOperator.getActiveStages().stream()
+ .filter(stage -> stage.containsTask(taskId))
+ .findFirst().orElse(null);
+ if (stageTaskListener != null) {
+ return stageTaskListener.getId();
+ }
+ } else {
+ if (mMainStage.containsTask(taskId)) {
+ return STAGE_TYPE_MAIN;
+ } else if (mSideStage.containsTask(taskId)) {
+ return STAGE_TYPE_SIDE;
+ }
}
return STAGE_TYPE_UNDEFINED;
@@ -491,14 +580,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskId) {
return true;
}
- return mMainStage.isRootTaskId(taskId) || mSideStage.isRootTaskId(taskId);
+ if (enableFlexibleSplit()) {
+ return mStageOrderOperator.getActiveStages().stream()
+ .anyMatch((stage) -> stage.isRootTaskId(taskId));
+ } else {
+ return mMainStage.isRootTaskId(taskId) || mSideStage.isRootTaskId(taskId);
+ }
}
boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
WindowContainerTransaction wct) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "moveToStage: task=%d position=%d", task.taskId,
stagePosition);
- prepareEnterSplitScreen(wct, task, stagePosition, false /* resizeAnim */);
+ // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+ // specific cases in the future. Only focusing on parity with starting intent/task
+ prepareEnterSplitScreen(wct, task, stagePosition, false /* resizeAnim */,
+ SPLIT_INDEX_UNDEFINED);
mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct,
null, this,
isSplitScreenVisible()
@@ -596,11 +693,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
* same window container transaction as the starting of the intent.
*/
void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options,
- @Nullable WindowContainerToken hideTaskToken) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startTask: task=%d position=%d", taskId, position);
+ @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startTask: task=%d position=%d index=%d",
+ taskId, position, index);
mSplitRequest = new SplitRequest(taskId, position);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
+ options = enableFlexibleSplit()
+ ? resolveStartStageForIndex(options, null /*wct*/, index)
+ : resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
if (hideTaskToken != null) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Reordering hide-task to bottom");
wct.reorder(hideTaskToken, false /* onTop */);
@@ -624,7 +724,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = isSplitActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
- prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
+ prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering, index);
mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
extraTransitType, !mIsDropEntering);
@@ -636,13 +736,16 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
* same window container transaction as the starting of the intent.
*/
void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
- @Nullable Bundle options, @Nullable WindowContainerToken hideTaskToken) {
+ @Nullable Bundle options, @Nullable WindowContainerToken hideTaskToken,
+ @SplitIndex int index) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startIntent: intent=%s position=%d", intent.getIntent(),
position);
mSplitRequest = new SplitRequest(intent.getIntent(), position);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
+ options = enableFlexibleSplit()
+ ? resolveStartStageForIndex(options, null /*wct*/, index)
+ : resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
if (hideTaskToken != null) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Reordering hide-task to bottom");
wct.reorder(hideTaskToken, false /* onTop */);
@@ -667,13 +770,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = isSplitActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
- prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
+ prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering, index);
mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
extraTransitType, !mIsDropEntering);
}
- /** Starts 2 tasks in one transition. */
+ /**
+ * Starts 2 tasks in one transition.
+ * @param taskId1 starts in the mSideStage
+ * @param taskId2 starts in the mainStage #startWithTask()
+ */
void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2,
@SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition,
@Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
@@ -688,11 +795,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
- addActivityOptions(options1, mSideStage);
+ StageTaskListener stageForTask1;
+ if (enableFlexibleSplit()) {
+ stageForTask1 = mStageOrderOperator.getStageForLegacyPosition(splitPosition,
+ true /*checkAllStagesIfNotActive*/);
+ } else {
+ stageForTask1 = mSideStage;
+ }
+ addActivityOptions(options1, stageForTask1);
prepareTasksForSplitScreen(new int[] {taskId1, taskId2}, wct);
wct.startTask(taskId1, options1);
- startWithTask(wct, taskId2, options2, snapPosition, remoteTransition, instanceId);
+ startWithTask(wct, taskId2, options2, snapPosition, remoteTransition, instanceId,
+ splitPosition);
}
/** Start an intent and a task to a split pair in one transition. */
@@ -722,7 +837,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
prepareTasksForSplitScreen(new int[] {taskId}, wct);
- startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId);
+ startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId,
+ splitPosition);
}
/**
@@ -766,7 +882,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
prepareTasksForSplitScreen(new int[] {taskId}, wct);
- startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId);
+ startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId,
+ splitPosition);
}
/**
@@ -796,11 +913,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
*/
private void startWithTask(WindowContainerTransaction wct, int mainTaskId,
@Nullable Bundle mainOptions, @PersistentSnapPosition int snapPosition,
- @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+ @Nullable RemoteTransition remoteTransition, InstanceId instanceId,
+ @SplitPosition int splitPosition) {
if (!isSplitActive()) {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
- activateSplit(wct, false /* reparentToTop */);
+ // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+ // specific cases in the future. Only focusing on parity with starting intent/task
+ activateSplit(wct, false /* reparentToTop */, SPLIT_INDEX_UNDEFINED);
}
mSplitLayout.setDivideRatio(snapPosition);
updateWindowBounds(mSplitLayout, wct);
@@ -808,10 +928,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
false /* reparentLeafTaskIfRelaunch */);
setRootForceTranslucent(false, wct);
-
+ // All callers of this method set the correct activity options on mSideStage,
+ // so we choose the opposite stage for this method
+ StageTaskListener stage;
+ if (enableFlexibleSplit()) {
+ stage = mStageOrderOperator
+ .getStageForLegacyPosition(reverseSplitPosition(splitPosition),
+ false /*checkAllStagesIfNotActive*/);
+ } else {
+ stage = mMainStage;
+ }
// Make sure the launch options will put tasks in the corresponding split roots
mainOptions = mainOptions != null ? mainOptions : new Bundle();
- addActivityOptions(mainOptions, mMainStage);
+ addActivityOptions(mainOptions, stage);
// Add task launch requests
wct.startTask(mainTaskId, mainOptions);
@@ -867,7 +996,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!isSplitActive()) {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
- activateSplit(wct, false /* reparentToTop */);
+ // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+ // specific cases in the future. Only focusing on parity with starting intent/task
+ activateSplit(wct, false /* reparentToTop */, SPLIT_INDEX_UNDEFINED);
}
setSideStagePosition(splitPosition, wct);
@@ -975,6 +1106,31 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSideStage.evictInvisibleChildren(wct);
}
+ /**
+ * @param index for the new stage that will be opening. Ex. if app is dragged to
+ * index=1, then this will tell the stage at index=1 to launch the task
+ * in the wct in that stage. This doesn't verify that the non-specified
+ * indices' stages have their tasks correctly set/re-parented.
+ */
+ Bundle resolveStartStageForIndex(@Nullable Bundle options,
+ @Nullable WindowContainerTransaction wct,
+ @SplitIndex int index) {
+ StageTaskListener oppositeStage;
+ if (index == SPLIT_INDEX_UNDEFINED) {
+ // Arbitrarily choose a stage
+ oppositeStage = mStageOrderOperator.getStageForIndex(SPLIT_INDEX_1);
+ } else {
+ oppositeStage = mStageOrderOperator.getStageForIndex(index);
+ }
+ if (options == null) {
+ options = new Bundle();
+ }
+ updateStageWindowBoundsForIndex(wct, index);
+ addActivityOptions(options, oppositeStage);
+
+ return options;
+ }
+
Bundle resolveStartStage(@StageType int stage, @SplitPosition int position,
@Nullable Bundle options, @Nullable WindowContainerTransaction wct) {
switch (stage) {
@@ -1042,20 +1198,35 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return INVALID_TASK_ID;
}
- return mSideStagePosition == splitPosition
- ? mSideStage.getTopVisibleChildTaskId()
- : mMainStage.getTopVisibleChildTaskId();
+ if (enableFlexibleSplit()) {
+ StageTaskListener stage = mStageOrderOperator.getStageForLegacyPosition(splitPosition,
+ true /*checkAllStagesIfNotActive*/);
+ return stage != null ? stage.getTopVisibleChildTaskId() : INVALID_TASK_ID;
+ } else {
+ return mSideStagePosition == splitPosition
+ ? mSideStage.getTopVisibleChildTaskId()
+ : mMainStage.getTopVisibleChildTaskId();
+ }
}
void switchSplitPosition(String reason) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "switchSplitPosition");
final SurfaceControl.Transaction t = mTransactionPool.acquire();
mTempRect1.setEmpty();
- final StageTaskListener topLeftStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
- final StageTaskListener bottomRightStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
-
+ final StageTaskListener topLeftStage;
+ final StageTaskListener bottomRightStage;
+ if (enableFlexibleSplit()) {
+ topLeftStage = mStageOrderOperator.getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+ false /*checkAllStagesIfNotActive*/);
+ bottomRightStage = mStageOrderOperator
+ .getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+ false /*checkAllStagesIfNotActive*/);
+ } else {
+ topLeftStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+ bottomRightStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+ }
// Don't allow windows or divider to be focused during animation (mRootTaskInfo is the
// parent of all 3 leaves). We don't want the user to be able to tap and focus a window
// while it is moving across the screen, because granting focus also recalculates the
@@ -1092,23 +1263,40 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
});
ProtoLog.v(WM_SHELL_SPLIT_SCREEN, "Switch split position: %s", reason);
- mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLeftRightSplit());
+ if (enableFlexibleSplit()) {
+ // TODO(b/374825718) update logging for 2+ apps
+ } else {
+ mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+ getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+ mSplitLayout.isLeftRightSplit());
+ }
}
void setSideStagePosition(@SplitPosition int sideStagePosition,
@Nullable WindowContainerTransaction wct) {
- setSideStagePosition(sideStagePosition, true /* updateBounds */, wct);
- }
-
- private void setSideStagePosition(@SplitPosition int sideStagePosition, boolean updateBounds,
- @Nullable WindowContainerTransaction wct) {
if (mSideStagePosition == sideStagePosition) return;
mSideStagePosition = sideStagePosition;
sendOnStagePositionChanged();
+ StageTaskListener stage = enableFlexibleSplit()
+ ? mStageOrderOperator.getStageForLegacyPosition(mSideStagePosition,
+ true /*checkAllStagesIfNotActive*/)
+ : mSideStage;
- if (mSideStage.mVisible && updateBounds) {
+ if (stage.mVisible) {
+ if (wct == null) {
+ // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
+ onLayoutSizeChanged(mSplitLayout);
+ } else {
+ updateWindowBounds(mSplitLayout, wct);
+ sendOnBoundsChanged();
+ }
+ }
+ }
+
+ private void updateStageWindowBoundsForIndex(@Nullable WindowContainerTransaction wct,
+ @SplitIndex int index) {
+ StageTaskListener stage = mStageOrderOperator.getStageForIndex(index);
+ if (stage.mVisible) {
if (wct == null) {
// onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
onLayoutSizeChanged(mSplitLayout);
@@ -1158,10 +1346,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
void recordLastActiveStage() {
if (!isSplitActive() || !isSplitScreenVisible()) {
mLastActiveStage = STAGE_TYPE_UNDEFINED;
- } else if (mMainStage.isFocused()) {
- mLastActiveStage = STAGE_TYPE_MAIN;
- } else if (mSideStage.isFocused()) {
- mLastActiveStage = STAGE_TYPE_SIDE;
+ } else if (enableFlexibleSplit()) {
+ mStageOrderOperator.getActiveStages().stream()
+ .filter(StageTaskListener::isFocused)
+ .findFirst()
+ .ifPresent(stage -> mLastActiveStage = stage.getId());
+ } else {
+ if (mMainStage.isFocused()) {
+ mLastActiveStage = STAGE_TYPE_MAIN;
+ } else if (mSideStage.isFocused()) {
+ mLastActiveStage = STAGE_TYPE_SIDE;
+ }
}
}
@@ -1218,7 +1413,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
mSideStage.removeAllTasks(wct, false /* toTop */);
- deactivateSplit(wct, false /* reparentToTop */);
+ deactivateSplit(wct, STAGE_TYPE_UNDEFINED);
wct.reorder(mRootTaskInfo.token, false /* onTop */);
setRootForceTranslucent(true, wct);
wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
@@ -1247,7 +1442,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
childrenToTop.fadeOutDecor(() -> {
WindowContainerTransaction finishedWCT = new WindowContainerTransaction();
mIsExiting = false;
- deactivateSplit(finishedWCT, childrenToTop == mMainStage /* reparentToTop */);
+ deactivateSplit(finishedWCT, childrenToTop.getId());
mSideStage.removeAllTasks(finishedWCT, childrenToTop == mSideStage /* toTop */);
finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
setRootForceTranslucent(true, finishedWCT);
@@ -1275,6 +1470,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(stage, wct);
mSplitTransitions.startDismissTransition(wct, this, stage, exitReason);
+ // reset stages to their default sides.
+ setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null);
logExit(exitReason);
}
@@ -1362,15 +1559,24 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
void clearSplitPairedInRecents(@ExitReason int exitReason) {
- if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return;
+ if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearSplitPairedInRecents: skipping reason=%s",
+ !mShouldUpdateRecents ? "shouldn't update" : exitReasonToString(exitReason));
+ return;
+ }
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearSplitPairedInRecents: reason=%s",
exitReasonToString(exitReason));
mRecentTasks.ifPresent(recentTasks -> {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
- mMainStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
- mSideStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+ if (enableFlexibleSplit()) {
+ runForActiveStages((stage) ->
+ stage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId)));
+ } else {
+ mMainStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+ mSideStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+ }
});
logExit(exitReason);
}
@@ -1383,15 +1589,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
void prepareExitSplitScreen(@StageType int stageToTop,
@NonNull WindowContainerTransaction wct) {
if (!isSplitActive()) return;
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%d", stageToTop);
- mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
- deactivateSplit(wct, stageToTop == STAGE_TYPE_MAIN);
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%s",
+ stageTypeToString(stageToTop));
+ if (enableFlexibleSplit()) {
+ mStageOrderOperator.getActiveStages().stream()
+ .filter(stage -> stage.getId() != stageToTop)
+ .forEach(stage -> stage.removeAllTasks(wct, false /*toTop*/));
+ } else {
+ mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
+ }
+ deactivateSplit(wct, stageToTop);
}
private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareEnterSplitScreen");
prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED,
- !mIsDropEntering);
+ !mIsDropEntering, SPLIT_INDEX_UNDEFINED);
}
/**
@@ -1400,7 +1613,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
*/
void prepareEnterSplitScreen(WindowContainerTransaction wct,
@Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
- boolean resizeAnim) {
+ boolean resizeAnim, @SplitIndex int index) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareEnterSplitScreen: position=%d resize=%b",
startPosition, resizeAnim);
onSplitScreenEnter();
@@ -1412,7 +1625,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (isSplitActive()) {
prepareBringSplit(wct, taskInfo, startPosition, resizeAnim);
} else {
- prepareActiveSplit(wct, taskInfo, startPosition, resizeAnim);
+ prepareActiveSplit(wct, taskInfo, startPosition, resizeAnim, index);
}
}
@@ -1433,14 +1646,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!mSkipEvictingMainStageChildren) {
mMainStage.evictAllChildren(wct);
}
- mMainStage.reparentTopTask(wct);
+ // TODO(b/349828130) revisit bring split from BG to FG scenarios
+ if (enableFlexibleSplit()) {
+ runForActiveStages(stage -> stage.reparentTopTask(wct));
+ } else {
+ mMainStage.reparentTopTask(wct);
+ }
prepareSplitLayout(wct, resizeAnim);
}
}
+ /**
+ * @param index The index that has already been assigned a stage
+ */
private void prepareActiveSplit(WindowContainerTransaction wct,
@Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
- boolean resizeAnim) {
+ boolean resizeAnim, @SplitIndex int index) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareActiveSplit: task=%d isSplitVisible=%b",
taskInfo != null ? taskInfo.taskId : -1, isSplitScreenVisible());
// We handle split visibility itself on shell transition, but sometimes we didn't
@@ -1450,7 +1671,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setSideStagePosition(startPosition, wct);
mSideStage.addTask(taskInfo, wct);
}
- activateSplit(wct, true /* reparentToTop */);
+ activateSplit(wct, true /* reparentToTop */, index);
prepareSplitLayout(wct, resizeAnim);
}
@@ -1477,8 +1698,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "finishEnterSplitScreen");
mSplitLayout.update(null, true /* resetImePosition */);
- mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash);
- mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash);
+ if (enableFlexibleSplit()) {
+ runForActiveStages((stage) ->
+ stage.getSplitDecorManager().inflate(mContext, stage.mRootLeash));
+ } else {
+ mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash);
+ mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash);
+ }
setDividerVisibility(true, finishT);
// Ensure divider surface are re-parented back into the hierarchy at the end of the
// transition. See Transition#buildFinishTransaction for more detail.
@@ -1492,6 +1718,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitRequest = null;
updateRecentTasksSplitPair();
+ if (enableFlexibleSplit()) {
+ // TODO(b/374825718) log 2+ apps
+ return;
+ }
mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
getMainStagePosition(), mMainStage.getTopChildTaskUid(),
getSideStagePosition(), mSideStage.getTopChildTaskUid(),
@@ -1499,8 +1729,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
- outTopOrLeftBounds.set(mSplitLayout.getBounds1());
- outBottomOrRightBounds.set(mSplitLayout.getBounds2());
+ outTopOrLeftBounds.set(mSplitLayout.getTopLeftBounds());
+ outBottomOrRightBounds.set(mSplitLayout.getBottomRightBounds());
+ }
+
+ private void runForActiveStages(Consumer<StageTaskListener> consumer) {
+ mStageOrderOperator.getActiveStages().forEach(consumer);
+ }
+
+ private boolean runForActiveStagesAllMatch(Predicate<StageTaskListener> predicate) {
+ List<StageTaskListener> activeStages = mStageOrderOperator.getActiveStages();
+ return !activeStages.isEmpty() && activeStages.stream().allMatch(predicate);
}
@SplitPosition
@@ -1516,6 +1755,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void addActivityOptions(Bundle opts, @Nullable StageTaskListener launchTarget) {
ActivityOptions options = ActivityOptions.fromBundle(opts);
if (launchTarget != null) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+ "addActivityOptions setting launch root for stage=%s",
+ stageTypeToString(launchTarget.getId()));
options.setLaunchRootTask(launchTarget.mRootTaskInfo.token);
}
// Put BAL flags to avoid activity start aborted. Otherwise, flows like shortcut to split
@@ -1559,8 +1801,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
listener.onSplitBoundsChanged(mSplitLayout.getRootBounds(), getMainStageBounds(),
getSideStageBounds());
}
- mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
- mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+ if (enableFlexibleSplit()) {
+ // TODO(b/349828130) replace w/ stageID
+ mStageOrderOperator.getAllStages().forEach(
+ stage -> stage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_UNDEFINED)
+ );
+ } else {
+ mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
+ mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+ }
}
private void sendOnStagePositionChanged() {
@@ -1584,20 +1833,43 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
boolean present, boolean visible) {
int stage;
if (present) {
- stage = stageListener == mSideStage ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
+ if (enableFlexibleSplit()) {
+ stage = stageListener.getId();
+ } else {
+ stage = stageListener == mSideStage ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
+ }
} else {
// No longer on any stage
stage = STAGE_TYPE_UNDEFINED;
}
- if (stage == STAGE_TYPE_MAIN) {
- mLogger.logMainStageAppChange(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- mSplitLayout.isLeftRightSplit());
- } else if (stage == STAGE_TYPE_SIDE) {
- mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLeftRightSplit());
+ if (!enableFlexibleSplit()) {
+ if (stage == STAGE_TYPE_MAIN) {
+ mLogger.logMainStageAppChange(getMainStagePosition(),
+ mMainStage.getTopChildTaskUid(),
+ mSplitLayout.isLeftRightSplit());
+ } else if (stage == STAGE_TYPE_SIDE) {
+ mLogger.logSideStageAppChange(getSideStagePosition(),
+ mSideStage.getTopChildTaskUid(),
+ mSplitLayout.isLeftRightSplit());
+ }
}
if (present) {
updateRecentTasksSplitPair();
+ } else {
+ // TODO (b/349828130): Test b/333270112 for flex split (launch adjacent for flex
+ // currently not working)
+ boolean allRootsEmpty = enableFlexibleSplit()
+ ? runForActiveStagesAllMatch(stageTaskListener ->
+ stageTaskListener.getChildCount() == 0)
+ : mMainStage.getChildCount() == 0 && mSideStage.getChildCount() == 0;
+ if (allRootsEmpty) {
+ mRecentTasks.ifPresent(recentTasks -> {
+ // remove the split pair mapping from recentTasks, and disable further updates
+ // to splits in the recents until we enter split again.
+ recentTasks.removeSplitPair(taskId);
+ });
+ dismissSplitScreen(INVALID_TASK_ID, EXIT_REASON_ROOT_TASK_VANISHED);
+ }
}
for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -1608,22 +1880,45 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void updateRecentTasksSplitPair() {
// Preventing from single task update while processing recents.
if (!mShouldUpdateRecents || !mPausingTasks.isEmpty()) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "updateRecentTasksSplitPair: skipping reason=%s",
+ !mShouldUpdateRecents ? "shouldn't update" : "no pausing tasks");
return;
}
mRecentTasks.ifPresent(recentTasks -> {
- Rect topLeftBounds = mSplitLayout.getBounds1();
- Rect bottomRightBounds = mSplitLayout.getBounds2();
- int mainStageTopTaskId = mMainStage.getTopVisibleChildTaskId();
- int sideStageTopTaskId = mSideStage.getTopVisibleChildTaskId();
+ Rect topLeftBounds = new Rect();
+ mSplitLayout.copyTopLeftBounds(topLeftBounds);
+ Rect bottomRightBounds = new Rect();
+ mSplitLayout.copyBottomRightBounds(bottomRightBounds);
+
+ int sideStageTopTaskId;
+ int mainStageTopTaskId;
+ if (enableFlexibleSplit()) {
+ List<StageTaskListener> activeStages = mStageOrderOperator.getActiveStages();
+ if (activeStages.size() != 2) {
+ sideStageTopTaskId = mainStageTopTaskId = INVALID_TASK_ID;
+ } else {
+ // doesn't matter which one we assign to? What matters is the order of 0 and 1?
+ mainStageTopTaskId = activeStages.get(0).getTopVisibleChildTaskId();
+ sideStageTopTaskId = activeStages.get(1).getTopVisibleChildTaskId();
+ }
+ } else {
+ mainStageTopTaskId = mMainStage.getTopVisibleChildTaskId();
+ sideStageTopTaskId= mSideStage.getTopVisibleChildTaskId();
+ }
boolean sideStageTopLeft = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
int leftTopTaskId;
int rightBottomTaskId;
- if (sideStageTopLeft) {
- leftTopTaskId = sideStageTopTaskId;
- rightBottomTaskId = mainStageTopTaskId;
- } else {
+ if (enableFlexibleSplit()) {
leftTopTaskId = mainStageTopTaskId;
rightBottomTaskId = sideStageTopTaskId;
+ } else {
+ if (sideStageTopLeft) {
+ leftTopTaskId = sideStageTopTaskId;
+ rightBottomTaskId = mainStageTopTaskId;
+ } else {
+ leftTopTaskId = mainStageTopTaskId;
+ rightBottomTaskId = sideStageTopTaskId;
+ }
}
if (Flags.enableFlexibleTwoAppSplit()) {
@@ -1732,29 +2027,59 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@VisibleForTesting
@Override
public void onRootTaskAppeared() {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskAppeared: rootTask=%s mainRoot=%b sideRoot=%b",
- mRootTaskInfo, mMainStage.mHasRootTask, mSideStage.mHasRootTask);
+ if (enableFlexibleSplit()) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskAppeared: rootTask=%s",
+ mRootTaskInfo);
+ mStageOrderOperator.getAllStages().forEach(stage -> {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+ " onRootStageAppeared stageId=%s hasRoot=%b",
+ stageTypeToString(stage.getId()), stage.mHasRootTask);
+ });
+ } else {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+ "onRootTaskAppeared: rootTask=%s mainRoot=%b sideRoot=%b",
+ mRootTaskInfo, mMainStage.mHasRootTask, mSideStage.mHasRootTask);
+ }
+ boolean notAllStagesHaveRootTask;
+ if (enableFlexibleSplit()) {
+ notAllStagesHaveRootTask = mStageOrderOperator.getAllStages().stream()
+ .anyMatch((stage) -> !stage.mHasRootTask);
+ } else {
+ notAllStagesHaveRootTask = !mMainStage.mHasRootTask
+ || !mSideStage.mHasRootTask;
+ }
// Wait unit all root tasks appeared.
- if (mRootTaskInfo == null
- || !mMainStage.mHasRootTask
- || !mSideStage.mHasRootTask) {
+ if (mRootTaskInfo == null || notAllStagesHaveRootTask) {
return;
}
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(mMainStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
- wct.reparent(mSideStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+ if (enableFlexibleSplit()) {
+ mStageOrderOperator.getAllStages().forEach(stage ->
+ wct.reparent(stage.mRootTaskInfo.token, mRootTaskInfo.token, true));
+ } else {
+ wct.reparent(mMainStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+ wct.reparent(mSideStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+ }
- // Make the stages adjacent to each other so they occlude what's behind them.
- wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
setRootForceTranslucent(true, wct);
- mSplitLayout.getInvisibleBounds(mTempRect1);
- wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+ if (!enableFlexibleSplit()) {
+ //TODO(b/373709676) Need to figure out how adjacentRoots work for flex split
+
+ // Make the stages adjacent to each other so they occlude what's behind them.
+ wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
+ mSplitLayout.getInvisibleBounds(mTempRect1);
+ wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+ }
mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> {
- t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
- });
- mLaunchAdjacentController.setLaunchAdjacentRoot(mSideStage.mRootTaskInfo.token);
+ if (!enableFlexibleSplit()) {
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
+ });
+ mLaunchAdjacentController.setLaunchAdjacentRoot(mSideStage.mRootTaskInfo.token);
+ } else {
+ // TODO(b/373709676) Need to figure out how adjacentRoots work for flex split
+ }
}
@Override
@@ -1867,11 +2192,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDividerFadeInAnimator.cancel();
}
- mSplitLayout.getRefDividerBounds(mTempRect1);
if (t != null) {
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
t.setVisibility(dividerLeash, mDividerVisible);
- t.setLayer(dividerLeash, Integer.MAX_VALUE);
- t.setPosition(dividerLeash, mTempRect1.left, mTempRect1.top);
} else if (mDividerVisible) {
final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
mDividerFadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
@@ -1891,11 +2214,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDividerFadeInAnimator.cancel();
return;
}
- mSplitLayout.getRefDividerBounds(mTempRect1);
+ updateSurfaceBounds(mSplitLayout, transaction, false /* applyResizingOffset */);
transaction.show(dividerLeash);
transaction.setAlpha(dividerLeash, 0);
- transaction.setLayer(dividerLeash, Integer.MAX_VALUE);
- transaction.setPosition(dividerLeash, mTempRect1.left, mTempRect1.top);
transaction.apply();
}
@@ -1949,15 +2270,21 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onSnappedToDismiss(boolean bottomOrRight, @ExitReason int exitReason) {
+ public void onSnappedToDismiss(boolean closedBottomRightStage, @ExitReason int exitReason) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onSnappedToDismiss: bottomOrRight=%b reason=%s",
- bottomOrRight, exitReasonToString(exitReason));
- final boolean mainStageToTop =
- bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+ closedBottomRightStage, exitReasonToString(exitReason));
+ boolean mainStageToTop =
+ closedBottomRightStage ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
: mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
- final StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage;
-
- final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage;
+ int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ if (enableFlexibleSplit()) {
+ toTopStage = mStageOrderOperator.getStageForLegacyPosition(closedBottomRightStage
+ ? SPLIT_POSITION_TOP_OR_LEFT
+ : SPLIT_POSITION_BOTTOM_OR_RIGHT,
+ false /*checkAllStagesIfNotActive*/);
+ dismissTop = toTopStage.getId();
+ }
final WindowContainerTransaction wct = new WindowContainerTransaction();
toTopStage.resetBounds(wct);
prepareExitSplitScreen(dismissTop, wct);
@@ -1989,8 +2316,21 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
updateSurfaceBounds(layout, t, shouldUseParallaxEffect);
getMainStageBounds(mTempRect1);
getSideStageBounds(mTempRect2);
- mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately);
- mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately);
+ if (enableFlexibleSplit()) {
+ StageTaskListener ltStage =
+ mStageOrderOperator.getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+ false /*checkAllStagesIfNotActive*/);
+ StageTaskListener brStage =
+ mStageOrderOperator.getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+ false /*checkAllStagesIfNotActive*/);
+ ltStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately);
+ brStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately);
+ } else {
+ mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY,
+ mShowDecorImmediately);
+ mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY,
+ mShowDecorImmediately);
+ }
t.apply();
mTransactionPool.release(t);
}
@@ -2006,19 +2346,34 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!sizeChanged) {
// We still need to resize on decor for ensure all current status clear.
final SurfaceControl.Transaction t = mTransactionPool.acquire();
- mMainStage.onResized(t);
- mSideStage.onResized(t);
+ if (enableFlexibleSplit()) {
+ runForActiveStages(stage -> stage.onResized(t));
+ } else {
+ mMainStage.onResized(t);
+ mSideStage.onResized(t);
+ }
mTransactionPool.release(t);
return;
}
-
+ List<SplitDecorManager> decorManagers = new ArrayList<>();
+ SplitDecorManager mainDecor = null;
+ SplitDecorManager sideDecor = null;
+ if (enableFlexibleSplit()) {
+ decorManagers = mStageOrderOperator.getActiveStages().stream()
+ .map(StageTaskListener::getSplitDecorManager)
+ .toList();
+ } else {
+ mainDecor = mMainStage.getSplitDecorManager();
+ sideDecor = mSideStage.getSplitDecorManager();
+ }
sendOnBoundsChanged();
mSplitLayout.setDividerInteractive(false, false, "onSplitResizeStart");
mSplitTransitions.startResizeTransition(wct, this, (aborted) -> {
mSplitLayout.setDividerInteractive(true, false, "onSplitResizeConsumed");
}, (finishWct, t) -> {
mSplitLayout.setDividerInteractive(true, false, "onSplitResizeFinish");
- }, mMainStage.getSplitDecorManager(), mSideStage.getSplitDecorManager());
+ mSplitLayout.populateTouchZones();
+ }, mainDecor, sideDecor, decorManagers);
if (Flags.enableFlexibleTwoAppSplit()) {
switch (layout.calculateCurrentSnapPosition()) {
@@ -2045,29 +2400,55 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
* @return true if stage bounds actually .
*/
private boolean updateWindowBounds(SplitLayout layout, WindowContainerTransaction wct) {
- final StageTaskListener topLeftStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
- final StageTaskListener bottomRightStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+ final StageTaskListener topLeftStage;
+ final StageTaskListener bottomRightStage;
+ if (enableFlexibleSplit()) {
+ topLeftStage = mStageOrderOperator
+ .getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+ true /*checkAllStagesIfNotActive*/);
+ bottomRightStage = mStageOrderOperator
+ .getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+ true /*checkAllStagesIfNotActive*/);
+ } else {
+ topLeftStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+ ? mSideStage
+ : mMainStage;
+ bottomRightStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+ ? mMainStage
+ : mSideStage;
+ }
boolean updated = layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo,
bottomRightStage.mRootTaskInfo);
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "updateWindowBounds: topLeftStage=%s bottomRightStage=%s",
- layout.getBounds1(), layout.getBounds2());
+ layout.getTopLeftBounds(), layout.getBottomRightBounds());
return updated;
}
void updateSurfaceBounds(@Nullable SplitLayout layout, @NonNull SurfaceControl.Transaction t,
boolean applyResizingOffset) {
- final StageTaskListener topLeftStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
- final StageTaskListener bottomRightStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+ final StageTaskListener topLeftStage;
+ final StageTaskListener bottomRightStage;
+ if (enableFlexibleSplit()) {
+ topLeftStage = mStageOrderOperator
+ .getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+ true /*checkAllStagesIfNotActive*/);
+ bottomRightStage = mStageOrderOperator
+ .getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+ true /*checkAllStagesIfNotActive*/);
+ } else {
+ topLeftStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+ ? mSideStage
+ : mMainStage;
+ bottomRightStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+ ? mMainStage
+ : mSideStage;
+ }
(layout != null ? layout : mSplitLayout).applySurfaceChanges(t, topLeftStage.mRootLeash,
bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer,
applyResizingOffset);
ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
"updateSurfaceBounds: topLeftStage=%s bottomRightStage=%s",
- layout.getBounds1(), layout.getBounds2());
+ layout.getTopLeftBounds(), layout.getBottomRightBounds());
}
@Override
@@ -2076,10 +2457,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return SPLIT_POSITION_UNDEFINED;
}
- if (mMainStage.containsToken(token)) {
- return getMainStagePosition();
- } else if (mSideStage.containsToken(token)) {
- return getSideStagePosition();
+ if (enableFlexibleSplit()) {
+ // We could migrate to/return the new INDEX enums here since most callers just care that
+ // this value isn't SPLIT_POSITION_UNDEFINED, but
+ // ImePositionProcessor#getImeTargetPosition actually uses the leftTop/bottomRight value
+ StageTaskListener stageForToken = mStageOrderOperator.getAllStages().stream()
+ .filter(stage -> stage.containsToken(token))
+ .findFirst().orElse(null);
+ return stageForToken == null
+ ? SPLIT_POSITION_UNDEFINED
+ : mStageOrderOperator.getLegacyPositionForStage(stageForToken);
+ } else {
+ if (mMainStage.containsToken(token)) {
+ return getMainStagePosition();
+ } else if (mSideStage.containsToken(token)) {
+ return getSideStagePosition();
+ }
}
return SPLIT_POSITION_UNDEFINED;
@@ -2176,27 +2569,49 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private Rect getSideStageBounds() {
return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
- ? mSplitLayout.getBounds1() : mSplitLayout.getBounds2();
+ ? mSplitLayout.getTopLeftBounds() : mSplitLayout.getBottomRightBounds();
}
private Rect getMainStageBounds() {
return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
- ? mSplitLayout.getBounds2() : mSplitLayout.getBounds1();
+ ? mSplitLayout.getBottomRightBounds() : mSplitLayout.getTopLeftBounds();
}
+ /**
+ * TODO(b/349828130) Currently the way this is being used is only to to get the bottomRight
+ * stage. Eventually we'll need to rename and for now we'll repurpose the method to return
+ * the bottomRight bounds under the flex split flag
+ */
private void getSideStageBounds(Rect rect) {
- if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
- mSplitLayout.getBounds1(rect);
+ if (enableFlexibleSplit()) {
+ // Split Layout doesn't actually keep track of the bounds based on the stage,
+ // it only knows that bounds1 is leftTop position and bounds2 is bottomRight position
+ // We'll then assume this method is to get bounds of bottomRight stage
+ mSplitLayout.copyBottomRightBounds(rect);
+ } else if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
+ mSplitLayout.copyTopLeftBounds(rect);
} else {
- mSplitLayout.getBounds2(rect);
+ mSplitLayout.copyBottomRightBounds(rect);
}
}
+ /**
+ * TODO(b/349828130) Currently the way this is being used is only to to get the leftTop
+ * stage. Eventually we'll need to rename and for now we'll repurpose the method to return
+ * the leftTop bounds under the flex split flag
+ */
private void getMainStageBounds(Rect rect) {
- if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
- mSplitLayout.getBounds2(rect);
+ if (enableFlexibleSplit()) {
+ // Split Layout doesn't actually keep track of the bounds based on the stage,
+ // it only knows that bounds1 is leftTop position and bounds2 is bottomRight position
+ // We'll then assume this method is to get bounds of topLeft stage
+ mSplitLayout.copyTopLeftBounds(rect);
} else {
- mSplitLayout.getBounds1(rect);
+ if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
+ mSplitLayout.copyBottomRightBounds(rect);
+ } else {
+ mSplitLayout.copyTopLeftBounds(rect);
+ }
}
}
@@ -2205,14 +2620,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
* this task (yet) so this can also be used to identify which stage to put a task into.
*/
private StageTaskListener getStageOfTask(ActivityManager.RunningTaskInfo taskInfo) {
- // TODO(b/184679596): Find a way to either include task-org information in the transition,
- // or synchronize task-org callbacks so we can use stage.containsTask
- if (mMainStage.mRootTaskInfo != null
- && taskInfo.parentTaskId == mMainStage.mRootTaskInfo.taskId) {
- return mMainStage;
- } else if (mSideStage.mRootTaskInfo != null
- && taskInfo.parentTaskId == mSideStage.mRootTaskInfo.taskId) {
- return mSideStage;
+ if (enableFlexibleSplit()) {
+ return mStageOrderOperator.getActiveStages().stream()
+ .filter((stage) -> stage.mRootTaskInfo != null &&
+ taskInfo.parentTaskId == stage.mRootTaskInfo.taskId
+ )
+ .findFirst()
+ .orElse(null);
+ } else {
+ // TODO(b/184679596): Find a way to either include task-org information in the
+ // transition, or synchronize task-org callbacks so we can use stage.containsTask
+ if (mMainStage.mRootTaskInfo != null
+ && taskInfo.parentTaskId == mMainStage.mRootTaskInfo.taskId) {
+ return mMainStage;
+ } else if (mSideStage.mRootTaskInfo != null
+ && taskInfo.parentTaskId == mSideStage.mRootTaskInfo.taskId) {
+ return mSideStage;
+ }
}
return null;
}
@@ -2220,7 +2644,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@StageType
private int getStageType(StageTaskListener stage) {
if (stage == null) return STAGE_TYPE_UNDEFINED;
- return stage == mMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ if (enableFlexibleSplit()) {
+ return stage.getId();
+ } else {
+ return stage == mMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ }
}
@Override
@@ -2267,11 +2695,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (isSplitActive()) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d split active",
request.getDebugId());
+ StageTaskListener primaryStage = enableFlexibleSplit()
+ ? mStageOrderOperator.getActiveStages().get(0)
+ : mMainStage;
+ StageTaskListener secondaryStage = enableFlexibleSplit()
+ ? mStageOrderOperator.getActiveStages().get(1)
+ : mSideStage;
// Try to handle everything while in split-screen, so return a WCT even if it's empty.
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " split is active so using split"
+ "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
+ " sideChildren=%d", triggerTask.taskId, transitTypeToString(type),
- mMainStage.getChildCount(), mSideStage.getChildCount());
+ primaryStage.getChildCount(), secondaryStage.getChildCount());
out = new WindowContainerTransaction();
if (stage != null) {
if (isClosingType(type) && stage.getChildCount() == 1) {
@@ -2311,11 +2745,21 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// the remote handler.
return null;
}
-
- if ((mMainStage.containsTask(triggerTask.taskId)
- && mMainStage.getChildCount() == 1)
- || (mSideStage.containsTask(triggerTask.taskId)
- && mSideStage.getChildCount() == 1)) {
+ boolean anyStageContainsSingleFullscreenTask;
+ if (enableFlexibleSplit()) {
+ anyStageContainsSingleFullscreenTask =
+ mStageOrderOperator.getActiveStages().stream()
+ .anyMatch(stageListener ->
+ stageListener.containsTask(triggerTask.taskId)
+ && stageListener.getChildCount() == 1);
+ } else {
+ anyStageContainsSingleFullscreenTask =
+ (mMainStage.containsTask(triggerTask.taskId)
+ && mMainStage.getChildCount() == 1)
+ || (mSideStage.containsTask(triggerTask.taskId)
+ && mSideStage.getChildCount() == 1);
+ }
+ if (anyStageContainsSingleFullscreenTask) {
// A splitting task is opening to fullscreen causes one side of the split empty,
// so appends operations to exit split.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
@@ -2335,11 +2779,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// One of the cases above handled it
return out;
} else if (isSplitScreenVisible()) {
+ boolean allStagesHaveChildren;
+ if (enableFlexibleSplit()) {
+ allStagesHaveChildren = runForActiveStagesAllMatch(stageTaskListener ->
+ stageTaskListener.getChildCount() != 0);
+ } else {
+ allStagesHaveChildren = mMainStage.getChildCount() != 0
+ && mSideStage.getChildCount() != 0;
+ }
// If split is visible, only defer handling this transition if it's launching
// adjacent while there is already a split pair -- this may trigger PIP and
// that should be handled by the mixed handler.
final boolean deferTransition = requestHasLaunchAdjacentFlag(request)
- && mMainStage.getChildCount() != 0 && mSideStage.getChildCount() != 0;
+ && allStagesHaveChildren;
return !deferTransition ? out : null;
}
// Don't intercept the transition if we are not handling it as a part of one of the
@@ -2484,26 +2936,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mTaskOrganizer.applyTransaction(wct);
}
continue;
- } else if (Flags.enableFlexibleTwoAppSplit() && isOrderOnly(change)) {
- int focusedStageIndex = SPLIT_INDEX_UNDEFINED;
- if (taskInfo.token.equals(mMainStage.mRootTaskInfo.token)) {
- focusedStageIndex = mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
- ? SPLIT_INDEX_0 : SPLIT_INDEX_1;
- } else if (taskInfo.token.equals(mSideStage.mRootTaskInfo.token)) {
- focusedStageIndex = mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
- ? SPLIT_INDEX_1 : SPLIT_INDEX_0;
- }
-
- if (focusedStageIndex != SPLIT_INDEX_UNDEFINED) {
- @PersistentSnapPosition int currentSnapPosition =
- mSplitLayout.calculateCurrentSnapPosition();
- boolean offscreenTaskFocused =
- isPartiallyOffscreen(focusedStageIndex, currentSnapPosition);
-
- if (offscreenTaskFocused) {
- mSplitLayout.flingDividerToOtherSide(currentSnapPosition);
- }
- }
}
final StageTaskListener stage = getStageOfTask(taskInfo);
if (stage == null) {
@@ -2579,8 +3011,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage();
- if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0
- || dismissStages.size() == 1) {
+ boolean anyStageHasNoChildren;
+ if (enableFlexibleSplit()) {
+ anyStageHasNoChildren = mStageOrderOperator.getActiveStages().stream()
+ .anyMatch(stage -> stage.getChildCount() == 0);
+ } else {
+ anyStageHasNoChildren = mMainStage.getChildCount() == 0
+ || mSideStage.getChildCount() == 0;
+ }
+ if (anyStageHasNoChildren || dismissStages.size() == 1) {
// If the size of dismissStages == 1, one of the task is closed without prepare
// pending transition, which could happen if all activities were finished after
// finish top activity in a task, so the trigger task is null when handleRequest.
@@ -2726,24 +3165,48 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
shouldAnimate = startPendingDismissAnimation(
dismiss, info, startTransaction, finishTransaction);
if (shouldAnimate && dismiss.mReason == EXIT_REASON_DRAG_DIVIDER) {
- final StageTaskListener toTopStage =
- dismiss.mDismissTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage;
+ StageTaskListener toTopStage;
+ if (enableFlexibleSplit()) {
+ toTopStage = mStageOrderOperator.getAllStages().stream()
+ .filter(stage -> stage.getId() == dismiss.mDismissTop)
+ .findFirst().orElseThrow();
+ } else {
+ toTopStage = dismiss.mDismissTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage;
+ }
mSplitTransitions.playDragDismissAnimation(transition, info, startTransaction,
finishTransaction, finishCallback, toTopStage.mRootTaskInfo.token,
toTopStage.getSplitDecorManager(), mRootTaskInfo.token);
return true;
}
} else if (mSplitTransitions.isPendingResize(transition)) {
+ Map<WindowContainerToken, SplitDecorManager> tokenDecorMap = new HashMap<>();
+ if (enableFlexibleSplit()) {
+ runForActiveStages(stageTaskListener ->
+ tokenDecorMap.put(stageTaskListener.mRootTaskInfo.getToken(),
+ stageTaskListener.getSplitDecorManager()));
+ } else {
+ tokenDecorMap.put(mMainStage.mRootTaskInfo.getToken(),
+ mMainStage.getSplitDecorManager());
+ tokenDecorMap.put(mSideStage.mRootTaskInfo.getToken(),
+ mSideStage.getSplitDecorManager());
+ }
mSplitTransitions.playResizeAnimation(transition, info, startTransaction,
- finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token,
- mSideStage.mRootTaskInfo.token, mMainStage.getSplitDecorManager(),
- mSideStage.getSplitDecorManager());
+ finishTransaction, finishCallback, tokenDecorMap);
return true;
}
if (!shouldAnimate) return false;
+ WindowContainerToken mainToken;
+ WindowContainerToken sideToken;
+ if (enableFlexibleSplit()) {
+ mainToken = mStageOrderOperator.getActiveStages().get(0).mRootTaskInfo.token;
+ sideToken = mStageOrderOperator.getActiveStages().get(1).mRootTaskInfo.token;
+ } else {
+ mainToken = mMainStage.mRootTaskInfo.token;
+ sideToken = mSideStage.mRootTaskInfo.token;
+ }
mSplitTransitions.playAnimation(transition, info, startTransaction, finishTransaction,
- finishCallback, mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
+ finishCallback, mainToken, sideToken,
mRootTaskInfo.token);
return true;
}
@@ -2768,6 +3231,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// First, verify that we actually have opened apps in both splits.
TransitionInfo.Change mainChild = null;
TransitionInfo.Change sideChild = null;
+ StageTaskListener firstAppStage = null;
+ StageTaskListener secondAppStage = null;
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
@@ -2776,14 +3241,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mPausingTasks.contains(taskInfo.taskId)) {
continue;
}
- final @StageType int stageType = getStageType(getStageOfTask(taskInfo));
- if (mainChild == null && stageType == STAGE_TYPE_MAIN
+ StageTaskListener stage = getStageOfTask(taskInfo);
+ final @StageType int stageType = getStageType(stage);
+ if (mainChild == null
+ && stageType == (enableFlexibleSplit() ? STAGE_TYPE_A : STAGE_TYPE_MAIN)
&& (isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) {
// Includes TRANSIT_CHANGE to cover reparenting top-most task to split.
mainChild = change;
- } else if (sideChild == null && stageType == STAGE_TYPE_SIDE
+ firstAppStage = getStageOfTask(taskInfo);
+ } else if (sideChild == null
+ && stageType == (enableFlexibleSplit() ? STAGE_TYPE_B : STAGE_TYPE_SIDE)
&& (isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) {
sideChild = change;
+ secondAppStage = stage;
} else if (stageType != STAGE_TYPE_UNDEFINED && change.getMode() == TRANSIT_TO_BACK) {
// Collect all to back task's and evict them when transition finished.
evictWct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
@@ -2839,9 +3309,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// TODO(b/184679596): Find a way to either include task-org information in
// the transition, or synchronize task-org callbacks.
final boolean mainNotContainOpenTask =
- mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId);
+ mainChild != null && !firstAppStage.containsTask(mainChild.getTaskInfo().taskId);
final boolean sideNotContainOpenTask =
- sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId);
+ sideChild != null && !secondAppStage.containsTask(sideChild.getTaskInfo().taskId);
if (mainNotContainOpenTask) {
Log.w(TAG, "Expected onTaskAppeared on " + mMainStage
+ " to have been called with " + mainChild.getTaskInfo().taskId
@@ -2854,6 +3324,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
final TransitionInfo.Change finalMainChild = mainChild;
final TransitionInfo.Change finalSideChild = sideChild;
+ final StageTaskListener finalFirstAppStage = firstAppStage;
+ final StageTaskListener finalSecondAppStage = secondAppStage;
enterTransition.setFinishedCallback((callbackWct, callbackT) -> {
if (!enterTransition.mResizeAnim) {
// If resizing, we'll call notify at the end of the resizing animation (below)
@@ -2861,16 +3333,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
if (finalMainChild != null) {
if (!mainNotContainOpenTask) {
- mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
+ finalFirstAppStage.evictOtherChildren(callbackWct,
+ finalMainChild.getTaskInfo().taskId);
} else {
- mMainStage.evictInvisibleChildren(callbackWct);
+ finalFirstAppStage.evictInvisibleChildren(callbackWct);
}
}
if (finalSideChild != null) {
if (!sideNotContainOpenTask) {
- mSideStage.evictOtherChildren(callbackWct, finalSideChild.getTaskInfo().taskId);
+ finalSecondAppStage.evictOtherChildren(callbackWct,
+ finalSideChild.getTaskInfo().taskId);
} else {
- mSideStage.evictInvisibleChildren(callbackWct);
+ finalSecondAppStage.evictInvisibleChildren(callbackWct);
}
}
if (!evictWct.isEmpty()) {
@@ -2952,8 +3426,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
public void onPipExpandToSplit(WindowContainerTransaction wct,
ActivityManager.RunningTaskInfo taskInfo) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onPipExpandToSplit: task=%s", taskInfo);
+ // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+ // flex split + pip interactions in the future
prepareEnterSplitScreen(wct, taskInfo, getActivateSplitPosition(taskInfo),
- false /*resizeAnim*/);
+ false /*resizeAnim*/, SPLIT_INDEX_UNDEFINED);
if (!isSplitScreenVisible() || mSplitRequest == null) {
return;
@@ -3058,13 +3534,28 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Wait until after animation to update divider
// Reset crops so they don't interfere with subsequent launches
- t.setCrop(mMainStage.mRootLeash, null);
- t.setCrop(mSideStage.mRootLeash, null);
+ if (enableFlexibleSplit()) {
+ runForActiveStages(stage -> t.setCrop(stage.mRootLeash, null /*crop*/));
+ } else {
+ t.setCrop(mMainStage.mRootLeash, null);
+ t.setCrop(mSideStage.mRootLeash, null);
+ }
// Hide the non-top stage and set the top one to the fullscreen position.
if (toStage != STAGE_TYPE_UNDEFINED) {
- t.hide(toStage == STAGE_TYPE_MAIN ? mSideStage.mRootLeash : mMainStage.mRootLeash);
- t.setPosition(toStage == STAGE_TYPE_MAIN
- ? mMainStage.mRootLeash : mSideStage.mRootLeash, 0, 0);
+ if (enableFlexibleSplit()) {
+ StageTaskListener stageToKeep = mStageOrderOperator.getAllStages().stream()
+ .filter(stage -> stage.getId() == toStage)
+ .findFirst().orElseThrow();
+ List<StageTaskListener> stagesToHide = mStageOrderOperator.getAllStages().stream()
+ .filter(stage -> stage.getId() != toStage)
+ .toList();
+ stagesToHide.forEach(stage -> t.hide(stage.mRootLeash));
+ t.setPosition(stageToKeep.mRootLeash, 0, 0);
+ } else {
+ t.hide(toStage == STAGE_TYPE_MAIN ? mSideStage.mRootLeash : mMainStage.mRootLeash);
+ t.setPosition(toStage == STAGE_TYPE_MAIN
+ ? mMainStage.mRootLeash : mSideStage.mRootLeash, 0, 0);
+ }
} else {
for (int i = dismissingTasks.keySet().size() - 1; i >= 0; --i) {
finishT.hide(dismissingTasks.valueAt(i));
@@ -3079,8 +3570,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Hide divider and dim layer on transition finished.
setDividerVisibility(false, t);
- finishT.hide(mMainStage.mDimLayer);
- finishT.hide(mSideStage.mDimLayer);
+ if (enableFlexibleSplit()) {
+ runForActiveStages(stage -> finishT.hide(stage.mRootLeash));
+ } else {
+ finishT.hide(mMainStage.mDimLayer);
+ finishT.hide(mSideStage.mDimLayer);
+ }
}
private boolean startPendingDismissAnimation(
@@ -3101,8 +3596,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return false;
}
dismissTransition.setFinishedCallback((callbackWct, callbackT) -> {
- mMainStage.getSplitDecorManager().release(callbackT);
- mSideStage.getSplitDecorManager().release(callbackT);
+ if (enableFlexibleSplit()) {
+ runForActiveStages(stage -> stage.getSplitDecorManager().release(callbackT));
+ } else {
+ mMainStage.getSplitDecorManager().release(callbackT);
+ mSideStage.getSplitDecorManager().release(callbackT);
+ }
callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
});
return true;
@@ -3119,8 +3618,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (TransitionUtil.isClosingType(change.getMode())
&& change.getTaskInfo() != null) {
final int taskId = change.getTaskInfo().taskId;
- if (mMainStage.getTopVisibleChildTaskId() == taskId
- || mSideStage.getTopVisibleChildTaskId() == taskId) {
+ boolean anyStagesHaveTask;
+ if (enableFlexibleSplit()) {
+ anyStagesHaveTask = mStageOrderOperator.getActiveStages().stream()
+ .anyMatch(stage -> stage.getTopVisibleChildTaskId() == taskId);
+ } else {
+ anyStagesHaveTask = mMainStage.getTopVisibleChildTaskId() == taskId
+ || mSideStage.getTopVisibleChildTaskId() == taskId;
+ }
+ if (anyStagesHaveTask) {
mPausingTasks.add(taskId);
}
}
@@ -3152,9 +3658,16 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final WindowContainerTransaction.HierarchyOp op =
finishWct.getHierarchyOps().get(i);
final IBinder container = op.getContainer();
+ boolean anyStageContainsContainer;
+ if (enableFlexibleSplit()) {
+ anyStageContainsContainer = mStageOrderOperator.getActiveStages().stream()
+ .anyMatch(stage -> stage.containsContainer(container));
+ } else {
+ anyStageContainsContainer = mMainStage.containsContainer(container)
+ || mSideStage.containsContainer(container);
+ }
if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
- && (mMainStage.containsContainer(container)
- || mSideStage.containsContainer(container))) {
+ && anyStageContainsContainer) {
updateSurfaceBounds(mSplitLayout, finishT,
false /* applyResizingOffset */);
finishT.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
@@ -3181,10 +3694,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// user entering recents.
for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
final int taskId = mPausingTasks.get(i);
- if (mMainStage.containsTask(taskId)) {
- mMainStage.evictChildren(finishWct, taskId);
- } else if (mSideStage.containsTask(taskId)) {
- mSideStage.evictChildren(finishWct, taskId);
+ if (enableFlexibleSplit()) {
+ mStageOrderOperator.getActiveStages().stream()
+ .filter(stage -> stage.containsTask(taskId))
+ .findFirst()
+ .ifPresent(stageToEvict ->
+ stageToEvict.evictChild(finishWct, taskId, "recentsPairToPair"));
+ } else {
+ if (mMainStage.containsTask(taskId)) {
+ mMainStage.evictChild(finishWct, taskId, "recentsPairToPair");
+ } else if (mSideStage.containsTask(taskId)) {
+ mSideStage.evictChild(finishWct, taskId, "recentsPairToPair");
+ }
}
}
// If pending enter hasn't consumed, the mix handler will invoke start pending
@@ -3247,8 +3768,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
*/
private void setSplitsVisible(boolean visible) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setSplitsVisible: visible=%b", visible);
- mMainStage.mVisible = mSideStage.mVisible = visible;
- mMainStage.mHasChildren = mSideStage.mHasChildren = visible;
+ if (enableFlexibleSplit()) {
+ runForActiveStages(stage -> {
+ stage.mVisible = visible;
+ stage.mHasChildren = visible;
+ });
+ } else {
+ mMainStage.mVisible = mSideStage.mVisible = visible;
+ mMainStage.mHasChildren = mSideStage.mHasChildren = visible;
+ }
}
/**
@@ -3291,6 +3819,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
* executed.
*/
private void logExitToStage(@ExitReason int exitReason, boolean toMainStage) {
+ if (enableFlexibleSplit()) {
+ // TODO(b/374825718) update logging for 2+ apps
+ return;
+ }
mLogger.logExit(exitReason,
toMainStage ? getMainStagePosition() : SPLIT_POSITION_UNDEFINED,
toMainStage ? mMainStage.getTopChildTaskUid() : 0 /* mainStageUid */,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt
new file mode 100644
index 000000000000..b7b3c9b62a58
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen
+
+import android.content.Context
+import com.android.internal.protolog.ProtoLog
+import com.android.launcher3.icons.IconProvider
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.shared.split.SplitScreenConstants
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_NONE
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_2
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED
+import com.android.wm.shell.shared.split.SplitScreenConstants.SnapPosition
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition
+import com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_A
+import com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_B
+import com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_C
+import com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString
+import com.android.wm.shell.windowdecor.WindowDecorViewModel
+import java.util.Optional
+
+/**
+ * Responsible for creating [StageTaskListener]s and maintaining their ordering on screen.
+ * Must be notified whenever stages positions change via swapping or starting/ending tasks
+ */
+class StageOrderOperator (
+ context: Context,
+ taskOrganizer: ShellTaskOrganizer,
+ displayId: Int,
+ stageCallbacks: StageTaskListener.StageListenerCallbacks,
+ syncQueue: SyncTransactionQueue,
+ iconProvider: IconProvider,
+ windowDecorViewModel: Optional<WindowDecorViewModel>
+ ) {
+
+ private val MAX_STAGES = 3
+ /**
+ * This somewhat acts as a replacement to stageTypes in the intermediary, so we want to start
+ * it after the @StageType constant values just to be safe and avoid potentially subtle bugs.
+ */
+ private var stageIds = listOf(STAGE_TYPE_A, STAGE_TYPE_B, STAGE_TYPE_C)
+
+ /**
+ * Active Stages, this list represent the current, ordered list of stages that are
+ * currently visible to the user. This map should be empty if the user is currently
+ * not in split screen. Note that this is different than if split screen is visible, which
+ * is determined by [StageListenerImpl.mVisible].
+ * Split stages can be active and in the background
+ */
+ val activeStages = mutableListOf<StageTaskListener>()
+ val allStages = mutableListOf<StageTaskListener>()
+ var isActive: Boolean = false
+ var isVisible: Boolean = false
+ @SnapPosition private var currentLayout: Int = SNAP_TO_NONE
+
+ init {
+ for(i in 0 until MAX_STAGES) {
+ allStages.add(StageTaskListener(context,
+ taskOrganizer,
+ displayId,
+ stageCallbacks,
+ syncQueue,
+ iconProvider,
+ windowDecorViewModel,
+ stageIds[i])
+ )
+ }
+ }
+
+ /**
+ * Updates internal state to keep record of "active" stages. Note that this does NOT call
+ * [StageTaskListener.activate] on the stages.
+ */
+ fun onEnteringSplit(@SnapPosition goingToLayout: Int) {
+ if (goingToLayout == currentLayout) {
+ // Add protolog here. Return for now, but maybe we want to handle swap case, TBD
+ return
+ }
+ val freeStages: List<StageTaskListener> =
+ allStages.filterNot { activeStages.contains(it) }
+ when(goingToLayout) {
+ SplitScreenConstants.SNAP_TO_2_50_50 -> {
+ if (activeStages.size < 2) {
+ // take from allStages and add into activeStages
+ for (i in 0 until (2 - activeStages.size)) {
+ val stage = freeStages[i]
+ activeStages.add(stage)
+ }
+ }
+ }
+ }
+ ProtoLog.d(
+ ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Activated stages: %d ids=%s",
+ activeStages.size,
+ activeStages.joinToString(",") { stageTypeToString(it.id) }
+ )
+ isActive = true
+ }
+
+ fun onExitingSplit() {
+ activeStages.clear()
+ isActive = false
+ }
+
+ /**
+ * Given a legacy [SplitPosition] returns one of the stages from the actives stages.
+ * If there are no active stages and [checkAllStagesIfNotActive] is not true, then will return
+ * null
+ */
+ fun getStageForLegacyPosition(@SplitPosition position: Int,
+ checkAllStagesIfNotActive : Boolean = false) :
+ StageTaskListener? {
+ if (activeStages.size != 2 && !checkAllStagesIfNotActive) {
+ return null
+ }
+ val listToCheck = if (activeStages.isEmpty() and checkAllStagesIfNotActive)
+ allStages else
+ activeStages
+ if (position == SPLIT_POSITION_TOP_OR_LEFT) {
+ return listToCheck[0]
+ } else if (position == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
+ return listToCheck[1]
+ } else {
+ throw IllegalArgumentException("No stage for invalid position")
+ }
+ }
+
+ /**
+ * Returns a legacy split position for the given stage. If no stages are active then this will
+ * return [SPLIT_POSITION_UNDEFINED]
+ */
+ @SplitPosition
+ fun getLegacyPositionForStage(stage: StageTaskListener) : Int {
+ if (allStages[0] == stage) {
+ return SPLIT_POSITION_TOP_OR_LEFT
+ } else if (allStages[1] == stage) {
+ return SPLIT_POSITION_BOTTOM_OR_RIGHT
+ } else {
+ return SPLIT_POSITION_UNDEFINED
+ }
+ }
+
+ /**
+ * Returns the stageId from a given splitIndex. This will default to checking from all stages if
+ * [isActive] is false, otherwise will only check active stages.
+ */
+ fun getStageForIndex(@SplitIndex splitIndex: Int) : StageTaskListener {
+ // Probably should do a check for index to be w/in the bounds of the current split layout
+ // that we're currently in
+ val listToCheck = if (isActive) activeStages else allStages
+ if (splitIndex == SPLIT_INDEX_0) {
+ return listToCheck[0]
+ } else if (splitIndex == SPLIT_INDEX_1) {
+ return listToCheck[1]
+ } else if (splitIndex == SPLIT_INDEX_2) {
+ return listToCheck[2]
+ } else {
+ // Though I guess what if we're adding to the end? Maybe that indexing needs to be
+ // resolved elsewhere
+ throw IllegalStateException("No stage for the given splitIndex")
+ }
+ }
+} \ No newline at end of file
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 4407e5b3106f..4a37169add36 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,14 +22,17 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
+import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import android.annotation.CallSuper;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.TaskInfo;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
@@ -71,6 +74,8 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
// No current way to enforce this but if enableFlexibleSplit() is enabled, then only 1 of the
// stages should have this be set/being used
private boolean mIsActive;
+ /** Unique identifier for this state, > 0 */
+ @StageType private final int mId;
/** Callback interface for listening to changes in a split-screen stage. */
public interface StageListenerCallbacks {
void onRootTaskAppeared();
@@ -109,13 +114,14 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
IconProvider iconProvider,
- Optional<WindowDecorViewModel> windowDecorViewModel) {
+ Optional<WindowDecorViewModel> windowDecorViewModel, int id) {
mContext = context;
mCallbacks = callbacks;
mSyncQueue = syncQueue;
mIconProvider = iconProvider;
mWindowDecorViewModel = windowDecorViewModel;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
+ mId = id;
}
int getChildCount() {
@@ -138,6 +144,8 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
* Returns the top visible child task's id.
*/
int getTopVisibleChildTaskId() {
+ // TODO(b/378601156): This doesn't get the top task (translucent tasks are also
+ // visible-requested)
final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible
&& t.isVisibleRequested);
return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID;
@@ -147,6 +155,7 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
* Returns the top activity uid for the top child task.
*/
int getTopChildTaskUid() {
+ // TODO(b/378601156): This doesn't get the top task
final ActivityManager.RunningTaskInfo taskInfo =
getChildTaskInfo(t -> t.topActivityInfo != null);
return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0;
@@ -157,6 +166,11 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
return contains(t -> t.isFocused);
}
+ @StageType
+ int getId() {
+ return mId;
+ }
+
private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) {
if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) {
return true;
@@ -193,10 +207,10 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@CallSuper
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: taskId=%d taskParent=%d rootTask=%d "
- + "taskActivity=%s",
+ + "stageId=%s taskActivity=%s",
taskInfo.taskId, taskInfo.parentTaskId,
mRootTaskInfo != null ? mRootTaskInfo.taskId : -1,
- taskInfo.baseActivity);
+ stageTypeToString(mId), taskInfo.baseActivity);
if (mRootTaskInfo == null) {
mRootLeash = leash;
mRootTaskInfo = taskInfo;
@@ -226,8 +240,9 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s",
- taskInfo.taskId, taskInfo.baseActivity);
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s "
+ + "stageId=%s",
+ taskInfo.taskId, taskInfo.baseActivity, stageTypeToString(mId));
mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
if (mRootTaskInfo.taskId == taskInfo.taskId) {
mRootTaskInfo = taskInfo;
@@ -257,7 +272,8 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
@CallSuper
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%d", taskInfo.taskId);
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%d stageId=%s",
+ taskInfo.taskId, stageTypeToString(mId));
final int taskId = taskInfo.taskId;
mWindowDecorViewModel.ifPresent(vm -> vm.onTaskVanished(taskInfo));
if (mRootTaskInfo.taskId == taskId) {
@@ -379,10 +395,9 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
/** Collects all the current child tasks and prepares transaction to evict them to display. */
void evictAllChildren(WindowContainerTransaction wct) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evicting all children");
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
- wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ evictChild(wct, taskInfo, "all");
}
}
@@ -390,13 +405,11 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
if (taskId == taskInfo.taskId) continue;
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict other child: task=%d", taskId);
- wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ evictChild(wct, taskInfo, "other");
}
}
void evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "evictNonOpeningChildren");
final SparseArray<ActivityManager.RunningTaskInfo> toBeEvict = mChildrenTaskInfo.clone();
for (int i = 0; i < apps.length; i++) {
if (apps[i].mode == MODE_OPENING) {
@@ -405,8 +418,7 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
for (int i = toBeEvict.size() - 1; i >= 0; i--) {
final ActivityManager.RunningTaskInfo taskInfo = toBeEvict.valueAt(i);
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict non-opening child: task=%d", taskInfo.taskId);
- wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ evictChild(wct, taskInfo, "non-opening");
}
}
@@ -414,21 +426,30 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
if (!taskInfo.isVisible) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict invisible child: task=%d",
- taskInfo.taskId);
- wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ evictChild(wct, taskInfo, "invisible");
}
}
}
- void evictChildren(WindowContainerTransaction wct, int taskId) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d", taskId);
+ void evictChild(WindowContainerTransaction wct, int taskId, String reason) {
final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.get(taskId);
if (taskInfo != null) {
- wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ evictChild(wct, taskInfo, reason);
}
}
+ private void evictChild(@NonNull WindowContainerTransaction wct, @NonNull TaskInfo taskInfo,
+ @NonNull String reason) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d reason=%s", taskInfo.taskId,
+ reason);
+ // We are reparenting the task, but not removing the task from mChildrenTaskInfo, so to
+ // prevent this task from being considered as a top task for the roots, we need to override
+ // the visibility of the soon-to-be-hidden task
+ taskInfo.isVisible = false;
+ taskInfo.isVisibleRequested = false;
+ wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ }
+
void reparentTopTask(WindowContainerTransaction wct) {
wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token,
CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES,
@@ -457,14 +478,17 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
void activate(WindowContainerTransaction wct, boolean includingTopTask) {
- if (mIsActive) return;
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: includingTopTask=%b",
- includingTopTask);
+ if (mIsActive && !enableFlexibleSplit()) return;
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: includingTopTask=%b stage=%s",
+ includingTopTask, stageTypeToString(mId));
if (includingTopTask) {
reparentTopTask(wct);
}
+ if (enableFlexibleSplit()) {
+ return;
+ }
mIsActive = true;
}
@@ -472,11 +496,14 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
deactivate(wct, false /* toTop */);
}
- void deactivate(WindowContainerTransaction wct, boolean toTop) {
- if (!mIsActive) return;
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: toTop=%b rootTaskInfo=%s",
- toTop, mRootTaskInfo);
- mIsActive = false;
+ void deactivate(WindowContainerTransaction wct, boolean reparentTasksToTop) {
+ if (!mIsActive && !enableFlexibleSplit()) return;
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: reparentTasksToTop=%b "
+ + "rootTaskInfo=%s stage=%s",
+ reparentTasksToTop, mRootTaskInfo, stageTypeToString(mId));
+ if (!enableFlexibleSplit()) {
+ mIsActive = false;
+ }
if (mRootTaskInfo == null) return;
final WindowContainerToken rootToken = mRootTaskInfo.token;
@@ -485,14 +512,15 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
null /* newParent */,
null /* windowingModes */,
null /* activityTypes */,
- toTop);
+ reparentTasksToTop);
}
// --------
- // Previously only used in SideStage
+ // Previously only used in SideStage. With flexible split this is called for all stages
boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b",
- mChildrenTaskInfo.size(), toTop);
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b "
+ + " stageI=%s",
+ mChildrenTaskInfo.size(), toTop, stageTypeToString(mId));
if (mChildrenTaskInfo.size() == 0) return false;
wct.reparentTasks(
mRootTaskInfo.token,
@@ -513,6 +541,15 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
@Override
+ public String toString() {
+ return "mId: " + stageTypeToString(mId)
+ + " mVisible: " + mVisible
+ + " mActive: " + mIsActive
+ + " mHasRootTask: " + mHasRootTask
+ + " childSize: " + mChildrenTaskInfo.size();
+ }
+
+ @Override
@CallSuper
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
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 17483dd68632..92d1f9c26bbc 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
@@ -370,7 +370,8 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
if (mRecentsHandler != null) {
if (mSplitHandler.isSplitScreenVisible()) {
return this::setRecentsTransitionDuringSplit;
- } else if (mKeyguardHandler.isKeyguardShowing()) {
+ } else if (mKeyguardHandler.isKeyguardShowing()
+ && !mKeyguardHandler.isKeyguardAnimating()) {
return this::setRecentsTransitionDuringKeyguard;
} else if (mDesktopTasksController != null
// Check on the default display. Recents/gesture nav is only available there
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
index fd4d568326d0..8cdbe26a2c76 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
@@ -117,6 +117,11 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during"
+ " Keyguard #%d", info.getDebugId());
+ if (!mKeyguardHandler.isKeyguardShowing() || mKeyguardHandler.isKeyguardAnimating()) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Cancel mixed transition because "
+ + "keyguard state was changed #%d", info.getDebugId());
+ return false;
+ }
if (mInfo == null) {
mInfo = info;
mFinishT = finishTransaction;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index d28287da83b6..32f3cd820421 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -334,8 +334,8 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator,
// Sides adjacent to split bar or task bar are not be animated.
Insets margins;
- final boolean isLandscape = mRootStageBounds.width() > mRootStageBounds.height();
- if (isLandscape) { // Left and right splits.
+ final boolean isLeftRightSplit = mSplitScreenController.get().get().isLeftRightSplit();
+ if (isLeftRightSplit) {
margins = getLandscapeMargins(margin, taskbarExpanded);
} else { // Top and bottom splits.
margins = getPortraitMargins(margin, taskbarExpanded);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
index 7b71e41874c7..b8c91519422c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
@@ -23,6 +23,7 @@ import android.graphics.Rect
import android.view.WindowManager
import android.window.TaskSnapshot
import androidx.compose.ui.graphics.toArgb
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
@@ -101,6 +102,7 @@ class DesktopHandleManageWindowsMenu(
flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
view = menuView.rootView,
+ ignoreCutouts = DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context),
)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index d71e61a4c4de..1913e93ae64e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -33,6 +33,7 @@ import static android.view.WindowInsets.Type.statusBars;
import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;
import static com.android.wm.shell.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing;
+import static com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod;
import static com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
@@ -78,7 +79,7 @@ import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.ViewConfiguration;
-import android.widget.Toast;
+import android.view.WindowManager;
import android.window.DesktopModeFlags;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
@@ -107,6 +108,8 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler;
import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger;
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum;
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator;
import com.android.wm.shell.desktopmode.DesktopRepository;
import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -227,6 +230,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
private final TaskPositionerFactory mTaskPositionerFactory;
private final FocusTransitionObserver mFocusTransitionObserver;
private final DesktopModeEventLogger mDesktopModeEventLogger;
+ private final DesktopModeUiEventLogger mDesktopModeUiEventLogger;
public DesktopModeWindowDecorViewModel(
Context context,
@@ -256,7 +260,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
FocusTransitionObserver focusTransitionObserver,
- DesktopModeEventLogger desktopModeEventLogger) {
+ DesktopModeEventLogger desktopModeEventLogger,
+ DesktopModeUiEventLogger desktopModeUiEventLogger) {
this(
context,
shellExecutor,
@@ -291,7 +296,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
activityOrientationChangeHandler,
new TaskPositionerFactory(),
focusTransitionObserver,
- desktopModeEventLogger);
+ desktopModeEventLogger,
+ desktopModeUiEventLogger);
}
@VisibleForTesting
@@ -329,7 +335,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
TaskPositionerFactory taskPositionerFactory,
FocusTransitionObserver focusTransitionObserver,
- DesktopModeEventLogger desktopModeEventLogger) {
+ DesktopModeEventLogger desktopModeEventLogger,
+ DesktopModeUiEventLogger desktopModeUiEventLogger) {
mContext = context;
mMainExecutor = shellExecutor;
mMainHandler = mainHandler;
@@ -392,6 +399,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
mTaskPositionerFactory = taskPositionerFactory;
mFocusTransitionObserver = focusTransitionObserver;
mDesktopModeEventLogger = desktopModeEventLogger;
+ mDesktopModeUiEventLogger = desktopModeUiEventLogger;
shellInit.addInitCallback(this::onInit, this);
}
@@ -413,7 +421,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
} catch (RemoteException e) {
Log.e(TAG, "Failed to register window manager callbacks", e);
}
- if (DesktopModeStatus.canEnterDesktopMode(mContext)
+ if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(mContext)
&& Flags.enableDesktopWindowingAppHandleEducation()) {
mAppHandleEducationController.setAppHandleEducationTooltipCallbacks(
/* appHandleTooltipClickCallback= */(taskId) -> {
@@ -572,14 +580,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
if (decoration == null) {
return;
}
- mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent,
- decoration.mTaskInfo,
- mDisplayController, /* displayLayoutSize= */ null);
mInteractionJankMonitor.begin(
decoration.mTaskSurface, mContext, mMainHandler,
Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo, resizeTrigger,
- motionEvent);
+ DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent));
decoration.closeHandleMenu();
decoration.closeMaximizeMenu();
}
@@ -593,33 +598,20 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
decoration.closeMaximizeMenu();
}
- private void onSnapResize(int taskId, boolean left, MotionEvent motionEvent) {
+ public void onSnapResize(int taskId, boolean left, InputMethod inputMethod) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
if (decoration == null) {
return;
}
- if (!decoration.mTaskInfo.isResizeable
- && DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
- Toast.makeText(mContext,
- R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show();
- } else {
- ResizeTrigger resizeTrigger =
- left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU;
- mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent,
- decoration.mTaskInfo,
- mDisplayController, /* displayLayoutSize= */ null);
- mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
- Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable");
- mDesktopTasksController.snapToHalfScreen(
- decoration.mTaskInfo,
- decoration.mTaskSurface,
- decoration.mTaskInfo.configuration.windowConfiguration.getBounds(),
- left ? SnapPosition.LEFT : SnapPosition.RIGHT,
- resizeTrigger,
- motionEvent,
- mWindowDecorByTaskId.get(taskId));
- }
+ mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
+ Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable");
+ mDesktopTasksController.handleInstantSnapResizingTask(
+ decoration.mTaskInfo,
+ left ? SnapPosition.LEFT : SnapPosition.RIGHT,
+ left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU,
+ inputMethod,
+ decoration);
decoration.closeHandleMenu();
decoration.closeMaximizeMenu();
@@ -652,6 +644,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
decoration.addCaptionInset(wct);
mDesktopTasksController.moveTaskToDesktop(taskId, wct, source);
decoration.closeHandleMenu();
+
+ if (source == DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON) {
+ mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_DESKTOP_MODE);
+ }
}
private void onToFullscreen(int taskId) {
@@ -667,6 +664,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
mDesktopTasksController.moveToFullscreen(taskId,
DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON);
}
+ mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_FULL_SCREEN);
}
private void onToSplitScreen(int taskId) {
@@ -679,6 +678,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
// we shouldn't receive input for it any longer.
decoration.disposeStatusBarInputLayer();
mDesktopTasksController.requestSplit(decoration.mTaskInfo, false /* leftOrTop */);
+ mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_SPLIT_SCREEN);
}
private void onNewWindow(int taskId) {
@@ -818,6 +819,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
} else if (id == R.id.back_button) {
mTaskOperations.injectBackKey(mDisplayId);
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
+ if (id == R.id.caption_handle && !decoration.mTaskInfo.isFreeform()) {
+ // Clicking the App Handle.
+ mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+ DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_TAP);
+ }
if (!decoration.isHandleMenuActive()) {
moveTaskToFront(decoration.mTaskInfo);
openHandleMenu(mTaskId);
@@ -974,7 +980,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
final RunningTaskInfo taskInfo = decoration.mTaskInfo;
- if (DesktopModeStatus.canEnterDesktopMode(mContext)
+ if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(mContext)
&& !taskInfo.isFreeform()) {
return handleNonFreeformMotionEvent(decoration, v, e);
} else {
@@ -1500,7 +1506,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
if (isPartOfDefaultHomePackage(taskInfo)) {
return false;
}
- return DesktopModeStatus.canEnterDesktopMode(mContext)
+ final boolean isOnLargeScreen = taskInfo.getConfiguration().smallestScreenWidthDp
+ >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
+ if (!DesktopModeStatus.canEnterDesktopMode(mContext)
+ && DesktopModeStatus.overridesShowAppHandle(mContext) && !isOnLargeScreen) {
+ // Devices with multiple screens may enable the app handle but it should not show on
+ // small screens
+ return false;
+ }
+ return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(mContext)
&& !DesktopWallpaperActivity.isWallpaperTask(taskInfo)
&& taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
&& taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
@@ -1561,6 +1575,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, taskPositioner);
+ InputMethod inputMethod = DesktopModeEventLogger.getInputMethodFromMotionEvent(
+ touchEventListener.mMotionEvent);
windowDecoration.setOnMaximizeOrRestoreClickListener(() -> {
onMaximizeOrRestore(taskInfo.taskId, "maximize_menu", ResizeTrigger.MAXIMIZE_MENU,
touchEventListener.mMotionEvent);
@@ -1571,11 +1587,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
return Unit.INSTANCE;
});
windowDecoration.setOnLeftSnapClickListener(() -> {
- onSnapResize(taskInfo.taskId, /* isLeft= */ true, touchEventListener.mMotionEvent);
+ onSnapResize(taskInfo.taskId, /* isLeft= */ true, inputMethod);
return Unit.INSTANCE;
});
windowDecoration.setOnRightSnapClickListener(() -> {
- onSnapResize(taskInfo.taskId, /* isLeft= */ false, touchEventListener.mMotionEvent);
+ onSnapResize(taskInfo.taskId, /* isLeft= */ false, inputMethod);
return Unit.INSTANCE;
});
windowDecoration.setOnToDesktopClickListener(desktopModeTransitionSource -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index cdcf14e0cbf3..d57044a4d27c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -30,6 +30,7 @@ import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_
import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopModeOrShowAppHandle;
import static com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.DisabledEdge;
@@ -81,7 +82,6 @@ import android.window.TaskSnapshot;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider;
import com.android.window.flags.Flags;
@@ -207,7 +207,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
private final DesktopRepository mDesktopRepository;
- DesktopModeWindowDecoration(
+ public DesktopModeWindowDecoration(
Context context,
@NonNull Context userContext,
DisplayController displayController,
@@ -1008,8 +1008,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
relayoutParams.mWindowDecorConfig = windowDecorConfig;
if (DesktopModeStatus.useRoundedCorners()) {
- relayoutParams.mCornerRadius =
- (int) ScreenDecorationsUtils.getWindowCornerRadius(context);
+ relayoutParams.mCornerRadius = taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+ ? loadDimensionPixelSize(context.getResources(),
+ R.dimen.desktop_windowing_freeform_rounded_corner_radius)
+ : INVALID_CORNER_RADIUS;
}
}
@@ -1396,10 +1398,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
mAppIconBitmap,
mAppName,
mSplitScreenController,
- canEnterDesktopMode(mContext),
+ canEnterDesktopModeOrShowAppHandle(mContext),
supportsMultiInstance,
shouldShowManageWindowsButton,
shouldShowChangeAspectRatioButton,
+ canEnterDesktopMode(mContext),
isBrowserApp,
isBrowserApp ? getAppLink() : getBrowserLink(),
mResult.mCaptionWidth,
@@ -1414,7 +1417,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
mHandleMenu.show(
/* onToDesktopClickListener= */ () -> {
mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
- mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
return Unit.INSTANCE;
},
/* onToFullscreenClickListener= */ mOnToFullscreenClickListener,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 420409705b05..a6d503d0d991 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -460,7 +460,9 @@ class DragResizeInputListener implements AutoCloseable {
|| ctrlType == CTRL_TYPE_RIGHT || ctrlType == CTRL_TYPE_LEFT)
? ResizeTrigger.EDGE : ResizeTrigger.CORNER;
mDesktopModeEventLogger.logTaskResizingStarted(mResizeTrigger,
- e, mTaskInfo, /* displayController= */ null,
+ DesktopModeEventLogger.getInputMethodFromMotionEvent(e),
+ mTaskInfo, mDragStartTaskBounds.width(),
+ mDragStartTaskBounds.height(), /* displayController= */ null,
/* displayLayoutSize= */ mDisplayLayoutSizeSupplier.get());
// Increase the input sink region to cover the whole screen; this is to
// prevent input and focus from going to other tasks during a drag resize.
@@ -512,8 +514,9 @@ class DragResizeInputListener implements AutoCloseable {
}
mDesktopModeEventLogger.logTaskResizingEnded(mResizeTrigger,
- mLastMotionEventOnDown, mTaskInfo, taskBounds.height(),
- taskBounds.width(),
+ DesktopModeEventLogger.getInputMethodFromMotionEvent(
+ mLastMotionEventOnDown), mTaskInfo, taskBounds.width(),
+ taskBounds.height(),
/* displayController= */ null,
/* displayLayoutSize= */ mDisplayLayoutSizeSupplier.get());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 54c247bff984..049b8d621427 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -45,6 +45,7 @@ import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.compose.ui.graphics.toArgb
import androidx.core.view.isGone
+import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.apptoweb.isBrowserApp
import com.android.wm.shell.shared.split.SplitScreenConstants
@@ -75,6 +76,7 @@ class HandleMenu(
private val shouldShowNewWindowButton: Boolean,
private val shouldShowManageWindowsButton: Boolean,
private val shouldShowChangeAspectRatioButton: Boolean,
+ private val shouldShowDesktopModeButton: Boolean,
private val isBrowserApp: Boolean,
private val openInAppOrBrowserIntent: Intent?,
private val captionWidth: Int,
@@ -185,6 +187,7 @@ class HandleMenu(
shouldShowNewWindowButton = shouldShowNewWindowButton,
shouldShowManageWindowsButton = shouldShowManageWindowsButton,
shouldShowChangeAspectRatioButton = shouldShowChangeAspectRatioButton,
+ shouldShowDesktopModeButton = shouldShowDesktopModeButton,
isBrowserApp = isBrowserApp
).apply {
bind(taskInfo, appIconBitmap, appName, shouldShowMoreActionsPill)
@@ -218,7 +221,8 @@ class HandleMenu(
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
view = handleMenuView.rootView,
- forciblyShownTypes = if (forceShowSystemBars) { systemBars() } else { 0 }
+ forciblyShownTypes = if (forceShowSystemBars) { systemBars() } else { 0 },
+ ignoreCutouts = Flags.showAppHandleLargeScreens()
)
} else {
parentDecor.addWindow(
@@ -238,8 +242,12 @@ class HandleMenu(
val taskBounds = taskInfo.getConfiguration().windowConfiguration.bounds
updateGlobalMenuPosition(taskBounds, captionX, captionY)
if (layoutResId == R.layout.desktop_mode_app_header) {
- // Align the handle menu to the left side of the caption.
- menuX = marginMenuStart
+ // Align the handle menu to the start of the header.
+ menuX = if (context.isRtl()) {
+ taskBounds.width() - menuWidth - marginMenuStart
+ } else {
+ marginMenuStart
+ }
menuY = captionY + marginMenuTop
} else {
if (DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue()) {
@@ -261,10 +269,17 @@ class HandleMenu(
val nonFreeformX = captionX + (captionWidth / 2) - (menuWidth / 2)
when {
taskInfo.isFreeform -> {
- globalMenuPosition.set(
- /* x = */ taskBounds.left + marginMenuStart,
- /* y = */ taskBounds.top + captionY + marginMenuTop
- )
+ if (context.isRtl()) {
+ globalMenuPosition.set(
+ /* x= */ taskBounds.right - menuWidth - marginMenuStart,
+ /* y= */ taskBounds.top + captionY + marginMenuTop
+ )
+ } else {
+ globalMenuPosition.set(
+ /* x= */ taskBounds.left + marginMenuStart,
+ /* y= */ taskBounds.top + captionY + marginMenuTop
+ )
+ }
}
taskInfo.isFullscreen -> {
globalMenuPosition.set(
@@ -430,6 +445,9 @@ class HandleMenu(
return context.resources.getDimensionPixelSize(resourceId)
}
+ private fun Context.isRtl() =
+ resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
+
fun close() {
handleMenuView?.animateCloseMenu {
handleMenuViewContainer?.releaseView()
@@ -448,6 +466,7 @@ class HandleMenu(
private val shouldShowNewWindowButton: Boolean,
private val shouldShowManageWindowsButton: Boolean,
private val shouldShowChangeAspectRatioButton: Boolean,
+ private val shouldShowDesktopModeButton: Boolean,
private val isBrowserApp: Boolean
) {
val rootView = LayoutInflater.from(context)
@@ -644,12 +663,15 @@ class HandleMenu(
floatingBtn.isSelected = taskInfo.isPinned
floatingBtn.isEnabled = !taskInfo.isPinned
floatingBtn.imageTintList = style.windowingButtonColor
+ desktopBtn.isGone = !shouldShowDesktopModeButton
desktopBtn.isSelected = taskInfo.isFreeform
desktopBtn.isEnabled = !taskInfo.isFreeform
desktopBtn.imageTintList = style.windowingButtonColor
}
private fun bindMoreActionsPill(style: MenuStyle) {
+ moreActionsPill.background.setTint(style.backgroundColor)
+
arrayOf(
screenshotBtn to SHOULD_SHOW_SCREENSHOT_BUTTON,
newWindowBtn to shouldShowNewWindowButton,
@@ -660,7 +682,6 @@ class HandleMenu(
val shouldShow = it.second
button.apply {
isGone = !shouldShow
- background.setTint(style.backgroundColor)
setTextColor(style.textColor)
compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
}
@@ -724,6 +745,7 @@ interface HandleMenuFactory {
shouldShowNewWindowButton: Boolean,
shouldShowManageWindowsButton: Boolean,
shouldShowChangeAspectRatioButton: Boolean,
+ shouldShowDesktopModeButton: Boolean,
isBrowserApp: Boolean,
openInAppOrBrowserIntent: Intent?,
captionWidth: Int,
@@ -746,6 +768,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
shouldShowNewWindowButton: Boolean,
shouldShowManageWindowsButton: Boolean,
shouldShowChangeAspectRatioButton: Boolean,
+ shouldShowDesktopModeButton: Boolean,
isBrowserApp: Boolean,
openInAppOrBrowserIntent: Intent?,
captionWidth: Int,
@@ -764,6 +787,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
shouldShowNewWindowButton,
shouldShowManageWindowsButton,
shouldShowChangeAspectRatioButton,
+ shouldShowDesktopModeButton,
isBrowserApp,
openInAppOrBrowserIntent,
captionWidth,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
index 4bb1e7b6cc05..11a7cf8da8d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
@@ -70,6 +70,7 @@ import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHo
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.OPACITY_12
import com.android.wm.shell.windowdecor.common.OPACITY_40
+import com.android.wm.shell.windowdecor.common.OPACITY_60
import com.android.wm.shell.windowdecor.common.withAlpha
import java.util.function.Supplier
@@ -310,8 +311,6 @@ class MaximizeMenu(
.desktop_mode_maximize_menu_immersive_button_fill_padding)
private val maximizeFillPaddingDefault = context.resources.getDimensionPixelSize(R.dimen
.desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding)
- private val maximizeFillPaddingBottom = context.resources.getDimensionPixelSize(R.dimen
- .desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding_bottom)
private val maximizeRestoreFillPaddingVertical = context.resources.getDimensionPixelSize(
R.dimen.desktop_mode_maximize_menu_restore_button_fill_vertical_padding)
private val maximizeRestoreFillPaddingHorizontal = context.resources.getDimensionPixelSize(
@@ -320,7 +319,7 @@ class MaximizeMenu(
maximizeFillPaddingDefault,
maximizeFillPaddingDefault,
maximizeFillPaddingDefault,
- maximizeFillPaddingBottom
+ maximizeFillPaddingDefault
)
private val maximizeRestoreFillPaddingRect = Rect(
maximizeRestoreFillPaddingHorizontal,
@@ -684,7 +683,7 @@ class MaximizeMenu(
inactiveSnapSideColor = colorScheme.outlineVariant.toArgb(),
semiActiveSnapSideColor = colorScheme.primary.toArgb().withAlpha(OPACITY_40),
activeSnapSideColor = colorScheme.primary.toArgb(),
- inactiveStrokeColor = colorScheme.outlineVariant.toArgb(),
+ inactiveStrokeColor = colorScheme.outlineVariant.toArgb().withAlpha(OPACITY_60),
activeStrokeColor = colorScheme.primary.toArgb(),
inactiveBackgroundColor = menuBackgroundColor,
activeBackgroundColor = colorScheme.primary.toArgb().withAlpha(OPACITY_12)
@@ -753,7 +752,8 @@ class MaximizeMenu(
val activeStrokeAndFill = colorScheme.primary.toArgb()
val activeBackground = colorScheme.primary.toArgb().withAlpha(OPACITY_12)
val activeDrawable = createMaximizeOrImmersiveButtonDrawable(
- strokeAndFillColor = activeStrokeAndFill,
+ strokeColor = activeStrokeAndFill,
+ fillColor = activeStrokeAndFill,
backgroundColor = activeBackground,
// Add a mask with the menu background's color because the active background color is
// semi transparent, otherwise the transparency will reveal the stroke/fill color
@@ -770,7 +770,8 @@ class MaximizeMenu(
addState(
StateSet.WILD_CARD,
createMaximizeOrImmersiveButtonDrawable(
- strokeAndFillColor = colorScheme.outlineVariant.toArgb(),
+ strokeColor = colorScheme.outlineVariant.toArgb().withAlpha(OPACITY_60),
+ fillColor = colorScheme.outlineVariant.toArgb(),
backgroundColor = colorScheme.surfaceContainerLow.toArgb(),
backgroundMask = null, // not needed because the bg color is fully opaque
fillPadding = fillPadding,
@@ -780,7 +781,8 @@ class MaximizeMenu(
}
private fun createMaximizeOrImmersiveButtonDrawable(
- @ColorInt strokeAndFillColor: Int,
+ @ColorInt strokeColor: Int,
+ @ColorInt fillColor: Int,
@ColorInt backgroundColor: Int,
@ColorInt backgroundMask: Int?,
fillPadding: Rect,
@@ -794,7 +796,7 @@ class MaximizeMenu(
null /* inset */,
null /* innerRadii */
)
- paint.color = strokeAndFillColor
+ paint.color = strokeColor
paint.style = Paint.Style.FILL
})
// Second layer, a mask for the next (background) layer if needed because of
@@ -829,7 +831,7 @@ class MaximizeMenu(
null /* inset */,
null /* innerRadii */
)
- paint.color = strokeAndFillColor
+ paint.color = fillColor
paint.style = Paint.Style.FILL
})
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index a3c75bf33cde..852eee5f6672 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -107,6 +107,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
static final int INPUT_SINK_Z_ORDER = -2;
/**
+ * Invalid corner radius that signifies that corner radius should not be set.
+ */
+ static final int INVALID_CORNER_RADIUS = -1;
+
+ /**
* System-wide context. Only used to create context with overridden configurations.
*/
final Context mContext;
@@ -449,20 +454,22 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
startT.show(mTaskSurface);
}
- if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
- if (!DesktopModeStatus.isVeiledResizeEnabled()) {
- // When fluid resize is enabled, add a background to freeform tasks
- int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
- mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
- mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
- mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
- startT.setColor(mTaskSurface, mTmpColor);
- }
- startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
- finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+ if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+ && !DesktopModeStatus.isVeiledResizeEnabled()) {
+ // When fluid resize is enabled, add a background to freeform tasks
+ int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
+ mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
+ mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
+ mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
+ startT.setColor(mTaskSurface, mTmpColor);
} else if (!DesktopModeStatus.isVeiledResizeEnabled()) {
startT.unsetColor(mTaskSurface);
}
+
+ if (params.mCornerRadius != INVALID_CORNER_RADIUS) {
+ startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+ finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+ }
}
/**
@@ -593,13 +600,25 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
private Rect calculateBoundingRectLocal(@NonNull OccludingCaptionElement element,
int elementWidthPx, @NonNull Rect captionRect) {
+ final boolean isRtl =
+ mDecorWindowContext.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_RTL;
switch (element.mAlignment) {
case START -> {
- return new Rect(0, 0, elementWidthPx, captionRect.height());
+ if (isRtl) {
+ return new Rect(captionRect.width() - elementWidthPx, 0,
+ captionRect.width(), captionRect.height());
+ } else {
+ return new Rect(0, 0, elementWidthPx, captionRect.height());
+ }
}
case END -> {
- return new Rect(captionRect.width() - elementWidthPx, 0,
- captionRect.width(), captionRect.height());
+ if (isRtl) {
+ return new Rect(0, 0, elementWidthPx, captionRect.height());
+ } else {
+ return new Rect(captionRect.width() - elementWidthPx, 0,
+ captionRect.width(), captionRect.height());
+ }
}
}
throw new IllegalArgumentException("Unexpected alignment " + element.mAlignment);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt
index 8b6aaaf619e0..4a01e8e3d455 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt
@@ -25,6 +25,7 @@ import android.view.SurfaceControl
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
import com.android.wm.shell.windowdecor.WindowManagerWrapper
/**
@@ -40,6 +41,7 @@ class AdditionalSystemViewContainer(
height: Int,
flags: Int,
@WindowInsets.Type.InsetsType forciblyShownTypes: Int = 0,
+ ignoreCutouts: Boolean = false,
override val view: View
) : AdditionalViewContainer() {
val lp: WindowManager.LayoutParams = WindowManager.LayoutParams(
@@ -52,6 +54,10 @@ class AdditionalSystemViewContainer(
gravity = Gravity.LEFT or Gravity.TOP
setTrustedOverlay()
this.forciblyShownTypes = forciblyShownTypes
+ if (ignoreCutouts) {
+ fitInsetsTypes = 0
+ layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ }
}
constructor(
@@ -63,7 +69,8 @@ class AdditionalSystemViewContainer(
width: Int,
height: Int,
flags: Int,
- @LayoutRes layoutId: Int
+ @LayoutRes layoutId: Int,
+ ignoreCutouts: Boolean = false
) : this(
windowManagerWrapper = windowManagerWrapper,
taskId = taskId,
@@ -72,7 +79,8 @@ class AdditionalSystemViewContainer(
width = width,
height = height,
flags = flags,
- view = LayoutInflater.from(context).inflate(layoutId, null /* parent */)
+ view = LayoutInflater.from(context).inflate(layoutId, null /* parent */),
+ ignoreCutouts = ignoreCutouts
)
constructor(
@@ -83,7 +91,8 @@ class AdditionalSystemViewContainer(
y: Int,
width: Int,
height: Int,
- flags: Int
+ flags: Int,
+ ignoreCutouts: Boolean = false
) : this(
windowManagerWrapper = windowManagerWrapper,
taskId = taskId,
@@ -92,7 +101,8 @@ class AdditionalSystemViewContainer(
width = width,
height = height,
flags = flags,
- view = View(context)
+ view = View(context),
+ ignoreCutouts = ignoreCutouts
)
init {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
index f7cfbfa88485..c5057aa3cc18 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
@@ -52,6 +52,7 @@ const val OPACITY_12 = 31
const val OPACITY_15 = 38
const val OPACITY_40 = 102
const val OPACITY_55 = 140
+const val OPACITY_60 = 153
const val OPACITY_65 = 166
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
index 6cdc517c9cb7..583282247f58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
@@ -18,10 +18,12 @@ package com.android.wm.shell.windowdecor.tiling
import android.content.Context
import android.content.res.Configuration
+import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.Region
import android.os.Binder
+import android.util.Size
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.RoundedCorner
@@ -40,7 +42,6 @@ import android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER
import android.view.WindowlessWindowManager
import com.android.wm.shell.R
import com.android.wm.shell.common.SyncTransactionQueue
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger
import java.util.function.Supplier
/**
@@ -48,7 +49,7 @@ import java.util.function.Supplier
* when two tasks are tiled on left and right to resize them simultaneously.
*/
class DesktopTilingDividerWindowManager(
- private val config: Configuration,
+ config: Configuration,
private val windowName: String,
private val context: Context,
private val leash: SurfaceControl,
@@ -61,7 +62,11 @@ class DesktopTilingDividerWindowManager(
private lateinit var viewHost: SurfaceControlViewHost
private var tilingDividerView: TilingDividerView? = null
private var dividerShown = false
- private var handleRegionWidth: Int = -1
+ private var handleRegionSize: Size =
+ Size(
+ context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width),
+ context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height),
+ )
private var setTouchRegion = true
private val maxRoundedCornerRadius = getMaxRoundedCornerRadius()
@@ -74,9 +79,62 @@ class DesktopTilingDividerWindowManager(
rect.set(dividerBounds)
}
- /** Sets the touch region for the SurfaceControlViewHost. */
- fun setTouchRegion(region: Rect) {
- setTouchRegion(viewHost.windowToken.asBinder(), Region(region))
+ /**
+ * Sets the touch region for the SurfaceControlViewHost.
+ *
+ * The region includes the area around the handle (for accessibility), the divider itself and
+ * the rounded corners (to prevent click reaching windows behind).
+ */
+ fun setTouchRegion(handle: Rect, divider: Rect, cornerRadius: Float) {
+ val path = Path()
+ path.fillType = Path.FillType.WINDING
+ // The UI starts on the top-left corner, the region will be:
+ //
+ // cornerLeft cornerRight
+ // c1Top +--------+
+ // |corners |
+ // c1Bottom +--+ +--+
+ // | |
+ // handleLeft| | handleRight
+ // handleTop +----+ +----+
+ // | handle |
+ // handleBot +----+ +----+
+ // | |
+ // | |
+ // c2Top +--+ +--+
+ // |corners |
+ // c2Bottom +--------+
+ val cornerLeft = 0f
+ val centerX = cornerRadius + divider.width() / 2f
+ val centerY = divider.height()
+ val cornerRight = divider.width() + 2 * cornerRadius
+ val handleLeft = centerX - handle.width() / 2f
+ val handleRight = handleLeft + handle.width()
+ val dividerLeft = centerY - divider.width() / 2f
+ val dividerRight = dividerLeft + divider.width()
+
+ val c1Top = 0f
+ val c1Bottom = cornerRadius
+ val handleTop = centerY - handle.height() / 2f
+ val handleBottom = handleTop + handle.height()
+ val c2Top = divider.height() - cornerRadius
+ val c2Bottom = divider.height().toFloat()
+
+ // Top corners
+ path.addRect(cornerLeft, c1Top, cornerRight, c1Bottom, Path.Direction.CCW)
+ // Bottom corners
+ path.addRect(cornerLeft, c1Top, cornerRight, c2Bottom, Path.Direction.CCW)
+ // Handle
+ path.addRect(handleLeft, handleTop, handleRight, handleBottom, Path.Direction.CCW)
+ // Divider
+ path.addRect(dividerLeft, c2Top, dividerRight, c2Bottom, Path.Direction.CCW)
+
+ val clip = Rect(handleLeft.toInt(), c1Top.toInt(), handleRight.toInt(), c2Bottom.toInt())
+
+ val region = Region()
+ region.setPath(path, Region(clip))
+
+ setTouchRegion(viewHost.windowToken.asBinder(), region)
}
/**
@@ -96,7 +154,7 @@ class DesktopTilingDividerWindowManager(
surfaceControlViewHost.setView(dividerView, lp)
val tmpDividerBounds = Rect()
getDividerBounds(tmpDividerBounds)
- dividerView.setup(this, tmpDividerBounds)
+ dividerView.setup(this, tmpDividerBounds, handleRegionSize)
t.setRelativeLayer(leash, relativeLeash, 1)
.setPosition(
leash,
@@ -112,7 +170,7 @@ class DesktopTilingDividerWindowManager(
viewHost = surfaceControlViewHost
dividerView.addOnLayoutChangeListener(this)
tilingDividerView = dividerView
- handleRegionWidth = dividerView.handleRegionWidth
+ updateTouchRegion()
}
/** Hides the divider bar. */
@@ -176,8 +234,8 @@ class DesktopTilingDividerWindowManager(
private fun getWindowManagerParams(): WindowManager.LayoutParams {
val lp =
WindowManager.LayoutParams(
- dividerBounds.width() + 2 * maxRoundedCornerRadius,
- dividerBounds.height(),
+ /* w= */ dividerBounds.width() + 2 * maxRoundedCornerRadius,
+ /* h= */ dividerBounds.height(),
TYPE_DOCK_DIVIDER,
FLAG_NOT_FOCUSABLE or
FLAG_NOT_TOUCH_MODAL or
@@ -216,13 +274,16 @@ class DesktopTilingDividerWindowManager(
) {
if (!setTouchRegion) return
- val startX = (dividerBounds.width() - handleRegionWidth) / 2
- val startY = 0
- val tempRect = Rect(startX, startY, startX + handleRegionWidth, dividerBounds.height())
- setTouchRegion(tempRect)
+ updateTouchRegion()
setTouchRegion = false
}
+ private fun updateTouchRegion() {
+ val startX = -handleRegionSize.width / 2
+ val handle = Rect(startX, 0, startX + handleRegionSize.width, dividerBounds.height())
+ setTouchRegion(handle, dividerBounds, maxRoundedCornerRadius.toFloat())
+ }
+
private fun setSlippery(slippery: Boolean) {
val lp = tilingDividerView?.layoutParams as WindowManager.LayoutParams
val isSlippery = (lp.flags and FLAG_SLIPPERY) != 0
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
index 418b8ecd5534..3b5c6ca2e58a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
@@ -225,18 +225,23 @@ class DesktopTilingWindowDecoration(
fun onDividerHandleDragStart(motionEvent: MotionEvent) {
val leftTiledTask = leftTaskResizingHelper ?: return
val rightTiledTask = rightTaskResizingHelper ?: return
+ val inputMethod = DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent)
desktopModeEventLogger.logTaskResizingStarted(
ResizeTrigger.TILING_DIVIDER,
- motionEvent,
+ inputMethod,
leftTiledTask.taskInfo,
+ leftTiledTask.bounds.width(),
+ leftTiledTask.bounds.height(),
displayController,
)
desktopModeEventLogger.logTaskResizingStarted(
ResizeTrigger.TILING_DIVIDER,
- motionEvent,
+ inputMethod,
rightTiledTask.taskInfo,
+ rightTiledTask.bounds.width(),
+ rightTiledTask.bounds.height(),
displayController,
)
}
@@ -296,22 +301,23 @@ class DesktopTilingWindowDecoration(
) {
val leftTiledTask = leftTaskResizingHelper ?: return
val rightTiledTask = rightTaskResizingHelper ?: return
+ val inputMethod = DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent)
desktopModeEventLogger.logTaskResizingEnded(
ResizeTrigger.TILING_DIVIDER,
- motionEvent,
+ inputMethod,
leftTiledTask.taskInfo,
- leftTiledTask.newBounds.height(),
leftTiledTask.newBounds.width(),
+ leftTiledTask.newBounds.height(),
displayController,
)
desktopModeEventLogger.logTaskResizingEnded(
ResizeTrigger.TILING_DIVIDER,
- motionEvent,
+ inputMethod,
rightTiledTask.taskInfo,
- rightTiledTask.newBounds.height(),
rightTiledTask.newBounds.width(),
+ rightTiledTask.newBounds.height(),
displayController,
)
@@ -486,9 +492,8 @@ class DesktopTilingWindowDecoration(
// Only called if [taskInfo] relates to a focused task
private fun isTilingRefocused(taskInfo: RunningTaskInfo): Boolean {
- return !isTilingFocused &&
- (taskInfo.taskId == leftTaskResizingHelper?.taskInfo?.taskId ||
- taskInfo.taskId == rightTaskResizingHelper?.taskInfo?.taskId)
+ return taskInfo.taskId == leftTaskResizingHelper?.taskInfo?.taskId ||
+ taskInfo.taskId == rightTaskResizingHelper?.taskInfo?.taskId
}
private fun buildTiledTasksMoveToFront(leftOnTop: Boolean): WindowContainerTransaction {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
index 111e28e450bd..b8e3b0fdb8d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
@@ -21,8 +21,10 @@ import android.graphics.Paint
import android.graphics.Rect
import android.provider.DeviceConfig
import android.util.AttributeSet
+import android.util.Size
import android.view.MotionEvent
import android.view.PointerIcon
+import android.view.RoundedCorner
import android.view.View
import android.view.ViewConfiguration
import android.widget.FrameLayout
@@ -42,6 +44,7 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
private lateinit var callback: DividerMoveCallback
private lateinit var handle: DividerHandleView
private lateinit var corners: DividerRoundedCorner
+ private var cornersRadius: Int = 0
private var touchElevation = 0
private var moving = false
@@ -49,8 +52,7 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
var handleRegionWidth: Int = 0
private var handleRegionHeight = 0
private var lastAcceptedPos = 0
- @VisibleForTesting var handleStartY = 0
- @VisibleForTesting var handleEndY = 0
+ @VisibleForTesting var handleY: IntRange = 0..0
private var canResize = false
private var resized = false
/**
@@ -79,16 +81,19 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
) : super(context, attrs, defStyleAttr, defStyleRes)
/** Sets up essential dependencies of the divider bar. */
- fun setup(dividerMoveCallback: DividerMoveCallback, dividerBounds: Rect) {
+ fun setup(
+ dividerMoveCallback: DividerMoveCallback,
+ dividerBounds: Rect,
+ handleRegionSize: Size,
+ ) {
callback = dividerMoveCallback
this.dividerBounds.set(dividerBounds)
handle.setIsLeftRightSplit(true)
corners.setIsLeftRightSplit(true)
- handleRegionHeight =
- resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width)
-
- handleRegionWidth =
- resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
+ handleRegionHeight = handleRegionSize.height
+ handleRegionWidth = handleRegionSize.width
+ cornersRadius =
+ context.display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)?.radius ?: 0
initHandleYCoordinates()
dragDetector =
DragDetector(
@@ -241,17 +246,17 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
return true
}
- private fun isWithinHandleRegion(touchYPos: Int): Boolean {
- return touchYPos in handleStartY..handleEndY
- }
+ private fun isWithinHandleRegion(touchYPos: Int): Boolean = touchYPos in handleY
private fun initHandleYCoordinates() {
- handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
- handleEndY = handleStartY + handleRegionHeight
+ val handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
+ val handleEndY = handleStartY + handleRegionHeight
+ handleY = handleStartY..handleEndY
}
companion object {
const val TOUCH_ANIMATION_DURATION: Long = 150
const val TOUCH_RELEASE_ANIMATION_DURATION: Long = 200
+ private val TAG = TilingDividerView::class.java.simpleName
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
index 503ad92d4d71..3f65d9318692 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
@@ -38,6 +38,7 @@ import android.window.DesktopModeFlags
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
import com.android.internal.policy.SystemBarUtils
+import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.shared.animation.Interpolators
import com.android.wm.shell.windowdecor.WindowManagerWrapper
@@ -114,7 +115,7 @@ internal class AppHandleViewHolder(
// If handle is not in status bar region(i.e., bottom stage in vertical split),
// do not create an input layer
if (position.y >= SystemBarUtils.getStatusBarHeight(context)) return
- if (!isCaptionVisible && statusBarInputLayerExists) {
+ if (!isCaptionVisible) {
disposeStatusBarInputLayer()
return
}
@@ -143,7 +144,8 @@ internal class AppHandleViewHolder(
if (!DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue()) return
statusBarInputLayer = AdditionalSystemViewContainer(context, windowManagerWrapper,
taskInfo.taskId, handlePosition.x, handlePosition.y, handleWidth, handleHeight,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ ignoreCutouts = Flags.showAppHandleLargeScreens()
)
val view = statusBarInputLayer?.view ?: error("Unable to find statusBarInputLayer View")
val lp = statusBarInputLayer?.lp ?: error("Unable to find statusBarInputLayer " +
@@ -227,6 +229,7 @@ internal class AppHandleViewHolder(
* is not visible.
*/
fun disposeStatusBarInputLayer() {
+ if (!statusBarInputLayerExists) return
statusBarInputLayerExists = false
handler.post {
statusBarInputLayer?.releaseView()
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 65e50f86e8fe..19829e7e5677 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -6,6 +6,7 @@ pablogamito@google.com
lbill@google.com
madym@google.com
hwwang@google.com
+gabiyev@google.com
chenghsiuchang@google.com
atsjenk@google.com
jorgegil@google.com
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt
new file mode 100644
index 000000000000..898964f0fdbc
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_90
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.BRING_APPS_TO_FRONT
+import com.android.wm.shell.scenarios.BringDesktopAppsToFront
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Bring apps to front by clicking on the App Header.
+ *
+ * Assert that the app windows move to front.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class BringDesktopAppsToFrontLandscape : BringDesktopAppsToFront(rotation = ROTATION_90) {
+
+ @ExpectedScenarios(["BRING_APPS_TO_FRONT"])
+ @Test
+ override fun bringDesktopAppsToFront() = super.bringDesktopAppsToFront()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig()
+ .use(FlickerServiceConfig.DEFAULT)
+ .use(BRING_APPS_TO_FRONT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt
new file mode 100644
index 000000000000..b123d7d96129
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_0
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.BRING_APPS_TO_FRONT
+import com.android.wm.shell.scenarios.BringDesktopAppsToFront
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Bring apps to front by clicking on the App Header.
+ *
+ * Assert that the app windows move to front.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class BringDesktopAppsToFrontPortrait : BringDesktopAppsToFront(rotation = ROTATION_0) {
+
+ @ExpectedScenarios(["BRING_APPS_TO_FRONT"])
+ @Test
+ override fun bringDesktopAppsToFront() = super.bringDesktopAppsToFront()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig()
+ .use(FlickerServiceConfig.DEFAULT)
+ .use(BRING_APPS_TO_FRONT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index 4cddf31321d6..d9c36cc70790 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -25,6 +25,8 @@ import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways
import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart
import android.tools.flicker.assertors.assertions.AppWindowAlignsWithOnlyOneDisplayCornerAtEnd
import android.tools.flicker.assertors.assertions.AppWindowBecomesInvisible
+import android.tools.flicker.assertors.assertions.AppWindowBecomesPinned
+import android.tools.flicker.assertors.assertions.AppWindowBecomesTopWindow
import android.tools.flicker.assertors.assertions.AppWindowBecomesVisible
import android.tools.flicker.assertors.assertions.AppWindowCoversLeftHalfScreenAtEnd
import android.tools.flicker.assertors.assertions.AppWindowCoversRightHalfScreenAtEnd
@@ -49,6 +51,7 @@ import android.tools.flicker.config.common.Components.LAUNCHER
import android.tools.flicker.config.desktopmode.Components.DESKTOP_MODE_APP
import android.tools.flicker.config.desktopmode.Components.DESKTOP_WALLPAPER
import android.tools.flicker.config.desktopmode.Components.NON_RESIZABLE_APP
+import android.tools.flicker.config.desktopmode.Components.SIMPLE_APP
import android.tools.flicker.extractors.ITransitionMatcher
import android.tools.flicker.extractors.ShellTransitionScenarioExtractor
import android.tools.flicker.extractors.TaggedCujTransitionMatcher
@@ -345,6 +348,30 @@ class DesktopModeFlickerScenarios {
).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
)
+ val BRING_APPS_TO_FRONT =
+ FlickerConfigEntry(
+ scenarioId = ScenarioId("BRING_APPS_TO_FRONT"),
+ extractor =
+ ShellTransitionScenarioExtractor(
+ transitionMatcher =
+ object : ITransitionMatcher {
+ override fun findAll(
+ transitions: Collection<Transition>
+ ): Collection<Transition> {
+ return transitions.filter {
+ it.type == TransitionType.TO_FRONT
+ }
+ }
+ }
+ ),
+ assertions =
+ AssertionTemplates.COMMON_ASSERTIONS +
+ listOf(
+ AppWindowBecomesTopWindow(DESKTOP_MODE_APP),
+ AppWindowOnTopAtEnd(DESKTOP_MODE_APP),
+ ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING })
+ )
+
val CASCADE_APP =
FlickerConfigEntry(
scenarioId = ScenarioId("CASCADE_APP"),
@@ -419,5 +446,45 @@ class DesktopModeFlickerScenarios {
AppWindowOnTopAtEnd(LAUNCHER),
).associateBy({ it }, { AssertionInvocationGroup.BLOCKING })
)
+ val OPEN_UNLIMITED_APPS =
+ FlickerConfigEntry(
+ scenarioId = ScenarioId("OPEN_UNLIMITED_APPS"),
+ extractor =
+ ShellTransitionScenarioExtractor(
+ transitionMatcher =
+ object : ITransitionMatcher {
+ override fun findAll(
+ transitions: Collection<Transition>
+ ): Collection<Transition> {
+ return transitions.filter { it.type == TransitionType.OPEN }
+ }
+ }
+ ),
+ assertions =
+ listOf(
+ AppWindowBecomesVisible(DESKTOP_MODE_APP),
+ AppWindowIsVisibleAlways(SIMPLE_APP)
+ ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+ )
+
+ val MINIMIZE_AUTO_PIP_APP =
+ FlickerConfigEntry(
+ scenarioId = ScenarioId("MINIMIZE_AUTO_PIP_APP"),
+ extractor =
+ ShellTransitionScenarioExtractor(
+ transitionMatcher =
+ object : ITransitionMatcher {
+ override fun findAll(
+ transitions: Collection<Transition>
+ ): Collection<Transition> =
+ transitions.filter { it.type == TransitionType.PIP }
+ }
+ ),
+ assertions =
+ AssertionTemplates.COMMON_ASSERTIONS +
+ listOf(
+ AppWindowBecomesPinned(DESKTOP_MODE_APP),
+ ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING })
+ )
}
}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt
new file mode 100644
index 000000000000..e1120bdda194
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_90
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by dragging it to the top drag zone.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppWindowWithDragToTopDragZoneLandscape : MaximizeAppWindowWithDragToTopDragZone(
+ rotation = ROTATION_90
+) {
+ @ExpectedScenarios(["MAXIMIZE_APP"])
+ @Test
+ override fun maximizeAppWithDragToTopDragZone() = super.maximizeAppWithDragToTopDragZone()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt
new file mode 100644
index 000000000000..fb910c7b907d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by dragging it to the top drag zone.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppWindowWithDragToTopDragZonePortrait : MaximizeAppWindowWithDragToTopDragZone() {
+ @ExpectedScenarios(["MAXIMIZE_APP"])
+ @Test
+ override fun maximizeAppWithDragToTopDragZone() = super.maximizeAppWithDragToTopDragZone()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt
new file mode 100644
index 000000000000..b10db689e5bd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MINIMIZE_AUTO_PIP_APP
+import com.android.wm.shell.scenarios.MinimizeAutoPipAppWindow
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MinimizeAutoPipAppWindow : MinimizeAutoPipAppWindow() {
+ @ExpectedScenarios(["MINIMIZE_AUTO_PIP_APP"])
+ @Test
+ override fun minimizePipAppWindow() = super.minimizePipAppWindow()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MINIMIZE_AUTO_PIP_APP)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenUnlimitedApps.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenUnlimitedApps.kt
new file mode 100644
index 000000000000..0a3984612987
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenUnlimitedApps.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.OPEN_UNLIMITED_APPS
+import com.android.wm.shell.scenarios.OpenUnlimitedApps
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Open many apps on the device without the window limit.
+ *
+ * Assert that the desktop task limit is not triggered.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenUnlimitedApps : OpenUnlimitedApps() {
+ @ExpectedScenarios(["OPEN_UNLIMITED_APPS"])
+ @Test
+ override fun openUnlimitedApps() = super.openUnlimitedApps()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(OPEN_UNLIMITED_APPS)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt
new file mode 100644
index 000000000000..6c8cc68da7c0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.BringDesktopAppsToFront
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/** Functional test for [BringDesktopAppsToFront]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class BringDesktopAppsToFrontTest : BringDesktopAppsToFront()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt
new file mode 100644
index 000000000000..7e0b81a783c0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [MaximizeAppWindowWithDragToTopDragZone]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class MaximizeAppWindowWithDragToTopDragZoneTest : MaximizeAppWindowWithDragToTopDragZone()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MinimizeAutoPipAppWindowTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MinimizeAutoPipAppWindowTest.kt
new file mode 100644
index 000000000000..48befc06b9c5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MinimizeAutoPipAppWindowTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.MinimizeAutoPipAppWindow
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [MinimizeAutoPipAppWindow]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class MinimizeAutoPipAppWindowTest : MinimizeAutoPipAppWindow()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenUnlimitedAppsTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenUnlimitedAppsTest.kt
new file mode 100644
index 000000000000..9462f15335de
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenUnlimitedAppsTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.OpenUnlimitedApps
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [OpenUnlimitedApps]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class OpenUnlimitedAppsTest : OpenUnlimitedApps()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt
new file mode 100644
index 000000000000..1db22ebb8c73
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.scenarios
+
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.MailAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Test Base Class")
+abstract class BringDesktopAppsToFront(
+ val rotation: Rotation = Rotation.ROTATION_0,
+ isResizable: Boolean = true,
+ isLandscapeApp: Boolean = true,
+) : DesktopScenarioCustomAppTestBase(isResizable, isLandscapeApp) {
+
+ private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
+
+ @Rule
+ @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ ChangeDisplayOrientationRule.setRotation(rotation)
+ tapl.enableTransientTaskbar(false)
+ // Launch a first app and snap it to left side so that it doesn't overlap too much with
+ // the next launching app, and their headers are visible enough to switch focus by tapping
+ // on them.
+ testApp.enterDesktopMode(wmHelper, device)
+ testApp.snapResizeDesktopApp(wmHelper, device, instrumentation.context, toLeft = true)
+ mailApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun bringDesktopAppsToFront() {
+ testApp.bringToFront(wmHelper, device)
+ mailApp.bringToFront(wmHelper, device)
+ testApp.bringToFront(wmHelper, device)
+ mailApp.bringToFront(wmHelper, device)
+ }
+
+ @After
+ fun teardown() {
+ mailApp.exit(wmHelper)
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
index 351a70094654..f9bf49ecae1c 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
@@ -57,7 +57,7 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
mailApp.launchViaIntent(wmHelper)
nonResizeableApp.launchViaIntent(wmHelper)
}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
index 3f9927f1fab6..16e537361b66 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
@@ -40,7 +40,7 @@ abstract class DragAppWindowMultiWindow : DragAppWindowScenarioTestBase()
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
mailApp.launchViaIntent(wmHelper)
newTasksApp.launchViaIntent(wmHelper)
imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
index 6d52a11153d9..bb812ad51135 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
@@ -45,9 +45,9 @@ open class DragAppWindowMultiWindowAndPip : DragAppWindowScenarioTestBase()
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ testApp.enterDesktopMode(wmHelper, device)
// Set string extra to ensure the app is on PiP mode at launch
pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
- testApp.enterDesktopWithDrag(wmHelper, device)
mailApp.launchViaIntent(wmHelper)
newTasksApp.launchViaIntent(wmHelper)
imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt
index 91cfd17340fc..786a8b710434 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt
@@ -36,7 +36,7 @@ open class DragAppWindowSingleWindow : DragAppWindowScenarioTestBase()
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
index 967bd29958c2..8d04749d76a5 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
@@ -49,7 +49,8 @@ constructor(
@Test
open fun enterDesktopWithDrag() {
- testApp.enterDesktopWithDrag(wmHelper, device)
+ // By default this method uses drag to desktop
+ testApp.enterDesktopMode(wmHelper, device)
}
@After
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
index f442fdb31592..28008393da84 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
@@ -46,7 +46,7 @@ constructor(
instrumentation.context.resources.getBoolean(R.bool.config_dragToMaximizeInDesktopMode))
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt
index 6637b01f9d9c..5cf51e3be18c 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt
@@ -66,7 +66,7 @@ abstract class MaximiseAppWithCornerResize(
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
ChangeDisplayOrientationRule.setRotation(rotation)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
testApp.cornerResize(
wmHelper,
device,
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
index a54d497bf511..d2be4944d365 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
@@ -58,7 +58,7 @@ constructor(private val rotation: Rotation = Rotation.ROTATION_0, isResizable: B
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
ChangeDisplayOrientationRule.setRotation(rotation)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt
new file mode 100644
index 000000000000..60a0fb547909
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.internal.R
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+/**
+ * Base scenario test for maximizing a desktop app window by dragging it to the top drag zone.
+ */
+@Ignore("Test Base Class")
+abstract class MaximizeAppWindowWithDragToTopDragZone
+constructor(private val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ // Skip the test when the drag-to-maximize is disabled on this device.
+ Assume.assumeTrue(Flags.enableDragToMaximize() &&
+ instrumentation.context.resources.getBoolean(R.bool.config_dragToMaximizeInDesktopMode))
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ ChangeDisplayOrientationRule.setRotation(rotation)
+ testApp.enterDesktopMode(wmHelper, device)
+ }
+
+ @Test
+ open fun maximizeAppWithDragToTopDragZone() {
+ testApp.maximizeAppWithDragToTopDragZone(wmHelper, device)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt
index b5483634b057..971637b62604 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt
@@ -61,7 +61,7 @@ constructor(private val rotation: Rotation = Rotation.ROTATION_0) {
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
ChangeDisplayOrientationRule.setRotation(rotation)
- testApp1.enterDesktopWithDrag(wmHelper, device)
+ testApp1.enterDesktopMode(wmHelper, device)
testApp2.launchViaIntent(wmHelper)
testApp3.launchViaIntent(wmHelper)
}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAutoPipAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAutoPipAppWindow.kt
new file mode 100644
index 000000000000..d6c3266e915c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAutoPipAppWindow.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+/** Base scenario test for minimizing the app entering pip on leave automatically */
+@Ignore("Test Base Class")
+abstract class MinimizeAutoPipAppWindow {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+ private val pipApp = PipAppHelper(instrumentation)
+ private val pipAppDesktopMode = DesktopModeAppHelper(pipApp)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ Assume.assumeTrue(Flags.enableMinimizeButton())
+ testApp.enterDesktopMode(wmHelper, device)
+ pipApp.launchViaIntent(wmHelper)
+ pipApp.enableAutoEnterForPipActivity()
+ }
+
+ @Test
+ open fun minimizePipAppWindow() {
+ pipAppDesktopMode.minimizeDesktopApp(wmHelper, device, isPip = true)
+ }
+
+ @After
+ fun teardown() {
+ pipApp.exit(wmHelper)
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt
index b86765e23422..a246326f1137 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt
@@ -23,12 +23,10 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.LetterboxAppHelper
import com.android.server.wm.flicker.helpers.MailAppHelper
-import com.android.server.wm.flicker.helpers.NewTasksAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.window.flags.Flags
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import org.junit.After
import org.junit.Assume
import org.junit.Before
@@ -51,32 +49,30 @@ open class MinimizeWindowOnAppOpen()
private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
- private val newTasksApp = DesktopModeAppHelper(NewTasksAppHelper(instrumentation))
- private val imeApp = DesktopModeAppHelper(ImeAppHelper(instrumentation))
- private val letterboxAppHelper = DesktopModeAppHelper(LetterboxAppHelper(instrumentation))
+
+ private val maxNum = DesktopModeStatus.getMaxTaskLimit(instrumentation.context)
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
- testApp.enterDesktopWithDrag(wmHelper, device)
- mailApp.launchViaIntent(wmHelper)
- newTasksApp.launchViaIntent(wmHelper)
- imeApp.launchViaIntent(wmHelper)
+ Assume.assumeTrue(maxNum > 0)
+ testApp.enterDesktopMode(wmHelper, device)
+ // Launch new [maxNum-1] tasks, which ends up opening [maxNum] tasks in total.
+ for (i in 1..maxNum - 1) {
+ mailApp.launchViaIntent(wmHelper)
+ }
}
@Test
open fun openAppToMinimizeWindow() {
- // Launch a new app while 4 apps are already open on desktop. This should result in the
- // first app we opened to be minimized.
- letterboxAppHelper.launchViaIntent(wmHelper)
+ // Launch a new tasks, which ends up opening [maxNum]+1 tasks in total. This should
+ // result in the first app we opened to be minimized.
+ mailApp.launchViaIntent(wmHelper)
}
@After
fun teardown() {
testApp.exit(wmHelper)
mailApp.exit(wmHelper)
- newTasksApp.exit(wmHelper)
- imeApp.exit(wmHelper)
- letterboxAppHelper.exit(wmHelper)
}
}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
index aad266fb8374..6ce36f53f0d1 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
@@ -61,7 +61,7 @@ abstract class OpenAppsInDesktopMode(val rotation: Rotation = Rotation.ROTATION_
tapl.setExpectedRotation(rotation.value)
tapl.enableTransientTaskbar(false)
ChangeDisplayOrientationRule.setRotation(rotation)
- firstApp.enterDesktopWithDrag(wmHelper, device)
+ firstApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt
new file mode 100644
index 000000000000..367c4a437018
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.MailAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+/**
+ * Base scenario test for opening many apps on the device without the window limit.
+ */
+@Ignore("Test Base Class")
+abstract class OpenUnlimitedApps()
+{
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+
+ private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+ private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
+
+ private val maxNum = DesktopModeStatus.getMaxTaskLimit(instrumentation.context)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ Assume.assumeTrue(maxNum == 0)
+ testApp.enterDesktopMode(wmHelper, device)
+ }
+
+ @Test
+ open fun openUnlimitedApps() {
+ // The maximum number of active tasks is infinite. We here use 12 as a large enough number.
+ val openTaskNum = 12
+
+ // Launch new [openTaskNum] tasks.
+ for (i in 1..openTaskNum) {
+ mailApp.launchViaIntent(wmHelper)
+ }
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ mailApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
index bfee3181cbc0..eefa0bb3c00a 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
@@ -61,7 +61,7 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0,
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
mailApp.launchViaIntent(wmHelper)
newTasksApp.launchViaIntent(wmHelper)
imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
index 5b1b64e7c562..41452c3bdd9f 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
@@ -63,9 +63,9 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0,
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
+ testApp.enterDesktopMode(wmHelper, device)
// Set string extra to ensure the app is on PiP mode at launch
pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
- testApp.enterDesktopWithDrag(wmHelper, device)
mailApp.launchViaIntent(wmHelper)
newTasksApp.launchViaIntent(wmHelper)
imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
index a7cebf402d8e..64636230e5e0 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
@@ -67,7 +67,7 @@ abstract class ResizeAppWithCornerResize(
tapl.setEnableRotation(true)
ChangeDisplayOrientationRule.setRotation(rotation)
tapl.setExpectedRotation(rotation.value)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
index 67802387b267..f198cfed7c50 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
@@ -60,7 +60,7 @@ constructor(
)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
index 2b40497844ef..fd4c2434589d 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
@@ -56,7 +56,7 @@ constructor(private val toLeft: Boolean = true, isResizable: Boolean = true) {
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
index b4bd7e1c5211..62e860ed24a7 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
@@ -56,7 +56,7 @@ constructor(private val toLeft: Boolean = true, isResizable: Boolean = true) {
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
index f08e50e0d4ee..de330e072ad1 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
@@ -59,7 +59,7 @@ open class StartAppMediaProjectionResizeAndDrag {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(0)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
index ce235d445fe5..4b3f15f1db86 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
@@ -67,7 +67,7 @@ open class StartAppMediaProjectionWithMaxDesktopWindows {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(0)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
index 005195296c62..a1083671f687 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
@@ -62,7 +62,7 @@ open class StartScreenMediaProjectionWithMaxDesktopWindows {
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
index dad2eb633c72..1455bd1888e2 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
@@ -54,7 +54,7 @@ constructor(val navigationMode: NavBar = NavBar.MODE_GESTURAL) {
@Before
fun setup() {
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
- testApp.enterDesktopWithDrag(wmHelper, device)
+ testApp.enterDesktopMode(wmHelper, device)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
deleted file mode 100644
index 85e6a8d1d865..000000000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
+++ /dev/null
@@ -1,38 +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 {
- // 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: "WMShellFlickerTestsMediaProjection",
- defaults: ["WMShellFlickerTestsDefault"],
- manifest: "AndroidManifest.xml",
- test_config_template: "AndroidTestTemplate.xml",
- srcs: ["src/**/*.kt"],
- static_libs: [
- "WMShellFlickerTestsBase",
- "WMShellScenariosMediaProjection",
- "WMShellTestUtils",
- ],
- data: ["trace_config/*"],
-}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
deleted file mode 100644
index 74b0daf3a2aa..000000000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<!--
- ~ Copyright (C) 2023 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"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.wm.shell.flicker">
-
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
- <!-- Read and write traces from external storage -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <!-- Allow the test to write directly to /sdcard/ -->
- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
- <!-- Write secure settings -->
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <!-- Capture screen contents -->
- <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
- <!-- Enable / Disable tracing !-->
- <uses-permission android:name="android.permission.DUMP" />
- <!-- Run layers trace -->
- <uses-permission android:name="android.permission.HARDWARE_TEST"/>
- <!-- Capture screen recording -->
- <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
- <!-- Workaround grant runtime permission exception from b/152733071 -->
- <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
- <uses-permission android:name="android.permission.READ_LOGS"/>
- <!-- Force-stop test apps -->
- <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
- <!-- Control test app's media session -->
- <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
- <!-- ATM.removeRootTasksWithActivityTypes() -->
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
- <!-- Enable bubble notification-->
- <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
- <!-- Allow the test to connect to perfetto trace processor -->
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
- <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
-
- <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
- <application android:requestLegacyExternalStorage="true"
- android:networkSecurityConfig="@xml/network_security_config"
- android:largeHeap="true">
- <uses-library android:name="android.test.runner"/>
-
- <service android:name=".NotificationListener"
- android:exported="true"
- android:label="WMShellTestsNotificationListenerService"
- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
- <intent-filter>
- <action android:name="android.service.notification.NotificationListenerService" />
- </intent-filter>
- </service>
-
- <service android:name="com.android.wm.shell.flicker.utils.MediaProjectionService"
- android:foregroundServiceType="mediaProjection"
- android:label="WMShellTestsMediaProjectionService"
- android:enabled="true">
- </service>
-
- <!-- (b/197936012) Remove startup provider due to test timeout issue -->
- <provider
- android:name="androidx.startup.InitializationProvider"
- android:authorities="${applicationId}.androidx-startup"
- tools:node="remove" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.wm.shell.flicker"
- android:label="WindowManager Shell Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
deleted file mode 100644
index 40dbbac32c7f..000000000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 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.
- -->
-<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}">
- <option name="test-tag" value="FlickerTests"/>
- <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
- <option name="isolated-storage" value="false"/>
-
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <!-- disable DeprecatedTargetSdk warning -->
- <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
- <!-- keeps the screen on during tests -->
- <option name="screen-always-on" value="on"/>
- <!-- prevents the phone from restarting -->
- <option name="force-skip-system-props" value="true"/>
- <!-- set WM tracing verbose level to all -->
- <option name="run-command" value="cmd window tracing level all"/>
- <!-- set WM tracing to frame (avoid incomplete states) -->
- <option name="run-command" value="cmd window tracing frame"/>
- <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
- <option name="run-command" value="pm disable com.google.android.internal.betterbug"/>
- <!-- ensure lock screen mode is swipe -->
- <option name="run-command" value="locksettings set-disabled false"/>
- <!-- restart launcher to activate TAPL -->
- <option name="run-command"
- value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/>
- <!-- Increase trace size: 20mb for WM and 80mb for SF -->
- <option name="run-command" value="cmd window tracing size 20480"/>
- <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/>
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="test-user-token" value="%TEST_USER%"/>
- <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
- <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
- <option name="run-command" value="settings put system show_touches 1"/>
- <option name="run-command" value="settings put system pointer_location 1"/>
- <option name="teardown-command"
- value="settings delete secure show_ime_with_hard_keyboard"/>
- <option name="teardown-command" value="settings delete system show_touches"/>
- <option name="teardown-command" value="settings delete system pointer_location"/>
- <option name="teardown-command"
- value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/>
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="{MODULE}.apk"/>
- <option name="test-file-name" value="FlickerTestApp.apk"/>
- </target_preparer>
-
- <!-- Needed for pushing the trace config file -->
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="push-file"
- key="trace_config.textproto"
- value="/data/misc/perfetto-traces/trace_config.textproto"
- />
- <!--Install the content provider automatically when we push some file in sdcard folder.-->
- <!--Needed to avoid the installation during the test suite.-->
- <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/>
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="{PACKAGE}"/>
- <option name="shell-timeout" value="6600s"/>
- <option name="test-timeout" value="6000s"/>
- <option name="hidden-api-checks" value="false"/>
- <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
- <!-- PerfettoListener related arguments -->
- <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
- <option name="instrumentation-arg"
- key="perfetto_config_file"
- value="trace_config.textproto"
- />
- <option name="instrumentation-arg" key="per_run" value="true"/>
- <option name="instrumentation-arg" key="perfetto_persist_pid_track" value="true"/>
- </test>
- <!-- Needed for pulling the collected trace config on to the host -->
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="pull-pattern-keys" value="perfetto_file_path"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="collect-on-run-ended-only" value="true"/>
- <option name="clean-up" value="true"/>
- </metrics_collector>
-</configuration>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
deleted file mode 100644
index 9f2e49755fec..000000000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) 2023 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.
-
-# proto-message: TraceConfig
-
-# Enable periodic flushing of the trace buffer into the output file.
-write_into_file: true
-
-# Writes the userspace buffer into the file every 1s.
-file_write_period_ms: 2500
-
-# See b/126487238 - we need to guarantee ordering of events.
-flush_period_ms: 30000
-
-# The trace buffers needs to be big enough to hold |file_write_period_ms| of
-# trace data. The trace buffer sizing depends on the number of trace categories
-# enabled and the device activity.
-
-# RSS events
-buffers: {
- size_kb: 63488
- fill_policy: RING_BUFFER
-}
-
-data_sources {
- config {
- name: "linux.process_stats"
- target_buffer: 0
- # polled per-process memory counters and process/thread names.
- # If you don't want the polled counters, remove the "process_stats_config"
- # section, but keep the data source itself as it still provides on-demand
- # thread/process naming for ftrace data below.
- process_stats_config {
- scan_all_processes_on_start: true
- }
- }
-}
-
-data_sources: {
- config {
- name: "linux.ftrace"
- ftrace_config {
- ftrace_events: "ftrace/print"
- ftrace_events: "task/task_newtask"
- ftrace_events: "task/task_rename"
- atrace_categories: "ss"
- atrace_categories: "wm"
- atrace_categories: "am"
- atrace_categories: "aidl"
- atrace_categories: "input"
- atrace_categories: "binder_driver"
- atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker.testapp"
- atrace_apps: "com.android.systemui"
- atrace_apps: "com.android.wm.shell.flicker.service"
- atrace_apps: "com.google.android.apps.nexuslauncher"
- }
- }
-}
-
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt
new file mode 100644
index 000000000000..2b9772d9cbdd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionFromSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionFromSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionFromSplitScreenTest() : StartAppMediaProjectionFromSplitScreen() \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt
new file mode 100644
index 000000000000..e92297b48166
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionInSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionInSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionInSplitScreenTest() : StartAppMediaProjectionInSplitScreen() \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt
new file mode 100644
index 000000000000..3f8107592667
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjection
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjection]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionTest() : StartAppMediaProjection() \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt
new file mode 100644
index 000000000000..1975cc7f86d2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionWithExtraIntent
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionWithExtraIntent]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionWithExtraIntentTest : StartAppMediaProjectionWithExtraIntent() \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt
new file mode 100644
index 000000000000..943033c1819c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjectionFromSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjectionFromSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionFromSplitScreenTest() : StartRecentAppMediaProjectionFromSplitScreen() \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt
new file mode 100644
index 000000000000..6facfd5b0063
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjectionInSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjectionInSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionInSplitScreenTest() : StartRecentAppMediaProjectionInSplitScreen() \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt
new file mode 100644
index 000000000000..bab09052715a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjection
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjection]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionTest() : StartRecentAppMediaProjection() \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt
new file mode 100644
index 000000000000..fe2c57801f72
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session.
+ *
+ * This is for testing that the requested app is opened as expected upon selecting it from the app
+ * selector, so capture can proceed as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjection {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt
new file mode 100644
index 000000000000..3beece8c38b8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session, while the HOST app is in
+ * split screen
+ *
+ * This is for testing that the requested app is opened as expected upon selecting it from the app
+ * selector, so capture can proceed as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionFromSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val simpleApp = SimpleAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, simpleApp, testApp, initialRotation)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, simpleApp, testApp)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt
new file mode 100644
index 000000000000..d3186ae88081
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session, while the TARGET app is in
+ * split screen (next to the host app)
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionInSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, targetApp, testApp, initialRotation)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .withWindowSurfaceAppeared(testApp)
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ targetApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt
new file mode 100644
index 000000000000..0b2a1ca23cdb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session but launches an intent to
+ * return to the home screen, before the intent for opening the requested app to capture.
+ *
+ * This is for testing that even if a different intent interrupts the process the launching the
+ * requested capture target, the MediaProjection process isn't interrupted and the device is still
+ * interactive.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionWithExtraIntent {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjectionWithExtraIntent(wmHelper, targetApp)
+
+ // Check we can still interact with device after
+ tapl.workspace.switchToAllApps().getAppIcon(targetApp.appName).launch(targetApp.packageName)
+
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt
new file mode 100644
index 000000000000..30e0e4aa490a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents.
+ *
+ * This is for testing that the app is started from recents and capture proceeds as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjection {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ targetApp.open()
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt
new file mode 100644
index 000000000000..f1dcf1fab140
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents while the HOST
+ * app is in split screen.
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjectionFromSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val simpleApp = SimpleAppHelper(instrumentation)
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ targetApp.open()
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, simpleApp, testApp, initialRotation)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ // The app we want to open for PSS will be the second item in the carousel,
+ // because the first will be the app open in split screen alongside the MediaProjection app
+ testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp, recentTasksIndex = 1)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt
new file mode 100644
index 000000000000..0a6992f9a152
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents while the
+ * TARGET app is in split screen (with host app).
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjectionInSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, targetApp, testApp, initialRotation)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp)
+
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .withWindowSurfaceAppeared(testApp)
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ targetApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
index 176020ffc3b9..6d12b00a61e6 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
@@ -49,6 +49,7 @@ java_library {
"wm-flicker-common-assertions",
"launcher-helper-lib",
"launcher-aosp-tapl",
+ "com_android_wm_shell_flags_lib",
],
}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 6d396ea6e9d4..9c71510df8a0 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -17,12 +17,16 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
import com.android.wm.shell.flicker.utils.ICommonAssertions
import com.android.wm.shell.flicker.utils.appWindowBecomesInvisible
@@ -30,6 +34,7 @@ import com.android.wm.shell.flicker.utils.layerBecomesInvisible
import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesInvisible
import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesInvisible
import org.junit.FixMethodOrder
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -44,8 +49,13 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class DismissSplitScreenByGoHome(override val flicker: LegacyFlickerTest) :
DismissSplitScreenByGoHomeBenchmark(flicker), ICommonAssertions {
+ @JvmField
+ @Rule
+ val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
override val transition: FlickerBuilder.() -> Unit
get() = {
defaultSetup(this)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index a248303b1c33..fd4328dee0a1 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -16,16 +16,18 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder
import android.tools.flicker.subject.exceptions.IncorrectRegionException
import android.tools.flicker.subject.layers.LayerSubject
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import org.junit.Assume
import org.junit.FixMethodOrder
@@ -35,6 +37,7 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
import kotlin.math.abs
+
/**
* Test entering pip from an app via auto-enter property when navigating to home.
*
@@ -60,6 +63,7 @@ import kotlin.math.abs
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
index df952c925720..d4ad4ef8a401 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
@@ -17,10 +17,12 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.traces.component.ComponentNameMatcher
+import com.android.wm.shell.Flags
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -52,6 +54,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class AutoEnterPipWithSourceRectHintTest(flicker: LegacyFlickerTest) :
AutoEnterPipOnGoToHomeTest(flicker) {
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index 302b8c414979..cc6e4b5a90d5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
@@ -53,6 +54,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 77a1edb7039a..53725fa046c6 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -17,9 +17,11 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.ClosePipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -52,6 +54,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.closePipWindow(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 6e32d6412b50..a1551b7924fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,9 +17,11 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import org.junit.Assume
import org.junit.FixMethodOrder
@@ -43,6 +45,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index 9a6cb61cfc66..ea5b3e5b08df 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.pip
import android.app.Activity
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.assertions.FlickerTest
import android.tools.flicker.junit.FlickerParametersRunnerFactory
@@ -32,6 +33,7 @@ import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -68,6 +70,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = FixedOrientationAppHelper(instrumentation)
private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index 6b4751cee3bb..a109c4bba2b3 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -16,9 +16,11 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -49,6 +51,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
open class EnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.clickEnterPipButton(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 8d0bc0f5a155..14ec303206ee 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -16,9 +16,11 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -51,6 +53,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) :
ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index 939f3280d2e6..8a34b5e27fdb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -16,9 +16,11 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -50,6 +52,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 258663b5556d..4f189fc6190d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -17,12 +17,14 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.traces.component.ComponentNameMatcher
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -54,6 +56,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class ExpandPipOnDoubleClickTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.doubleClickPipWindow(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 1964e3cebc89..4d72b03d0345 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -17,11 +17,13 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -33,6 +35,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class ExpandPipOnPinchOpenTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.25f, 30) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
index 5f8ac2af241b..1c40d89aec80 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
@@ -16,7 +16,10 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
@@ -24,10 +27,9 @@ import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.helpers.WindowUtils
import android.tools.traces.parsers.toFlickerComponent
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.FixMethodOrder
@@ -62,6 +64,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class FromSplitScreenAutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) :
AutoEnterPipOnGoToHomeTest(flicker) {
private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index 48c85a84e556..12e23285ea68 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -16,7 +16,10 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
@@ -24,10 +27,9 @@ import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.helpers.WindowUtils
import android.tools.traces.parsers.toFlickerComponent
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
@@ -63,6 +65,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :
EnterPipTransition(flicker) {
private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index ee62cf59b2f9..d979b428d8b2 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -17,10 +17,12 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
import com.android.wm.shell.flicker.utils.Direction
import org.junit.FixMethodOrder
@@ -56,6 +58,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class MovePipDownOnShelfHeightChange(flicker: LegacyFlickerTest) :
MovePipShelfHeightTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index 04fedf4f2550..88d78edae94a 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.assertions.FlickerTest
import android.tools.flicker.junit.FlickerParametersRunnerFactory
@@ -27,6 +28,7 @@ import android.tools.helpers.WindowUtils
import android.tools.traces.component.ComponentNameMatcher
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -41,6 +43,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class MovePipOnImeVisibilityChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val imeApp = ImeAppHelper(instrumentation)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 4d643f7b4408..c533800b37c5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -17,10 +17,12 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
import com.android.wm.shell.flicker.utils.Direction
import org.junit.FixMethodOrder
@@ -56,6 +58,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
open class MovePipUpOnShelfHeightChangeTest(flicker: LegacyFlickerTest) :
MovePipShelfHeightTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
@@ -65,7 +68,8 @@ open class MovePipUpOnShelfHeightChangeTest(flicker: LegacyFlickerTest) :
}
/** Checks that the visible region of [pipApp] window always moves up during the animation. */
- @Presubmit @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
+ @Presubmit
+ @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
/** Checks that the visible region of [pipApp] layer always moves up during the animation. */
@Presubmit @Test fun pipLayerMovesUp() = pipLayerMoves(Direction.UP)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
index 429774f890a5..04016a93e53d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
@@ -17,11 +17,13 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -33,6 +35,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.changeAspectRatio(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index a4df69fc6539..6bcaabc3b680 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -18,11 +18,13 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -35,6 +37,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class PipDragTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private var isDraggedLeft: Boolean = true
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index cbd4a528474a..d82bfdd6dc2f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -17,16 +17,18 @@
package com.android.wm.shell.flicker.pip
import android.graphics.Rect
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.flicker.rules.RemoveAllTasksButHomeRule
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -40,6 +42,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
// represents the direction in which the pip window should be snapping
private var willSnapRight: Boolean = true
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 16d08e5e9055..dbc97d072f9b 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -17,13 +17,15 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.flicker.subject.exceptions.IncorrectRegionException
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -36,6 +38,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index 578a9b536289..9d46ac1d6e00 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -17,8 +17,11 @@
package com.android.wm.shell.flicker.pip
import android.app.Activity
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.Rotation
import android.tools.flicker.assertions.FlickerTest
import android.tools.flicker.junit.FlickerParametersRunnerFactory
@@ -26,10 +29,9 @@ import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.helpers.WindowUtils
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import org.junit.Assume
@@ -48,6 +50,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
open class SetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index c6cf3411835c..e72251fb7a31 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.assertions.FlickerTest
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
@@ -25,6 +26,7 @@ import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -58,6 +60,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
class ShowPipAndRotateDisplay(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index bc2bfdbe1df1..c37bf3579e93 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -20,6 +20,7 @@ import android.app.Instrumentation
import android.content.Intent
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.tools.Rotation
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
@@ -31,9 +32,14 @@ import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.wm.shell.flicker.BaseTest
import com.google.common.truth.Truth
+import org.junit.Rule
import org.junit.Test
abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+ @JvmField
+ @Rule
+ val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
protected val pipApp = PipAppHelper(instrumentation)
protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
index f9706969ff11..8c2bdad364fc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
@@ -17,7 +17,11 @@
package com.android.wm.shell.flicker.utils
object MediaProjectionUtils {
- const val REQUEST_CODE: Int = 99
+ // Request code for the normal media projection request
+ const val REQUEST_CODE_NORMAL: Int = 11
+ // Request code for the media projection request which will include an extra intent to open
+ // home screen before starting requested app
+ const val REQUEST_CODE_EXTRA_INTENT: Int = 12
const val MSG_START_FOREGROUND_DONE: Int = 1
const val MSG_SERVICE_DESTROYED: Int = 2
const val EXTRA_MESSENGER: String = "messenger"
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
index f935ac76bbeb..310c2d725c09 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.mock;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Point;
import android.graphics.Rect;
@@ -42,9 +43,12 @@ public final class TestRunningTaskInfoBuilder {
private int mParentTaskId = INVALID_TASK_ID;
private int mUid = INVALID_TASK_ID;
private int mTaskId = INVALID_TASK_ID;
+ private int mUserId = -1;
private Intent mBaseIntent = new Intent();
+ private ComponentName mBaseActivity = null;
private @WindowConfiguration.ActivityType int mActivityType = ACTIVITY_TYPE_STANDARD;
private @WindowConfiguration.WindowingMode int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ private @WindowConfiguration.ActivityType int mTopActivityType = ACTIVITY_TYPE_STANDARD;
private int mDisplayId = Display.DEFAULT_DISPLAY;
private ActivityManager.TaskDescription.Builder mTaskDescriptionBuilder = null;
private final Point mPositionInParent = new Point();
@@ -87,6 +91,12 @@ public final class TestRunningTaskInfoBuilder {
return this;
}
+ /** Sets the task info's user id. */
+ public TestRunningTaskInfoBuilder setUserId(int userId) {
+ mUserId = userId;
+ return this;
+ }
+
/**
* Set {@link ActivityManager.RunningTaskInfo#baseIntent} for the task info, by default
* an empty intent is assigned
@@ -96,12 +106,26 @@ public final class TestRunningTaskInfoBuilder {
return this;
}
+ /**
+ * Set {@link ActivityManager.RunningTaskInfo#baseActivity} for the task info.
+ */
+ public TestRunningTaskInfoBuilder setBaseActivity(@NonNull ComponentName activity) {
+ mBaseActivity = activity;
+ return this;
+ }
+
public TestRunningTaskInfoBuilder setActivityType(
@WindowConfiguration.ActivityType int activityType) {
mActivityType = activityType;
return this;
}
+ public TestRunningTaskInfoBuilder setTopActivityType(
+ @WindowConfiguration.ActivityType int activityType) {
+ mTopActivityType = activityType;
+ return this;
+ }
+
public TestRunningTaskInfoBuilder setWindowingMode(
@WindowConfiguration.WindowingMode int windowingMode) {
mWindowingMode = windowingMode;
@@ -154,6 +178,7 @@ public final class TestRunningTaskInfoBuilder {
info.configuration.windowConfiguration.setBounds(mBounds);
info.configuration.windowConfiguration.setActivityType(mActivityType);
info.configuration.windowConfiguration.setWindowingMode(mWindowingMode);
+ info.topActivityType = mTopActivityType;
info.token = mToken;
info.isResizeable = true;
info.supportsMultiWindow = true;
@@ -164,6 +189,8 @@ public final class TestRunningTaskInfoBuilder {
info.isTopActivityTransparent = mIsTopActivityTransparent;
info.numActivities = mNumActivities;
info.lastActiveTime = mLastActiveTime;
+ info.userId = mUserId;
+ info.baseActivity = mBaseActivity;
return info;
}
}
diff --git a/core/java/android/content/pm/verify/pkg/IVerifierService.aidl b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt
index d3071fd67b9d..528ca7e94ee3 100644
--- a/core/java/android/content/pm/verify/pkg/IVerifierService.aidl
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt
@@ -13,19 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.wm.shell
-package android.content.pm.verify.pkg;
-
-import android.content.pm.verify.pkg.VerificationSession;
+import com.android.wm.shell.common.ShellExecutor
/**
- * Oneway interface that allows the system to communicate to the verifier service agent.
- * @hide
+ * Test ShellExecutor that runs everything synchronously.
*/
-oneway interface IVerifierService {
- void onPackageNameAvailable(in String packageName);
- void onVerificationCancelled(in String packageName);
- void onVerificationRequired(in VerificationSession session);
- void onVerificationRetry(in VerificationSession session);
- void onVerificationTimeout(int verificationId);
-} \ No newline at end of file
+class TestSyncExecutor : ShellExecutor {
+ override fun execute(runnable: Runnable) {
+ runnable.run()
+ }
+
+ override fun executeDelayed(runnable: Runnable, delayMillis: Long) {
+ runnable.run()
+ }
+
+ override fun removeCallbacks(runnable: Runnable) {
+ }
+
+ override fun hasCallback(runnable: Runnable): Boolean {
+ return false
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 13a8518ae8ed..c3e396524da1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -57,6 +57,8 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContentResolver;
@@ -91,6 +93,7 @@ import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -140,6 +143,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
@Mock
private Handler mHandler;
+ @Mock
+ private Transitions.TransitionHandler mTakeoverHandler;
private BackAnimationController mController;
private TestableContentResolver mContentResolver;
@@ -152,6 +157,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
private BackAnimationController.BackTransitionHandler mBackTransitionHandler;
+ @Rule
+ public SetFlagsRule mSetflagsRule = new SetFlagsRule();
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -605,6 +613,51 @@ public class BackAnimationControllerTest extends ShellTestCase {
verify(mAnimatorCallback, never()).onBackInvoked();
}
+ @EnableFlags({com.android.systemui.shared.Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ com.android.systemui.shared.Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ com.android.window.flags.Flags.FLAG_UNIFY_BACK_NAVIGATION_TRANSITION})
+ @Test
+ public void appCallback_receivesTakeoverHandler_whenAvailable() throws RemoteException {
+ registerAnimation(BackNavigationInfo.TYPE_CROSS_TASK);
+ mBackTransitionHandler.mTakeoverHandler = mTakeoverHandler;
+
+ final int type = BackNavigationInfo.TYPE_CALLBACK;
+ final ResultListener result = new ResultListener();
+ createNavigationInfo(new BackNavigationInfo.Builder()
+ .setType(type)
+ .setOnBackInvokedCallback(mAppCallback)
+ .setOnBackNavigationDone(new RemoteCallback(result))
+ .setTouchableRegion(mTouchableRegion)
+ .setAppProgressAllowed(true));
+
+ triggerBackGesture();
+ mShellExecutor.flushAll();
+ releaseBackGesture();
+ mShellExecutor.flushAll();
+
+ verify(mAppCallback).setHandoffHandler(any());
+ }
+
+ @Test
+ public void appCallback_doesNotReceiveTakeoverHandler_whenUnavailable() throws RemoteException {
+ registerAnimation(BackNavigationInfo.TYPE_CROSS_TASK);
+
+ final int type = BackNavigationInfo.TYPE_CALLBACK;
+ final ResultListener result = new ResultListener();
+ createNavigationInfo(new BackNavigationInfo.Builder()
+ .setType(type)
+ .setOnBackInvokedCallback(mAppCallback)
+ .setOnBackNavigationDone(new RemoteCallback(result))
+ .setTouchableRegion(mTouchableRegion)
+ .setAppProgressAllowed(true));
+ triggerBackGesture();
+ mShellExecutor.flushAll();
+ releaseBackGesture();
+ mShellExecutor.flushAll();
+
+ verify(mAppCallback, never()).setHandoffHandler(any());
+ }
+
@Test
public void skipsCancelWithoutStart() throws RemoteException {
final int type = BackNavigationInfo.TYPE_CALLBACK;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
index 2ed7d07ac75e..bf54e79119bf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
@@ -63,6 +63,7 @@ public class BackProgressAnimatorTest {
@Before
public void setUp() throws Exception {
mTargetProgressCalled = new CountDownLatch(1);
+ mTargetProgress = 0.5f;
mMainThreadHandler = new Handler(Looper.getMainLooper());
final BackMotionEvent backEvent = backMotionEventFrom(0, 0);
mMainThreadHandler.post(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 6fa37885b724..ce640b5e5195 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -47,6 +47,7 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.bubbles.BubbleData.TimeSource;
import com.android.wm.shell.common.ShellExecutor;
@@ -102,6 +103,7 @@ public class BubbleDataTest extends ShellTestCase {
private BubbleData mBubbleData;
private TestableBubblePositioner mPositioner;
+ private UiEventLoggerFake mUiEventLogger;
@Mock
private TimeSource mTimeSource;
@@ -112,8 +114,6 @@ public class BubbleDataTest extends ShellTestCase {
@Mock
private PendingIntent mDeleteIntent;
@Mock
- private BubbleLogger mBubbleLogger;
- @Mock
private BubbleEducationController mEducationController;
@Mock
private ShellExecutor mMainExecutor;
@@ -196,10 +196,12 @@ public class BubbleDataTest extends ShellTestCase {
mock(Icon.class),
mMainExecutor, mBgExecutor);
+ mUiEventLogger = new UiEventLoggerFake();
+
mPositioner = new TestableBubblePositioner(mContext,
mContext.getSystemService(WindowManager.class));
- mBubbleData = new BubbleData(getContext(), mBubbleLogger, mPositioner, mEducationController,
- mMainExecutor, mBgExecutor);
+ mBubbleData = new BubbleData(getContext(), new BubbleLogger(mUiEventLogger), mPositioner,
+ mEducationController, mMainExecutor, mBgExecutor);
// Used by BubbleData to set lastAccessedTime
when(mTimeSource.currentTimeMillis()).thenReturn(1000L);
@@ -297,6 +299,82 @@ public class BubbleDataTest extends ShellTestCase {
}
@Test
+ public void testRemoveBubbleFromBubbleBar_notifCancelled_logEvent() {
+ mPositioner.setShowingInBubbleBar(true);
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
+ assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+ assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+ BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_CANCELED.getId());
+ }
+
+ @Test
+ public void testRemoveBubbleFromBubbleBar_taskFinished_logEvent() {
+ mPositioner.setShowingInBubbleBar(true);
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+ assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+ assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+ BubbleLogger.Event.BUBBLE_BAR_BUBBLE_ACTIVITY_FINISH.getId());
+ }
+
+ @Test
+ public void testRemoveBubbleFromBubbleBar_notifBlocked_logEvent() {
+ mPositioner.setShowingInBubbleBar(true);
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_BLOCKED);
+ assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+ assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+ BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED.getId());
+ }
+
+ @Test
+ public void testRemoveBubbleFromBubbleBar_noLongerBubble_logEvent() {
+ mPositioner.setShowingInBubbleBar(true);
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE);
+ assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+ assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+ BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED.getId());
+ }
+
+ @Test
+ public void testRemoveBubbleFromBubbleBar_addToOverflow_logEvent() {
+ mPositioner.setShowingInBubbleBar(true);
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_AGED);
+ assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+ assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+ BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_ADD_AGED.getId());
+ }
+
+ @Test
+ public void testRemoveBubble_notifCancelled_noLog() {
+ mPositioner.setShowingInBubbleBar(false);
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_BLOCKED);
+ assertThat(mUiEventLogger.numLogs()).isEqualTo(0);
+ }
+
+ @Test
public void ifSuppress_hideFlyout() {
// Setup
mBubbleData.setListener(mListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
index 803e5d4442a9..1d390007d470 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
@@ -21,7 +21,7 @@ import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt
new file mode 100644
index 000000000000..75025d9064d3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.annotation.ColorRes
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
+import com.android.internal.R
+import com.android.wm.shell.ShellTestCase
+import java.util.function.Consumer
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+
+/**
+ * Tests for [LetterboxConfiguration].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:LetterboxConfigurationTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LetterboxConfigurationTest : ShellTestCase() {
+
+ companion object {
+ @JvmStatic
+ val COLOR_WHITE = Color.valueOf(Color.WHITE)
+ @JvmStatic
+ val COLOR_RED = Color.valueOf(Color.RED)
+ @JvmStatic
+ val COLOR_BLACK = Color.valueOf(Color.BLACK)
+ @JvmStatic
+ val COLOR_WHITE_RESOURCE_ID = android.R.color.white
+ @JvmStatic
+ val COLOR_BLACK_RESOURCE_ID = android.R.color.black
+ }
+
+ @Test
+ fun `default background color is used if override is not set`() {
+ runTestScenario { r ->
+ r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+ r.loadConfiguration()
+ r.checkBackgroundColor(COLOR_WHITE)
+ }
+ }
+
+ @Test
+ fun `overridden background color is used if set`() {
+ runTestScenario { r ->
+ r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+ r.loadConfiguration()
+ r.overrideBackgroundColor(COLOR_RED)
+ r.checkBackgroundColor(COLOR_RED)
+ }
+ }
+
+ @Test
+ fun `overridden background color resource is used if set without override`() {
+ runTestScenario { r ->
+ r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+ r.loadConfiguration()
+ r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID)
+ r.checkBackgroundColor(COLOR_BLACK)
+ }
+ }
+
+ @Test
+ fun `overridden background color has precedence over color id`() {
+ runTestScenario { r ->
+ r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+ r.loadConfiguration()
+ r.overrideBackgroundColor(COLOR_RED)
+ r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID)
+ r.checkBackgroundColor(COLOR_RED)
+ }
+ }
+
+ @Test
+ fun `reset background color`() {
+ runTestScenario { r ->
+ r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+ r.loadConfiguration()
+ r.overrideBackgroundColor(COLOR_RED)
+ r.checkBackgroundColor(COLOR_RED)
+
+ r.resetBackgroundColor()
+ r.checkBackgroundColor(COLOR_WHITE)
+
+ r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID)
+ r.checkBackgroundColor(COLOR_BLACK)
+
+ r.resetBackgroundColor()
+ r.checkBackgroundColor(COLOR_WHITE)
+ }
+ }
+
+ /**
+ * Runs a test scenario providing a Robot.
+ */
+ fun runTestScenario(consumer: Consumer<LetterboxConfigurationRobotTest>) {
+ val robot = LetterboxConfigurationRobotTest(mContext)
+ consumer.accept(robot)
+ }
+
+ class LetterboxConfigurationRobotTest(private val ctx: Context) {
+
+ private val resources: Resources
+ private lateinit var letterboxConfig: LetterboxConfiguration
+
+ init {
+ resources = ctx.resources
+ spyOn(resources)
+ }
+
+ fun setDefaultBackgroundColorId(@ColorRes colorId: Int) {
+ doReturn(colorId).`when`(resources)
+ .getColor(R.color.config_letterboxBackgroundColor, null)
+ }
+
+ fun loadConfiguration() {
+ letterboxConfig = LetterboxConfiguration(ctx)
+ }
+
+ fun overrideBackgroundColor(color: Color) {
+ letterboxConfig.setLetterboxBackgroundColor(color)
+ }
+
+ fun resetBackgroundColor() {
+ letterboxConfig.resetLetterboxBackgroundColor()
+ }
+
+ fun overrideBackgroundColorId(@ColorRes colorId: Int) {
+ letterboxConfig.setLetterboxBackgroundColorResourceId(colorId)
+ }
+
+ fun checkBackgroundColor(expected: Color) {
+ val colorComponents = letterboxConfig.getBackgroundColorRgbArray()
+ val expectedComponents = expected.components
+ assert(expectedComponents.contentEquals(colorComponents))
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt
new file mode 100644
index 000000000000..1ae1c3fc4563
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import android.view.WindowManager.TRANSIT_CLOSE
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.util.TransitionObserverInputBuilder
+import com.android.wm.shell.util.executeTransitionObserverTest
+import java.util.function.Consumer
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.times
+import org.mockito.kotlin.anyOrNull
+import org.mockito.verification.VerificationMode
+
+/**
+ * Tests for [LetterboxTransitionObserver].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:LetterboxTransitionObserverTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LetterboxTransitionObserverTest : ShellTestCase() {
+
+ @get:Rule
+ val setFlagsRule: SetFlagsRule = SetFlagsRule()
+
+ @Test
+ @DisableFlags(Flags.FLAG_APP_COMPAT_REFACTORING)
+ fun `when initialized and flag disabled the observer is not registered`() {
+ runTestScenario { r ->
+ executeTransitionObserverTest(observerFactory = r.observerFactory) {
+ r.invokeShellInit()
+ r.checkObservableIsRegistered(expected = false)
+ }
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_APP_COMPAT_REFACTORING)
+ fun `when initialized and flag enabled the observer is registered`() {
+ runTestScenario { r ->
+ executeTransitionObserverTest(observerFactory = r.observerFactory) {
+ r.invokeShellInit()
+ r.checkObservableIsRegistered(expected = true)
+ }
+ }
+ }
+
+ @Test
+ fun `LetterboxController not used without TaskInfos in Change`() {
+ runTestScenario { r ->
+ executeTransitionObserverTest(observerFactory = r.observerFactory) {
+ r.invokeShellInit()
+
+ inputBuilder {
+ buildTransitionInfo()
+ addChange(createChange())
+ addChange(createChange())
+ addChange(createChange())
+ }
+
+ validateOutput {
+ r.creationEventDetected(expected = false)
+ r.visibilityEventDetected(expected = false)
+ r.destroyEventDetected(expected = false)
+ r.boundsEventDetected(expected = false)
+ }
+ }
+ }
+ }
+
+ @Test
+ fun `When a topActivity is letterboxed surfaces creation is requested`() {
+ runTestScenario { r ->
+ executeTransitionObserverTest(observerFactory = r.observerFactory) {
+ r.invokeShellInit()
+
+ inputBuilder {
+ buildTransitionInfo()
+ r.createTopActivityChange(inputBuilder = this, isLetterboxed = true)
+ }
+
+ validateOutput {
+ r.creationEventDetected(expected = true)
+ r.visibilityEventDetected(expected = true, visible = true)
+ r.destroyEventDetected(expected = false)
+ r.boundsEventDetected(expected = true)
+ }
+ }
+ }
+ }
+
+ @Test
+ fun `When a topActivity is not letterboxed visibility is updated`() {
+ runTestScenario { r ->
+ executeTransitionObserverTest(observerFactory = r.observerFactory) {
+ r.invokeShellInit()
+
+ inputBuilder {
+ buildTransitionInfo()
+ r.createTopActivityChange(inputBuilder = this, isLetterboxed = false)
+ }
+
+ validateOutput {
+ r.creationEventDetected(expected = false)
+ r.visibilityEventDetected(expected = true, visible = false)
+ r.destroyEventDetected(expected = false)
+ r.boundsEventDetected(expected = false)
+ }
+ }
+ }
+ }
+
+ @Test
+ fun `When closing change letterbox surface destroy is triggered`() {
+ runTestScenario { r ->
+ executeTransitionObserverTest(observerFactory = r.observerFactory) {
+ r.invokeShellInit()
+
+ inputBuilder {
+ buildTransitionInfo()
+ r.createClosingChange(inputBuilder = this)
+ }
+
+ validateOutput {
+ r.destroyEventDetected(expected = true)
+ r.creationEventDetected(expected = false)
+ r.visibilityEventDetected(expected = false, visible = false)
+ r.boundsEventDetected(expected = false)
+ }
+ }
+ }
+ }
+
+ /**
+ * Runs a test scenario providing a Robot.
+ */
+ fun runTestScenario(consumer: Consumer<LetterboxTransitionObserverRobotTest>) {
+ val robot = LetterboxTransitionObserverRobotTest()
+ consumer.accept(robot)
+ }
+
+ class LetterboxTransitionObserverRobotTest {
+
+ companion object {
+ @JvmStatic
+ private val DISPLAY_ID = 1
+
+ @JvmStatic
+ private val TASK_ID = 20
+ }
+
+ private val executor: ShellExecutor
+ private val shellInit: ShellInit
+ private val transitions: Transitions
+ private val letterboxController: LetterboxController
+ private val letterboxObserver: LetterboxTransitionObserver
+
+ val observerFactory: () -> LetterboxTransitionObserver
+
+ init {
+ executor = Mockito.mock(ShellExecutor::class.java)
+ shellInit = ShellInit(executor)
+ transitions = Mockito.mock(Transitions::class.java)
+ letterboxController = Mockito.mock(LetterboxController::class.java)
+ letterboxObserver =
+ LetterboxTransitionObserver(shellInit, transitions, letterboxController)
+ observerFactory = { letterboxObserver }
+ }
+
+ fun invokeShellInit() = shellInit.init()
+
+ fun observer() = letterboxObserver
+
+ fun checkObservableIsRegistered(expected: Boolean) {
+ Mockito.verify(transitions, expected.asMode()).registerObserver(observer())
+ }
+
+ fun creationEventDetected(
+ expected: Boolean,
+ displayId: Int = DISPLAY_ID,
+ taskId: Int = TASK_ID
+ ) {
+ Mockito.verify(letterboxController, expected.asMode()).createLetterboxSurface(
+ toLetterboxKeyMatcher(displayId, taskId),
+ anyOrNull(),
+ anyOrNull()
+ )
+ }
+
+ fun visibilityEventDetected(
+ expected: Boolean,
+ displayId: Int = DISPLAY_ID,
+ taskId: Int = TASK_ID,
+ visible: Boolean? = null
+ ) {
+ Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceVisibility(
+ toLetterboxKeyMatcher(displayId, taskId),
+ anyOrNull(),
+ visible.asMatcher()
+ )
+ }
+
+ fun destroyEventDetected(
+ expected: Boolean,
+ displayId: Int = DISPLAY_ID,
+ taskId: Int = TASK_ID
+ ) {
+ Mockito.verify(letterboxController, expected.asMode()).destroyLetterboxSurface(
+ toLetterboxKeyMatcher(displayId, taskId),
+ anyOrNull()
+ )
+ }
+
+ fun boundsEventDetected(
+ expected: Boolean,
+ displayId: Int = DISPLAY_ID,
+ taskId: Int = TASK_ID
+ ) {
+ Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceBounds(
+ toLetterboxKeyMatcher(displayId, taskId),
+ anyOrNull(),
+ anyOrNull()
+ )
+ }
+
+ fun createTopActivityChange(
+ inputBuilder: TransitionObserverInputBuilder,
+ isLetterboxed: Boolean = true,
+ displayId: Int = DISPLAY_ID,
+ taskId: Int = TASK_ID
+ ) {
+ inputBuilder.addChange(changeTaskInfo = inputBuilder.createTaskInfo().apply {
+ appCompatTaskInfo.isTopActivityLetterboxed = isLetterboxed
+ this.taskId = taskId
+ this.displayId = displayId
+ })
+ }
+
+ fun createClosingChange(
+ inputBuilder: TransitionObserverInputBuilder,
+ displayId: Int = DISPLAY_ID,
+ taskId: Int = TASK_ID
+ ) {
+ inputBuilder.addChange(changeTaskInfo = inputBuilder.createTaskInfo().apply {
+ this.taskId = taskId
+ this.displayId = displayId
+ }, changeMode = TRANSIT_CLOSE)
+ }
+
+ private fun Boolean.asMode(): VerificationMode = if (this) times(1) else never()
+
+ private fun Boolean?.asMatcher(): Boolean =
+ if (this != null) eq(this) else any()
+
+ private fun toLetterboxKeyMatcher(displayId: Int, taskId: Int): LetterboxKey {
+ if (displayId < 0 || taskId < 0) {
+ return any()
+ } else {
+ return eq(LetterboxKey(displayId, taskId))
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
index aabd973fce90..2ea0379e3bf7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
@@ -39,8 +39,8 @@ import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.TaskStackListenerImpl
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
import com.android.wm.shell.desktopmode.persistence.Desktop
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
index a4f4d05d2079..b57c55c4c45a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
@@ -42,7 +42,8 @@ import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitReason.USER_INTERACTION
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.util.StubTransaction
@@ -168,7 +169,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.moveTaskToNonImmersive(task)
+ controller.moveTaskToNonImmersive(task, USER_INTERACTION)
controller.onTransitionReady(
transition = mockBinder,
info = createTransitionInfo(
@@ -195,7 +196,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
)
desktopRepository.saveBoundsBeforeFullImmersive(task.taskId, Rect(100, 100, 600, 600))
- controller.moveTaskToNonImmersive(task)
+ controller.moveTaskToNonImmersive(task, USER_INTERACTION)
controller.onTransitionReady(
transition = mockBinder,
info = createTransitionInfo(
@@ -252,8 +253,8 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
whenever(mockTransitions.startTransition(eq(TRANSIT_CHANGE), any(), eq(controller)))
.thenReturn(mockBinder)
- controller.moveTaskToNonImmersive(task)
- controller.moveTaskToNonImmersive(task)
+ controller.moveTaskToNonImmersive(task, USER_INTERACTION)
+ controller.moveTaskToNonImmersive(task, USER_INTERACTION)
verify(mockTransitions, times(1))
.startTransition(eq(TRANSIT_CHANGE), any(), eq(controller))
@@ -272,7 +273,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
assertThat(controller.pendingExternalExitTransitions.any { exit ->
exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
@@ -293,7 +294,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = false
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
assertThat(controller.pendingExternalExitTransitions.any { exit ->
exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
@@ -314,7 +315,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
assertThat(wct.hasBoundsChange(task.token)).isTrue()
}
@@ -332,7 +333,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = false
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
assertThat(wct.hasBoundsChange(task.token)).isFalse()
}
@@ -353,7 +354,8 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
controller.exitImmersiveIfApplicable(
wct = wct,
displayId = DEFAULT_DISPLAY,
- excludeTaskId = task.taskId
+ excludeTaskId = task.taskId,
+ reason = USER_INTERACTION,
).asExit()?.runOnTransitionStart?.invoke(transition)
assertThat(controller.pendingExternalExitTransitions.any { exit ->
@@ -374,7 +376,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task)
+ controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task, reason = USER_INTERACTION)
assertThat(wct.hasBoundsChange(task.token)).isTrue()
}
@@ -391,7 +393,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = false
)
- controller.exitImmersiveIfApplicable(wct, task)
+ controller.exitImmersiveIfApplicable(wct, task, USER_INTERACTION)
assertThat(wct.hasBoundsChange(task.token)).isFalse()
}
@@ -409,7 +411,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(wct, task)
+ controller.exitImmersiveIfApplicable(wct, task, USER_INTERACTION)
.asExit()?.runOnTransitionStart?.invoke(transition)
assertThat(controller.pendingExternalExitTransitions.any { exit ->
@@ -430,7 +432,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = false
)
- val result = controller.exitImmersiveIfApplicable(wct, task)
+ val result = controller.exitImmersiveIfApplicable(wct, task, USER_INTERACTION)
assertThat(result).isEqualTo(DesktopImmersiveController.ExitResult.NoExit)
}
@@ -447,7 +449,8 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = false
)
- val result = controller.exitImmersiveIfApplicable(wct, task.displayId)
+ val result = controller.exitImmersiveIfApplicable(
+ wct, task.displayId, excludeTaskId = null, USER_INTERACTION)
assertThat(result).isEqualTo(DesktopImmersiveController.ExitResult.NoExit)
}
@@ -464,7 +467,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
taskId = task.taskId,
immersive = true
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
controller.onTransitionReady(
transition = transition,
@@ -495,7 +498,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
taskId = task.taskId,
immersive = true
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
controller.onTransitionReady(
transition = transition,
@@ -530,7 +533,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
taskId = task.taskId,
immersive = true
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
controller.onTransitionReady(
transition = transition,
@@ -560,7 +563,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
desktopRepository.saveBoundsBeforeFullImmersive(task.taskId, Rect(100, 100, 600, 600))
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
controller.onTransitionReady(
transition = transition,
@@ -587,7 +590,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task)
+ controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task, reason = USER_INTERACTION)
assertThat(
wct.hasBoundsChange(task.token, calculateMaximizeBounds(mockDisplayLayout, task))
@@ -611,7 +614,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
val preImmersiveBounds = Rect(100, 100, 500, 500)
desktopRepository.saveBoundsBeforeFullImmersive(task.taskId, preImmersiveBounds)
- controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task)
+ controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task, reason = USER_INTERACTION)
assertThat(
wct.hasBoundsChange(task.token, preImmersiveBounds)
@@ -634,7 +637,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task)
+ controller.exitImmersiveIfApplicable(wct = wct, taskInfo = task, reason = USER_INTERACTION)
assertThat(
wct.hasBoundsChange(task.token, calculateInitialBounds(mockDisplayLayout, task))
@@ -652,10 +655,10 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
taskId = task.taskId,
immersive = true
)
- controller.exitImmersiveIfApplicable(wct, task)
+ controller.exitImmersiveIfApplicable(wct, task, USER_INTERACTION)
.asExit()?.runOnTransitionStart?.invoke(Binder())
- controller.moveTaskToNonImmersive(task)
+ controller.moveTaskToNonImmersive(task, USER_INTERACTION)
verify(mockTransitions, never()).startTransition(any(), any(), any())
}
@@ -674,7 +677,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+ controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION)
assertThat(controller.isImmersiveChange(transition, change)).isTrue()
}
@@ -692,7 +695,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.moveTaskToNonImmersive(task)
+ controller.moveTaskToNonImmersive(task, USER_INTERACTION)
controller.animateResizeChange(
change = TransitionInfo.Change(task.token, SurfaceControl()).apply {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
index f21f26443748..62717a32d99f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
@@ -31,6 +31,8 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.SurfaceControl
import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_BACK
import android.view.WindowManager.TransitionType
@@ -47,6 +49,7 @@ import com.android.wm.shell.desktopmode.DesktopMixedTransitionHandler.PendingMix
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.util.StubTransaction
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
@@ -491,6 +494,72 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startLaunchTransition_unknownLaunchingTask_animates() {
+ val wct = WindowContainerTransaction()
+ val task = createTask(WINDOWING_MODE_FREEFORM)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+ whenever(transitions.dispatchTransition(eq(transition), any(), any(), any(), any(), any()))
+ .thenReturn(mock())
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = null,
+ )
+
+ val started = mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(createChange(task, mode = TRANSIT_OPEN))
+ ),
+ StubTransaction(),
+ StubTransaction(),
+ ) { }
+
+ assertThat(started).isEqualTo(true)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startLaunchTransition_unknownLaunchingTaskOverImmersive_animatesImmersiveChange() {
+ val wct = WindowContainerTransaction()
+ val immersiveTask = createTask(WINDOWING_MODE_FREEFORM)
+ val openingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+ whenever(transitions.dispatchTransition(eq(transition), any(), any(), any(), any(), any()))
+ .thenReturn(mock())
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = null,
+ exitingImmersiveTask = immersiveTask.taskId,
+ )
+
+ val immersiveChange = createChange(immersiveTask, mode = TRANSIT_CHANGE)
+ val openingChange = createChange(openingTask, mode = TRANSIT_OPEN)
+ val started = mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(immersiveChange, openingChange)
+ ),
+ StubTransaction(),
+ StubTransaction(),
+ ) { }
+
+ assertThat(started).isEqualTo(true)
+ verify(desktopImmersiveController)
+ .animateResizeChange(eq(immersiveChange), any(), any(), any())
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() {
val wct = WindowContainerTransaction()
@@ -712,9 +781,13 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
changes.forEach { change -> addChange(change) }
}
- private fun createChange(task: RunningTaskInfo): TransitionInfo.Change =
+ private fun createChange(
+ task: RunningTaskInfo,
+ @TransitionInfo.TransitionMode mode: Int = TRANSIT_NONE
+ ): TransitionInfo.Change =
TransitionInfo.Change(task.token, SurfaceControl()).apply {
taskInfo = task
+ setMode(mode)
}
private fun createTask(@WindowingMode windowingMode: Int): RunningTaskInfo =
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
index 2a82e6e4f7b8..2f225f22cce0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
@@ -487,7 +487,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() {
@Test
fun logTaskResizingStarted_noOngoingSession_doesNotLog() {
desktopModeEventLogger.logTaskResizingStarted(ResizeTrigger.CORNER,
- null, createTaskInfo())
+ InputMethod.UNKNOWN_INPUT_METHOD, createTaskInfo())
verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
@@ -499,7 +499,8 @@ class DesktopModeEventLoggerTest : ShellTestCase() {
val sessionId = startDesktopModeSession()
desktopModeEventLogger.logTaskResizingStarted(ResizeTrigger.CORNER,
- null, createTaskInfo(), displayController)
+ InputMethod.UNKNOWN_INPUT_METHOD, createTaskInfo(), TASK_SIZE_UPDATE.taskWidth,
+ TASK_SIZE_UPDATE.taskHeight, displayController)
verify {
FrameworkStatsLog.write(
@@ -516,10 +517,10 @@ class DesktopModeEventLoggerTest : ShellTestCase() {
eq(TASK_SIZE_UPDATE.instanceId),
/* uid */
eq(TASK_SIZE_UPDATE.uid),
- /* task_height */
- eq(TASK_SIZE_UPDATE.taskHeight),
/* task_width */
eq(TASK_SIZE_UPDATE.taskWidth),
+ /* task_height */
+ eq(TASK_SIZE_UPDATE.taskHeight),
/* display_area */
eq(DISPLAY_AREA),
)
@@ -530,7 +531,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() {
@Test
fun logTaskResizingEnded_noOngoingSession_doesNotLog() {
desktopModeEventLogger.logTaskResizingEnded(ResizeTrigger.CORNER,
- null, createTaskInfo())
+ InputMethod.UNKNOWN_INPUT_METHOD, createTaskInfo())
verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
@@ -542,7 +543,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() {
val sessionId = startDesktopModeSession()
desktopModeEventLogger.logTaskResizingEnded(ResizeTrigger.CORNER,
- null, createTaskInfo(), displayController = displayController)
+ InputMethod.UNKNOWN_INPUT_METHOD, createTaskInfo(), displayController = displayController)
verify {
FrameworkStatsLog.write(
@@ -559,10 +560,10 @@ class DesktopModeEventLoggerTest : ShellTestCase() {
eq(TASK_SIZE_UPDATE.instanceId),
/* uid */
eq(TASK_SIZE_UPDATE.uid),
- /* task_height */
- eq(TASK_SIZE_UPDATE.taskHeight),
/* task_width */
eq(TASK_SIZE_UPDATE.taskWidth),
+ /* task_height */
+ eq(TASK_SIZE_UPDATE.taskHeight),
/* display_area */
eq(DISPLAY_AREA),
)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
new file mode 100644
index 000000000000..887bdc259f54
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.content.pm.ActivityInfo
+import android.graphics.Rect
+import android.hardware.input.InputManager
+import android.hardware.input.InputManager.KeyGestureEventHandler
+import android.hardware.input.KeyGestureEvent
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.KeyEvent
+import android.window.DisplayAreaInfo
+import androidx.test.filters.SmallTest
+import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
+import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS
+import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT
+import com.android.wm.shell.MockToken
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.transition.FocusTransitionObserver
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.whenever
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
+import java.util.Optional
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.quality.Strictness
+
+/**
+ * Test class for [DesktopModeKeyGestureHandler]
+ *
+ * Usage: atest WMShellUnitTests:DesktopModeKeyGestureHandlerTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@ExperimentalCoroutinesApi
+@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
+
+ @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+ private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>()
+ private val shellTaskOrganizer = mock<ShellTaskOrganizer>()
+ private val focusTransitionObserver = mock<FocusTransitionObserver>()
+ private val testExecutor = mock<ShellExecutor>()
+ private val inputManager = mock<InputManager>()
+ private val displayController = mock<DisplayController>()
+ private val displayLayout = mock<DisplayLayout>()
+ private val desktopModeWindowDecorViewModel = mock<DesktopModeWindowDecorViewModel>()
+ private val desktopTasksController = mock<DesktopTasksController>()
+
+ private lateinit var desktopModeKeyGestureHandler: DesktopModeKeyGestureHandler
+ private lateinit var keyGestureEventHandler: KeyGestureEventHandler
+ private lateinit var mockitoSession: StaticMockitoSession
+ private lateinit var testScope: CoroutineScope
+ private lateinit var shellInit: ShellInit
+
+ // Mock running tasks are registered here so we can get the list from mock shell task organizer
+ private val runningTasks = mutableListOf<RunningTaskInfo>()
+
+ @Before
+ fun setUp() {
+ Dispatchers.setMain(StandardTestDispatcher())
+ mockitoSession =
+ mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java)
+ .startMocking()
+ doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+
+ testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
+ shellInit = spy(ShellInit(testExecutor))
+
+ whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
+ whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
+ whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
+ val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+ whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda)
+
+ doAnswer {
+ keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler)
+ null
+ }.whenever(inputManager).registerKeyGestureEventHandler(any())
+ shellInit.init()
+ }
+
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+
+ runningTasks.clear()
+ testScope.cancel()
+ }
+
+ @Test
+ @EnableFlags(
+ FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS,
+ FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
+ FLAG_USE_KEY_GESTURE_EVENT_HANDLER
+ )
+ fun keyGestureMoveToNextDisplay_shouldMoveToNextDisplay() {
+ desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+ context,
+ Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+ inputManager, shellTaskOrganizer, focusTransitionObserver
+ )
+ // Set up two display ids
+ whenever(rootTaskDisplayAreaOrganizer.displayIds)
+ .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
+ // Create a mock for the target display area: default display
+ val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
+ whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .thenReturn(defaultDisplayArea)
+ // Setup a focused task on secondary display, which is expected to move to default display
+ val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
+ task.isFocused = true
+ whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+ whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+ val event = KeyGestureEvent.Builder()
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY)
+ .setDisplayId(SECOND_DISPLAY)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_D))
+ .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
+ .build()
+ val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+ assertThat(result).isTrue()
+ verify(desktopTasksController).moveToNextDisplay(task.taskId)
+ }
+
+ @Test
+ @EnableFlags(
+ FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+ FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+ )
+ fun keyGestureSnapLeft_shouldSnapResizeTaskToLeft() {
+ desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+ context,
+ Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+ inputManager, shellTaskOrganizer, focusTransitionObserver
+ )
+ val task = setUpFreeformTask()
+ task.isFocused = true
+ whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+ whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+ val event = KeyGestureEvent.Builder()
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET))
+ .setModifierState(KeyEvent.META_META_ON)
+ .build()
+ val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+ assertThat(result).isTrue()
+ verify(desktopModeWindowDecorViewModel).onSnapResize(
+ task.taskId, true, DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
+ )
+ }
+
+ @Test
+ @EnableFlags(
+ FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+ FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+ )
+ fun keyGestureSnapRight_shouldSnapResizeTaskToRight() {
+ desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+ context,
+ Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+ inputManager, shellTaskOrganizer, focusTransitionObserver
+ )
+ val task = setUpFreeformTask()
+ task.isFocused = true
+ whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+ whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+ val event = KeyGestureEvent.Builder()
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET))
+ .setModifierState(KeyEvent.META_META_ON)
+ .build()
+ val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+ assertThat(result).isTrue()
+ verify(desktopModeWindowDecorViewModel).onSnapResize(
+ task.taskId, false, DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
+ )
+ }
+
+ @Test
+ @EnableFlags(
+ FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+ FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+ )
+ fun keyGestureToggleFreeformWindowSize_shouldToggleTaskSize() {
+ desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+ context,
+ Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+ inputManager, shellTaskOrganizer, focusTransitionObserver
+ )
+ val task = setUpFreeformTask()
+ task.isFocused = true
+ whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+ whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+ val event = KeyGestureEvent.Builder()
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_EQUALS))
+ .setModifierState(KeyEvent.META_META_ON)
+ .build()
+ val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+ assertThat(result).isTrue()
+ verify(desktopTasksController).toggleDesktopTaskSize(
+ task,
+ ResizeTrigger.MAXIMIZE_MENU,
+ DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
+ )
+ }
+
+ @Test
+ @EnableFlags(
+ FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+ FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+ )
+ fun keyGestureMinimizeFreeformWindow_shouldMinimizeTask() {
+ desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+ context,
+ Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+ inputManager, shellTaskOrganizer, focusTransitionObserver
+ )
+ val task = setUpFreeformTask()
+ task.isFocused = true
+ whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+ whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+ val event = KeyGestureEvent.Builder()
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_MINUS))
+ .setModifierState(KeyEvent.META_META_ON)
+ .build()
+ val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+ assertThat(result).isTrue()
+ verify(desktopTasksController).minimizeTask(task)
+ }
+
+ private fun setUpFreeformTask(
+ displayId: Int = DEFAULT_DISPLAY,
+ bounds: Rect? = null,
+ ): RunningTaskInfo {
+ val task = createFreeformTask(displayId, bounds)
+ val activityInfo = ActivityInfo()
+ task.topActivityInfo = activityInfo
+ whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+ runningTasks.add(task)
+ return task
+ }
+
+ private companion object {
+ const val SECOND_DISPLAY = 2
+ val STABLE_BOUNDS = Rect(0, 0, 1000, 1000)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt
index 51b291c0b7a4..94698e2fc0fb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt
@@ -17,17 +17,22 @@
package com.android.wm.shell.desktopmode
+import android.content.ComponentName
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
-import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.Companion.DesktopUiEventEnum.DESKTOP_WINDOW_EDGE_DRAG_RESIZE
+import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum.DESKTOP_WINDOW_EDGE_DRAG_RESIZE
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
/**
* Test class for [DesktopModeUiEventLogger]
@@ -39,13 +44,13 @@ import org.junit.runner.RunWith
class DesktopModeUiEventLoggerTest : ShellTestCase() {
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var logger: DesktopModeUiEventLogger
- private val instanceIdSequence = InstanceIdSequence(/* instanceIdMax */ 1 shl 20)
+ private val mockPackageManager: PackageManager = mock<PackageManager>()
@Before
fun setUp() {
uiEventLoggerFake = UiEventLoggerFake()
- logger = DesktopModeUiEventLogger(uiEventLoggerFake, instanceIdSequence)
+ logger = DesktopModeUiEventLogger(uiEventLoggerFake, mockPackageManager)
}
@Test
@@ -102,10 +107,28 @@ class DesktopModeUiEventLoggerTest : ShellTestCase() {
assertThat(uiEventLoggerFake[0].packageName).isEqualTo(PACKAGE_NAME)
}
+ @Test
+ fun logWithTaskInfo_eventLogged() {
+ val event =
+ DESKTOP_WINDOW_EDGE_DRAG_RESIZE
+ val taskInfo = TestRunningTaskInfoBuilder()
+ .setUserId(USER_ID)
+ .setBaseActivity(ComponentName(PACKAGE_NAME, "test"))
+ .build()
+ whenever(mockPackageManager.getApplicationInfoAsUser(PACKAGE_NAME, /* flags= */ 0, USER_ID))
+ .thenReturn(ApplicationInfo().apply { uid = UID })
+ logger.log(taskInfo, event)
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(event.id)
+ assertThat(uiEventLoggerFake[0].instanceId).isNull()
+ assertThat(uiEventLoggerFake[0].uid).isEqualTo(UID)
+ assertThat(uiEventLoggerFake[0].packageName).isEqualTo(PACKAGE_NAME)
+ }
companion object {
private val INSTANCE_ID = InstanceId.fakeInstanceId(0)
private const val UID = 10
+ private const val USER_ID = 2
private const val PACKAGE_NAME = "com.foo"
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
index e977966a45fe..8e323acc4e66 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
@@ -23,8 +23,8 @@ import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION
import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
import org.junit.Before
import org.junit.Rule
import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index ad266ead774e..fc31d08b4571 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -36,12 +36,10 @@ import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
import android.content.res.Configuration.ORIENTATION_LANDSCAPE
import android.content.res.Configuration.ORIENTATION_PORTRAIT
+import android.content.res.Resources
import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
-import android.hardware.input.InputManager
-import android.hardware.input.InputManager.KeyGestureEventHandler
-import android.hardware.input.KeyGestureEvent
import android.os.Binder
import android.os.Bundle
import android.os.Handler
@@ -53,7 +51,6 @@ import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
import android.view.DragEvent
import android.view.Gravity
-import android.view.KeyEvent
import android.view.MotionEvent
import android.view.SurfaceControl
import android.view.WindowInsets
@@ -63,6 +60,7 @@ import android.view.WindowManager.TRANSIT_CLOSE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_BACK
import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.widget.Toast
import android.window.DisplayAreaInfo
import android.window.IWindowContainerToken
import android.window.RemoteTransition
@@ -75,18 +73,14 @@ import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_R
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
import android.window.WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID
import androidx.test.filters.SmallTest
-import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer
import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.dx.mockito.inline.extended.ExtendedMockito.never
import com.android.dx.mockito.inline.extended.StaticMockitoSession
-import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER
import com.android.internal.jank.InteractionJankMonitor
import com.android.window.flags.Flags
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
-import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS
import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP
-import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT
import com.android.wm.shell.MockToken
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -96,17 +90,21 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
-import com.android.wm.shell.common.LaunchAdjacentController
import com.android.wm.shell.common.MultiInstanceHelper
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DesktopTasksController.DesktopModeEntryExitTransitionListener
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
import com.android.wm.shell.desktopmode.DesktopTasksController.TaskbarDesktopTaskListener
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createHomeTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createSplitScreenTask
+import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
+import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler
import com.android.wm.shell.desktopmode.persistence.Desktop
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
@@ -116,14 +114,16 @@ import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.recents.RecentTasksController
import com.android.wm.shell.recents.RecentsTransitionHandler
import com.android.wm.shell.recents.RecentsTransitionStateListener
+import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_ANIMATING
+import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.UNKNOWN
import com.android.wm.shell.shared.split.SplitScreenConstants
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
-import com.android.wm.shell.transition.FocusTransitionObserver
import com.android.wm.shell.transition.OneShotRemoteHandler
import com.android.wm.shell.transition.TestRemoteTransition
import com.android.wm.shell.transition.Transitions
@@ -167,6 +167,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.times
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.capture
import org.mockito.kotlin.eq
@@ -206,12 +207,10 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Mock lateinit var dragToDesktopTransitionHandler: DragToDesktopTransitionHandler
@Mock
lateinit var mMockDesktopImmersiveController: DesktopImmersiveController
- @Mock lateinit var launchAdjacentController: LaunchAdjacentController
@Mock lateinit var splitScreenController: SplitScreenController
@Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler
@Mock lateinit var dragAndDropController: DragAndDropController
@Mock lateinit var multiInstanceHelper: MultiInstanceHelper
- @Mock lateinit var desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver
@Mock lateinit var desktopModeVisualIndicator: DesktopModeVisualIndicator
@Mock lateinit var recentTasksController: RecentTasksController
@Mock
@@ -221,24 +220,25 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Mock private lateinit var freeformTaskTransitionStarter: FreeformTaskTransitionStarter
@Mock private lateinit var mockHandler: Handler
@Mock private lateinit var desktopModeEventLogger: DesktopModeEventLogger
+ @Mock private lateinit var desktopModeUiEventLogger: DesktopModeUiEventLogger
@Mock lateinit var persistentRepository: DesktopPersistentRepository
- @Mock private lateinit var mockInputManager: InputManager
- @Mock private lateinit var mockFocusTransitionObserver: FocusTransitionObserver
@Mock lateinit var motionEvent: MotionEvent
@Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
-
+ @Mock private lateinit var mockToast: Toast
private lateinit var mockitoSession: StaticMockitoSession
@Mock
private lateinit var desktopTilingDecorViewModel: DesktopTilingDecorViewModel
@Mock
private lateinit var desktopWindowDecoration: DesktopModeWindowDecoration
+ @Mock private lateinit var resources: Resources
+ @Mock
+ lateinit var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener
private lateinit var controller: DesktopTasksController
private lateinit var shellInit: ShellInit
private lateinit var taskRepository: DesktopRepository
private lateinit var desktopTasksLimiter: DesktopTasksLimiter
private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener
private lateinit var testScope: CoroutineScope
- private lateinit var keyGestureEventHandler: KeyGestureEventHandler
private val shellExecutor = TestShellExecutor()
@@ -261,6 +261,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
mockitoSession()
.strictness(Strictness.LENIENT)
.spyStatic(DesktopModeStatus::class.java)
+ .spyStatic(Toast::class.java)
.startMocking()
doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
@@ -288,25 +289,22 @@ class DesktopTasksControllerTest : ShellTestCase() {
whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn(
Desktop.getDefaultInstance()
)
+ doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda)
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(any(), any<RunningTaskInfo>()))
- .thenReturn(DesktopImmersiveController.ExitResult.NoExit)
+ .exitImmersiveIfApplicable(any(), any<RunningTaskInfo>(), any()))
+ .thenReturn(ExitResult.NoExit)
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull()))
- .thenReturn(DesktopImmersiveController.ExitResult.NoExit)
+ .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull(), any()))
+ .thenReturn(ExitResult.NoExit)
controller = createController()
controller.setSplitScreenController(splitScreenController)
controller.freeformTaskTransitionStarter = freeformTaskTransitionStarter
-
- doAnswer {
- keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler)
- null
- }.whenever(mockInputManager).registerKeyGestureEventHandler(any())
+ controller.desktopModeEnterExitTransitionListener = desktopModeEnterExitTransitionListener
shellInit.init()
@@ -341,8 +339,6 @@ class DesktopTasksControllerTest : ShellTestCase() {
dragToDesktopTransitionHandler,
mMockDesktopImmersiveController,
taskRepository,
- desktopModeLoggerTransitionObserver,
- launchAdjacentController,
recentsTransitionHandler,
multiInstanceHelper,
shellExecutor,
@@ -350,9 +346,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
recentTasksController,
mockInteractionJankMonitor,
mockHandler,
- mockInputManager,
- mockFocusTransitionObserver,
desktopModeEventLogger,
+ desktopModeUiEventLogger,
desktopTilingDecorViewModel,
)
}
@@ -382,15 +377,15 @@ class DesktopTasksControllerTest : ShellTestCase() {
val task1 = setUpFreeformTask()
val argumentCaptor = ArgumentCaptor.forClass(Boolean::class.java)
- controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(argumentCaptor.capture())
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task1,
- STABLE_BOUNDS.height(),
STABLE_BOUNDS.width(),
+ STABLE_BOUNDS.height(),
displayController
)
assertThat(argumentCaptor.value).isTrue()
@@ -409,12 +404,12 @@ class DesktopTasksControllerTest : ShellTestCase() {
val task1 = setUpFreeformTask(bounds = stableBounds, active = true)
val argumentCaptor = ArgumentCaptor.forClass(Boolean::class.java)
- controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(argumentCaptor.capture())
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task1,
0,
0,
@@ -1071,6 +1066,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
val wct = getLatestEnterDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
}
@Test
@@ -1082,12 +1078,14 @@ class DesktopTasksControllerTest : ShellTestCase() {
val wct = getLatestEnterDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_UNDEFINED)
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
}
@Test
fun moveTaskToDesktop_nonExistentTask_doesNothing() {
controller.moveTaskToDesktop(999, transitionSource = UNKNOWN)
verifyEnterDesktopWCTNotExecuted()
+ verify(desktopModeEnterExitTransitionListener, times(0)).onEnterDesktopModeTransitionStarted(anyInt())
}
@Test
@@ -1132,9 +1130,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
-
val wct = getLatestEnterDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
}
@Test
@@ -1149,6 +1147,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
verifyEnterDesktopWCTNotExecuted()
+ verify(desktopModeEnterExitTransitionListener, times(0)).onEnterDesktopModeTransitionStarted(
+ FREEFORM_ANIMATION_DURATION
+ )
}
@Test
@@ -1195,6 +1196,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val wct = getLatestEnterDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
}
@Test
@@ -1214,6 +1216,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_FREEFORM)
}
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
}
@Test
@@ -1234,6 +1237,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_FREEFORM)
}
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
}
@Test
@@ -1255,6 +1259,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
assertThat(hierarchyOps.map { it.container })
.doesNotContain(freeformTaskSecond.token.asBinder())
}
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
}
@Test
@@ -1263,6 +1268,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
val wct = getLatestEnterDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
verify(splitScreenController)
.prepareExitSplitScreen(any(), anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE))
}
@@ -1273,6 +1279,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
val wct = getLatestEnterDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
verify(splitScreenController, never())
.prepareExitSplitScreen(any(), anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE))
}
@@ -1287,6 +1294,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveRunningTaskToDesktop(newTask, transitionSource = UNKNOWN)
val wct = getLatestEnterDesktopWct()
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
assertThat(wct.hierarchyOps.size).isEqualTo(MAX_TASK_LIMIT + 1) // visible tasks + home
wct.assertReorderAt(0, homeTask)
wct.assertReorderSequenceInRange(
@@ -1305,6 +1313,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveRunningTaskToDesktop(newTask, transitionSource = UNKNOWN)
val wct = getLatestEnterDesktopWct()
+ verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
assertThat(wct.hierarchyOps.size).isEqualTo(MAX_TASK_LIMIT + 2) // tasks + home + wallpaper
// Move home to front
wct.assertReorderAt(0, homeTask)
@@ -1324,6 +1333,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
val wct = getLatestExitDesktopWct()
+ verify(desktopModeEnterExitTransitionListener, times(1)).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_UNDEFINED)
}
@@ -1341,6 +1351,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val wct = getLatestExitDesktopWct()
val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+ verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
// Removes wallpaper activity when leaving desktop
wct.assertRemoveAt(index = 0, wallpaperToken)
@@ -1355,6 +1366,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val wct = getLatestExitDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
}
@Test
@@ -1371,6 +1383,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val wct = getLatestExitDesktopWct()
val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
// Removes wallpaper activity when leaving desktop
wct.assertRemoveAt(index = 0, wallpaperToken)
}
@@ -1391,6 +1404,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val wct = getLatestExitDesktopWct()
val task1Change = assertNotNull(wct.changes[task1.token.asBinder()])
assertThat(task1Change.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
+ verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
// Does not remove wallpaper activity, as desktop still has a visible desktop task
assertThat(wct.hierarchyOps).isEmpty()
}
@@ -1405,13 +1419,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveToFullscreen_secondDisplayTaskHasFreeform_secondDisplayNotAffected() {
val taskDefaultDisplay = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
val taskSecondDisplay = setUpFreeformTask(displayId = SECOND_DISPLAY)
-
controller.moveToFullscreen(taskDefaultDisplay.taskId, transitionSource = UNKNOWN)
with(getLatestExitDesktopWct()) {
assertThat(changes.keys).contains(taskDefaultDisplay.token.asBinder())
assertThat(changes.keys).doesNotContain(taskSecondDisplay.token.asBinder())
}
+ verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
}
@Test
@@ -1556,44 +1570,6 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
- @EnableFlags(
- FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS,
- FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
- FLAG_USE_KEY_GESTURE_EVENT_HANDLER
- )
- fun moveToNextDisplay_withKeyGesture() {
- // Set up two display ids
- whenever(rootTaskDisplayAreaOrganizer.displayIds)
- .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
- // Create a mock for the target display area: default display
- val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
- whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
- .thenReturn(defaultDisplayArea)
- // Setup a focused task on secondary display, which is expected to move to default display
- val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
- task.isFocused = true
- whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
- whenever(mockFocusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
-
- val event = KeyGestureEvent.Builder()
- .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY)
- .setDisplayId(SECOND_DISPLAY)
- .setKeycodes(intArrayOf(KeyEvent.KEYCODE_D))
- .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
- .build()
- val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
-
- assertThat(result).isTrue()
- with(getLatestWct(type = TRANSIT_CHANGE)) {
- assertThat(hierarchyOps).hasSize(1)
- assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
- assertThat(hierarchyOps[0].isReparent).isTrue()
- assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder())
- assertThat(hierarchyOps[0].toTop).isTrue()
- }
- }
-
- @Test
fun getTaskWindowingMode() {
val fullscreenTask = setUpFullscreenTask()
val freeformTask = setUpFreeformTask()
@@ -1822,7 +1798,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.minimizeTask(task)
- verify(mMockDesktopImmersiveController).exitImmersiveIfApplicable(any(), eq(task))
+ verify(mMockDesktopImmersiveController).exitImmersiveIfApplicable(any(), eq(task), any())
}
@Test
@@ -1832,8 +1808,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val runOnTransit = RunOnStartTransitionCallback()
whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
.thenReturn(transition)
- whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task)))
- .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task), any()))
+ .thenReturn(
+ ExitResult.Exit(
exitingTask = task.taskId,
runOnTransitionStart = runOnTransit,
))
@@ -1948,6 +1925,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun handleRequest_fullscreenTask_noTasks_enforceDesktop_freeformDisplay_returnFreeformWCT() {
whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
@@ -1959,8 +1937,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
assertNotNull(wct, "should handle request")
assertThat(wct.changes[fullscreenTask.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_UNDEFINED)
- assertThat(wct.hierarchyOps).hasSize(1)
- wct.assertReorderAt(0, fullscreenTask, toTop = true)
+ assertThat(wct.hierarchyOps).hasSize(3)
+ // There are 3 hops that are happening in this case:
+ // 1. Moving the fullscreen task to top as we add moveToDesktop() changes
+ // 2. Pending intent for the wallpaper
+ // 3. Bringing the fullscreen task back at the top
+ wct.assertPendingIntentAt(1, desktopWallpaperIntent)
+ wct.assertReorderAt(2, fullscreenTask, toTop = true)
}
@Test
@@ -2220,7 +2203,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
markTaskVisible(freeformTask)
// Mark recents animation running
- recentsTransitionStateListener.onAnimationStateChanged(true)
+ recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_ANIMATING)
// Open a fullscreen task, check that it does not result in a WCT with changes to it
val fullscreenTask = createFullscreenTask()
@@ -2234,7 +2217,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
markTaskVisible(freeformTask)
// Mark recents animation running
- recentsTransitionStateListener.onAnimationStateChanged(true)
+ recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_ANIMATING)
// Should become undefined as the TDA is set to fullscreen. It will inherit from the TDA.
val result = controller.handleRequest(Binder(), createTransition(freeformTask))
@@ -3041,16 +3024,18 @@ class DesktopTasksControllerTest : ShellTestCase() {
// Assert event is properly logged
verify(desktopModeEventLogger, times(1)).logTaskResizingStarted(
ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER,
- motionEvent,
+ InputMethod.UNKNOWN_INPUT_METHOD,
task,
+ task.configuration.windowConfiguration.bounds.width(),
+ task.configuration.windowConfiguration.bounds.height(),
displayController
)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER,
- motionEvent,
+ InputMethod.UNKNOWN_INPUT_METHOD,
task,
- STABLE_BOUNDS.height(),
STABLE_BOUNDS.width(),
+ STABLE_BOUNDS.height(),
displayController
)
}
@@ -3099,7 +3084,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
// Assert no event is logged
verify(desktopModeEventLogger, never()).logTaskResizingStarted(
- any(), any(), any(), any(), any()
+ any(), any(), any(), any(), any(), any(), any()
)
verify(desktopModeEventLogger, never()).logTaskResizingEnded(
any(), any(), any(), any(), any(), any(), any()
@@ -3187,7 +3172,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
runOpenNewWindow(task)
verify(splitScreenController)
.startIntent(any(), anyInt(), any(), any(),
- optionsCaptor.capture(), anyOrNull(), eq(true)
+ optionsCaptor.capture(), anyOrNull(), eq(true), eq(SPLIT_INDEX_UNDEFINED)
)
assertThat(ActivityOptions.fromBundle(optionsCaptor.value).launchWindowingMode)
.isEqualTo(WINDOWING_MODE_MULTI_WINDOW)
@@ -3203,7 +3188,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
verify(splitScreenController)
.startIntent(
any(), anyInt(), any(), any(),
- optionsCaptor.capture(), anyOrNull(), eq(true)
+ optionsCaptor.capture(), anyOrNull(), eq(true), eq(SPLIT_INDEX_UNDEFINED)
)
assertThat(ActivityOptions.fromBundle(optionsCaptor.value).launchWindowingMode)
.isEqualTo(WINDOWING_MODE_MULTI_WINDOW)
@@ -3214,13 +3199,43 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun newWindow_fromFreeformAddsNewWindow() {
setUpLandscapeDisplay()
val task = setUpFreeformTask()
- val wctCaptor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ val wctCaptor = argumentCaptor<WindowContainerTransaction>()
+ val transition = Binder()
+ whenever(mMockDesktopImmersiveController
+ .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull(), any()))
+ .thenReturn(ExitResult.NoExit)
+ whenever(desktopMixedTransitionHandler
+ .startLaunchTransition(anyInt(), any(), anyOrNull(), anyOrNull(), anyOrNull()))
+ .thenReturn(transition)
+
runOpenNewWindow(task)
- verify(transitions).startTransition(anyInt(), wctCaptor.capture(), anyOrNull())
- assertThat(ActivityOptions.fromBundle(wctCaptor.value.hierarchyOps[0].launchOptions)
+
+ verify(desktopMixedTransitionHandler)
+ .startLaunchTransition(anyInt(), wctCaptor.capture(), anyOrNull(), anyOrNull(), anyOrNull())
+ assertThat(ActivityOptions.fromBundle(wctCaptor.firstValue.hierarchyOps[0].launchOptions)
.launchWindowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
}
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
+ fun newWindow_fromFreeform_exitsImmersiveIfNeeded() {
+ setUpLandscapeDisplay()
+ val immersiveTask = setUpFreeformTask()
+ val task = setUpFreeformTask()
+ val runOnStart = RunOnStartTransitionCallback()
+ val transition = Binder()
+ whenever(mMockDesktopImmersiveController
+ .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull(), any()))
+ .thenReturn(ExitResult.Exit(immersiveTask.taskId, runOnStart))
+ whenever(desktopMixedTransitionHandler
+ .startLaunchTransition(anyInt(), any(), anyOrNull(), anyOrNull(), anyOrNull()))
+ .thenReturn(transition)
+
+ runOpenNewWindow(task)
+
+ runOnStart.assertOnlyInvocation(transition)
+ }
+
private fun runOpenNewWindow(task: RunningTaskInfo) {
markTaskVisible(task)
task.baseActivity = mock(ComponentName::class.java)
@@ -3313,8 +3328,10 @@ class DesktopTasksControllerTest : ShellTestCase() {
whenever(transitions.startTransition(eq(TRANSIT_OPEN), any(), anyOrNull()))
.thenReturn(transition)
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(any(), eq(immersiveTask.displayId), eq(freeformTask.taskId)))
- .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ .exitImmersiveIfApplicable(
+ any(), eq(immersiveTask.displayId), eq(freeformTask.taskId), any()))
+ .thenReturn(
+ ExitResult.Exit(
exitingTask = immersiveTask.taskId,
runOnTransitionStart = runOnStartTransit,
))
@@ -3322,7 +3339,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
runOpenInstance(immersiveTask, freeformTask.taskId)
verify(mMockDesktopImmersiveController)
- .exitImmersiveIfApplicable(any(), eq(immersiveTask.displayId), eq(freeformTask.taskId))
+ .exitImmersiveIfApplicable(any(), eq(immersiveTask.displayId), eq(freeformTask.taskId), any())
runOnStartTransit.assertOnlyInvocation(transition)
}
@@ -3342,17 +3359,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
val bounds = Rect(0, 0, 100, 100)
val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
// Assert bounds set to stable bounds
val wct = getLatestToggleResizeDesktopTaskWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(STABLE_BOUNDS)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task,
- STABLE_BOUNDS.height(),
STABLE_BOUNDS.width(),
+ STABLE_BOUNDS.height(),
displayController
)
}
@@ -3375,16 +3392,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
controller.snapToHalfScreen(task, mockSurface, currentDragBounds, SnapPosition.LEFT,
- ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration)
+ ResizeTrigger.SNAP_LEFT_MENU, InputMethod.TOUCH, desktopWindowDecoration)
// Assert bounds set to stable bounds
val wct = getLatestToggleResizeDesktopTaskWct(currentDragBounds)
assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.SNAP_LEFT_MENU,
- motionEvent,
+ InputMethod.TOUCH,
task,
- expectedBounds.height(),
expectedBounds.width(),
+ expectedBounds.height(),
displayController
)
}
@@ -3407,7 +3424,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
// Attempt to snap left again
val currentDragBounds = Rect(bounds).apply { offset(-100, 0) }
controller.snapToHalfScreen(task, mockSurface, currentDragBounds, SnapPosition.LEFT,
- ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration)
+ ResizeTrigger.SNAP_LEFT_MENU, InputMethod.TOUCH, desktopWindowDecoration)
// Assert that task is NOT updated via WCT
verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
@@ -3421,17 +3438,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.SNAP_LEFT_MENU,
- motionEvent,
+ InputMethod.TOUCH,
task,
- bounds.height(),
bounds.width(),
+ bounds.height(),
displayController
)
}
@Test
@DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING, Flags.FLAG_ENABLE_TILE_RESIZING)
- fun handleSnapResizingTask_nonResizable_snapsToHalfScreen() {
+ fun handleSnapResizingTaskOnDrag_nonResizable_snapsToHalfScreen() {
val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply {
isResizeable = false
}
@@ -3440,7 +3457,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val expectedBounds =
Rect(STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom)
- controller.handleSnapResizingTask(
+ controller.handleSnapResizingTaskOnDrag(
task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent,
desktopWindowDecoration
@@ -3451,22 +3468,24 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
verify(desktopModeEventLogger, times(1)).logTaskResizingStarted(
ResizeTrigger.DRAG_LEFT,
- motionEvent,
+ InputMethod.UNKNOWN_INPUT_METHOD,
task,
+ preDragBounds.width(),
+ preDragBounds.height(),
displayController
)
}
@Test
@EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
- fun handleSnapResizingTask_nonResizable_startsRepositionAnimation() {
+ fun handleSnapResizingTaskOnDrag_nonResizable_startsRepositionAnimation() {
val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply {
isResizeable = false
}
val preDragBounds = Rect(100, 100, 400, 500)
val currentDragBounds = Rect(0, 100, 300, 500)
- controller.handleSnapResizingTask(
+ controller.handleSnapResizingTaskOnDrag(
task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent,
desktopWindowDecoration)
verify(mReturnToDragStartAnimator).start(
@@ -3481,11 +3500,75 @@ class DesktopTasksControllerTest : ShellTestCase() {
any(),
any(),
any(),
+ any(),
+ any(),
any()
)
}
@Test
+ @EnableFlags(
+ Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING
+ )
+ fun handleInstantSnapResizingTask_nonResizable_animatorNotStartedAndShowsToast() {
+ val taskBounds = Rect(0, 0, 200, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply {
+ isResizeable = false
+ }
+
+ controller.handleInstantSnapResizingTask(
+ task,
+ SnapPosition.LEFT,
+ ResizeTrigger.SNAP_LEFT_MENU,
+ InputMethod.MOUSE,
+ desktopWindowDecoration
+ )
+
+ // Assert that task is NOT updated via WCT
+ verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
+ verify(mockToast).show()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
+ @DisableFlags(Flags.FLAG_ENABLE_TILE_RESIZING)
+ fun handleInstantSnapResizingTask_resizable_snapsToHalfScreenAndNotShowToast() {
+ val taskBounds = Rect(0, 0, 200, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply {
+ isResizeable = true
+ }
+ val expectedBounds = Rect(
+ STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom
+ )
+
+ controller.handleInstantSnapResizingTask(
+ task, SnapPosition.LEFT, ResizeTrigger.SNAP_LEFT_MENU, InputMethod.MOUSE,
+ desktopWindowDecoration
+ )
+
+ // Assert bounds set to half of the stable bounds
+ val wct = getLatestToggleResizeDesktopTaskWct(taskBounds)
+ assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
+ verify(mockToast, never()).show()
+ verify(desktopModeEventLogger, times(1)).logTaskResizingStarted(
+ ResizeTrigger.SNAP_LEFT_MENU,
+ InputMethod.MOUSE,
+ task,
+ taskBounds.width(),
+ taskBounds.height(),
+ displayController
+ )
+ verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
+ ResizeTrigger.SNAP_LEFT_MENU,
+ InputMethod.MOUSE,
+ task,
+ expectedBounds.width(),
+ expectedBounds.height(),
+ displayController
+ )
+ }
+
+ @Test
fun toggleBounds_togglesToCalculatedBoundsForNonResizable() {
val bounds = Rect(0, 0, 200, 100)
val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds).apply {
@@ -3501,17 +3584,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
// Bounds should be 1000 x 500, vertically centered in the 1000 x 1000 stable bounds
val expectedBounds = Rect(STABLE_BOUNDS.left, 250, STABLE_BOUNDS.right, 750)
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
// Assert bounds set to stable bounds
val wct = getLatestToggleResizeDesktopTaskWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task,
- expectedBounds.height(),
expectedBounds.width(),
+ expectedBounds.height(),
displayController
)
}
@@ -3521,7 +3604,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val bounds = Rect(0, 0, 100, 100)
val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isEqualTo(bounds)
verify(desktopModeEventLogger, never()).logTaskResizingEnded(
any(), any(), any(), any(),
@@ -3535,21 +3618,21 @@ class DesktopTasksControllerTest : ShellTestCase() {
val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
// Maximize
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)
// Restore
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
// Assert bounds set to last bounds before maximize
val wct = getLatestToggleResizeDesktopTaskWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task,
- boundsBeforeMaximize.height(),
boundsBeforeMaximize.width(),
+ boundsBeforeMaximize.height(),
displayController
)
}
@@ -3562,22 +3645,22 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
// Maximize
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS.left,
boundsBeforeMaximize.top, STABLE_BOUNDS.right, boundsBeforeMaximize.bottom)
// Restore
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
// Assert bounds set to last bounds before maximize
val wct = getLatestToggleResizeDesktopTaskWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task,
- boundsBeforeMaximize.height(),
boundsBeforeMaximize.width(),
+ boundsBeforeMaximize.height(),
displayController
)
}
@@ -3590,22 +3673,22 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
// Maximize
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
task.configuration.windowConfiguration.bounds.set(boundsBeforeMaximize.left,
STABLE_BOUNDS.top, boundsBeforeMaximize.right, STABLE_BOUNDS.bottom)
// Restore
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
// Assert bounds set to last bounds before maximize
val wct = getLatestToggleResizeDesktopTaskWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task,
- boundsBeforeMaximize.height(),
boundsBeforeMaximize.width(),
+ boundsBeforeMaximize.height(),
displayController
)
}
@@ -3616,20 +3699,20 @@ class DesktopTasksControllerTest : ShellTestCase() {
val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
// Maximize
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)
// Restore
- controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+ controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
// Assert last bounds before maximize removed after use
assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isNull()
verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
ResizeTrigger.MAXIMIZE_BUTTON,
- motionEvent,
+ InputMethod.TOUCH,
task,
- boundsBeforeMaximize.height(),
boundsBeforeMaximize.width(),
+ boundsBeforeMaximize.height(),
displayController
)
}
@@ -3684,7 +3767,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.toggleDesktopTaskFullImmersiveState(task)
- verify(mMockDesktopImmersiveController).moveTaskToNonImmersive(task)
+ verify(mMockDesktopImmersiveController).moveTaskToNonImmersive(eq(task), any())
}
@Test
@@ -3696,7 +3779,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
task.requestedVisibleTypes = WindowInsets.Type.statusBars()
controller.onTaskInfoChanged(task)
- verify(mMockDesktopImmersiveController).moveTaskToNonImmersive(task)
+ verify(mMockDesktopImmersiveController).moveTaskToNonImmersive(eq(task), any())
}
@Test
@@ -3708,7 +3791,20 @@ class DesktopTasksControllerTest : ShellTestCase() {
task.requestedVisibleTypes = WindowInsets.Type.statusBars()
controller.onTaskInfoChanged(task)
- verify(mMockDesktopImmersiveController, never()).moveTaskToNonImmersive(task)
+ verify(mMockDesktopImmersiveController, never()).moveTaskToNonImmersive(eq(task), any())
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun onTaskInfoChanged_inImmersiveUnrequestsImmersive_inRecentsTransition_noExit() {
+ val task = setUpFreeformTask(DEFAULT_DISPLAY)
+ taskRepository.setTaskInFullImmersiveState(DEFAULT_DISPLAY, task.taskId, immersive = true)
+ recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_REQUESTED)
+
+ task.requestedVisibleTypes = WindowInsets.Type.statusBars()
+ controller.onTaskInfoChanged(task)
+
+ verify(mMockDesktopImmersiveController, never()).moveTaskToNonImmersive(eq(task), any())
}
@Test
@@ -3718,8 +3814,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(wct, task.displayId, task.taskId))
- .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ .exitImmersiveIfApplicable(eq(wct), eq(task.displayId), eq(task.taskId), any()))
+ .thenReturn(
+ ExitResult.Exit(
exitingTask = 5,
runOnTransitionStart = runOnStartTransit,
))
@@ -3728,7 +3825,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveTaskToDesktop(taskId = task.taskId, wct = wct, transitionSource = UNKNOWN)
verify(mMockDesktopImmersiveController)
- .exitImmersiveIfApplicable(wct, task.displayId, task.taskId)
+ .exitImmersiveIfApplicable(eq(wct), eq(task.displayId), eq(task.taskId), any())
runOnStartTransit.assertOnlyInvocation(transition)
}
@@ -3739,8 +3836,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(wct, task.displayId, task.taskId))
- .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ .exitImmersiveIfApplicable(eq(wct), eq(task.displayId), eq(task.taskId), any()))
+ .thenReturn(
+ ExitResult.Exit(
exitingTask = 5,
runOnTransitionStart = runOnStartTransit,
))
@@ -3749,7 +3847,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveTaskToDesktop(taskId = task.taskId, wct = wct, transitionSource = UNKNOWN)
verify(mMockDesktopImmersiveController)
- .exitImmersiveIfApplicable(wct, task.displayId, task.taskId)
+ .exitImmersiveIfApplicable(eq(wct), eq(task.displayId), eq(task.taskId), any())
runOnStartTransit.assertOnlyInvocation(transition)
}
@@ -3759,8 +3857,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId)))
- .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId), any()))
+ .thenReturn(
+ ExitResult.Exit(
exitingTask = 5,
runOnTransitionStart = runOnStartTransit,
))
@@ -3771,7 +3870,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveTaskToFront(task.taskId, remoteTransition = null)
verify(mMockDesktopImmersiveController)
- .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId))
+ .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId), any())
runOnStartTransit.assertOnlyInvocation(transition)
}
@@ -3781,8 +3880,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId)))
- .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId), any()))
+ .thenReturn(
+ ExitResult.Exit(
exitingTask = 5,
runOnTransitionStart = runOnStartTransit,
))
@@ -3793,7 +3893,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveTaskToFront(task.taskId, remoteTransition = null)
verify(mMockDesktopImmersiveController)
- .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId))
+ .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId), any())
runOnStartTransit.assertOnlyInvocation(transition)
}
@@ -3807,7 +3907,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.handleRequest(binder, createTransition(task))
verify(mMockDesktopImmersiveController)
- .exitImmersiveIfApplicable(eq(binder), any(), eq(task.displayId))
+ .exitImmersiveIfApplicable(eq(binder), any(), eq(task.displayId), any())
}
@Test
@@ -3819,7 +3919,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.handleRequest(binder, createTransition(task))
verify(mMockDesktopImmersiveController)
- .exitImmersiveIfApplicable(eq(binder), any(), eq(task.displayId))
+ .exitImmersiveIfApplicable(eq(binder), any(), eq(task.displayId), any())
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
index 456b50da095b..797b12505ef2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
@@ -42,7 +42,7 @@ import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGAT
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.ShellExecutor
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
index 52da7fb811d0..866d1b3880b0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
@@ -27,62 +27,56 @@ import android.view.Display.DEFAULT_DISPLAY
import com.android.wm.shell.MockToken
import com.android.wm.shell.TestRunningTaskInfoBuilder
-class DesktopTestHelpers {
- companion object {
- /** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
- @JvmStatic
- @JvmOverloads
- fun createFreeformTask(
- displayId: Int = DEFAULT_DISPLAY,
- bounds: Rect? = null
- ): RunningTaskInfo {
- return TestRunningTaskInfoBuilder()
- .setDisplayId(displayId)
- .setToken(MockToken().token())
- .setActivityType(ACTIVITY_TYPE_STANDARD)
- .setWindowingMode(WINDOWING_MODE_FREEFORM)
- .setLastActiveTime(100)
- .apply { bounds?.let { setBounds(it) }}
- .build()
- }
+object DesktopTestHelpers {
+ /** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
+ fun createFreeformTask(
+ displayId: Int = DEFAULT_DISPLAY,
+ bounds: Rect? = null,
+ ): RunningTaskInfo =
+ TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
+ .setToken(MockToken().token())
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .setLastActiveTime(100)
+ .apply { bounds?.let { setBounds(it) } }
+ .build()
- /** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
- @JvmStatic
- @JvmOverloads
- fun createFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
- return TestRunningTaskInfoBuilder()
- .setDisplayId(displayId)
- .setToken(MockToken().token())
- .setActivityType(ACTIVITY_TYPE_STANDARD)
- .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
- .setLastActiveTime(100)
- .build()
- }
+ fun createFullscreenTaskBuilder(displayId: Int = DEFAULT_DISPLAY): TestRunningTaskInfoBuilder =
+ TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
+ .setToken(MockToken().token())
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+ .setLastActiveTime(100)
- /** Create a task that has windowing mode set to [WINDOWING_MODE_MULTI_WINDOW] */
- @JvmStatic
- @JvmOverloads
- fun createSplitScreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
- return TestRunningTaskInfoBuilder()
- .setDisplayId(displayId)
- .setToken(MockToken().token())
- .setActivityType(ACTIVITY_TYPE_STANDARD)
- .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
- .setLastActiveTime(100)
- .build()
- }
+ /** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
+ fun createFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+ createFullscreenTaskBuilder(displayId).build()
- /** Create a new home task */
- @JvmStatic
- @JvmOverloads
- fun createHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
- return TestRunningTaskInfoBuilder()
- .setDisplayId(displayId)
- .setToken(MockToken().token())
- .setActivityType(ACTIVITY_TYPE_HOME)
- .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
- .setLastActiveTime(100)
- .build()
- }
- }
-} \ No newline at end of file
+ /** Create a task that has windowing mode set to [WINDOWING_MODE_MULTI_WINDOW] */
+ fun createSplitScreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+ TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
+ .setToken(MockToken().token())
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
+ .setLastActiveTime(100)
+ .build()
+
+ fun createHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+ TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
+ .setToken(MockToken().token())
+ .setActivityType(ACTIVITY_TYPE_HOME)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+ .setLastActiveTime(100)
+ .build()
+
+ /** Create a new System Modal task, i.e. a task with a single transparent activity. */
+ fun createSystemModalTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+ createFullscreenTaskBuilder(displayId)
+ .setTopActivityTransparent(true)
+ .setNumActivities(1)
+ .build()
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt
new file mode 100644
index 000000000000..226e974d2875
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode.compatui
+
+import android.os.Binder
+import android.testing.AndroidTestingRunner
+import android.view.SurfaceControl
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TRANSIT_CLOSE
+import android.view.WindowManager.TRANSIT_OPEN
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTaskBuilder
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createSystemModalTask
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.TransitionInfoBuilder
+import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SystemModalsTransitionHandlerTest : ShellTestCase() {
+ private val mainExecutor = mock<ShellExecutor>()
+ private val animExecutor = mock<ShellExecutor>()
+ private val shellInit = mock<ShellInit>()
+ private val transitions = mock<Transitions>()
+ private val desktopRepository = mock<DesktopRepository>()
+ private val startT = mock<SurfaceControl.Transaction>()
+ private val finishT = mock<SurfaceControl.Transaction>()
+
+ private lateinit var transitionHandler: SystemModalsTransitionHandler
+
+ @Before
+ fun setUp() {
+ // Simulate having one Desktop task so that we see Desktop Mode as active
+ whenever(desktopRepository.getVisibleTaskCount(anyInt())).thenReturn(1)
+ transitionHandler = createTransitionHandler()
+ }
+
+ private fun createTransitionHandler() =
+ SystemModalsTransitionHandler(
+ context,
+ mainExecutor,
+ animExecutor,
+ shellInit,
+ transitions,
+ desktopRepository,
+ )
+
+ @Test
+ fun instantiate_addsInitCallback() {
+ verify(shellInit).addInitCallback(any(), any<SystemModalsTransitionHandler>())
+ }
+
+ @Test
+ fun startAnimation_desktopNotActive_doesNotAnimate() {
+ whenever(desktopRepository.getVisibleTaskCount(anyInt())).thenReturn(1)
+ val info =
+ TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, createSystemModalTask())
+ .build()
+
+ assertThat(transitionHandler.startAnimation(Binder(), info, startT, finishT) {}).isTrue()
+ }
+
+ @Test
+ fun startAnimation_launchingSystemModal_animates() {
+ val info =
+ TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, createSystemModalTask())
+ .build()
+
+ assertThat(transitionHandler.startAnimation(Binder(), info, startT, finishT) {}).isTrue()
+ }
+
+ @Test
+ fun startAnimation_nonLaunchingSystemModal_doesNotAnimate() {
+ val info =
+ TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_CHANGE, createSystemModalTask())
+ .build()
+
+ assertThat(transitionHandler.startAnimation(Binder(), info, startT, finishT) {}).isFalse()
+ }
+
+ @Test
+ fun startAnimation_launchingFullscreenTask_doesNotAnimate() {
+ val info =
+ TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, createFullscreenTask())
+ .build()
+
+ assertThat(transitionHandler.startAnimation(Binder(), info, startT, finishT) {}).isFalse()
+ }
+
+ @Test
+ fun startAnimation_closingSystemModal_animates() {
+ val info =
+ TransitionInfoBuilder(TRANSIT_CLOSE)
+ .addChange(TRANSIT_CLOSE, createSystemModalTask())
+ .build()
+
+ assertThat(transitionHandler.startAnimation(Binder(), info, startT, finishT) {}).isTrue()
+ }
+
+ @Test
+ fun startAnimation_closingFullscreenTask_doesNotAnimate() {
+ val info =
+ TransitionInfoBuilder(TRANSIT_CLOSE)
+ .addChange(TRANSIT_CLOSE, createFullscreenTask())
+ .build()
+
+ assertThat(transitionHandler.startAnimation(Binder(), info, startT, finishT) {}).isFalse()
+ }
+
+ @Test
+ fun startAnimation_closingPreviouslyLaunchedSystemModal_animates() {
+ val systemModalTask = createSystemModalTask()
+ val nonModalSystemModalTask =
+ createFullscreenTaskBuilder().setTaskId(systemModalTask.taskId).build()
+ val launchInfo =
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, systemModalTask).build()
+ transitionHandler.startAnimation(Binder(), launchInfo, startT, finishT) {}
+ val closeInfo =
+ TransitionInfoBuilder(TRANSIT_CLOSE)
+ .addChange(TRANSIT_CLOSE, nonModalSystemModalTask)
+ .build()
+
+ assertThat(transitionHandler.startAnimation(Binder(), closeInfo, startT, finishT) {})
+ .isTrue()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
index d94186c8284e..9c00c0cee8b1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
@@ -175,13 +175,13 @@ class AppHandleEducationControllerTest : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
- fun init_educationViewedAlready_shouldNotCallShowEducationTooltip() =
+ fun init_appHandleHintViewedAlready_shouldNotCallShowEducationTooltip() =
testScope.runTest {
- // App handle is visible but education has been viewed before. Should not show education
- // tooltip.
- // Mark education viewed.
+ // App handle is visible but app handle hint has been viewed before,
+ // should not show education tooltip.
+ // Mark app handle hint viewed.
testDataStoreFlow.value =
- createWindowingEducationProto(educationViewedTimestampMillis = 123L)
+ createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L)
setShouldShowAppHandleEducation(true)
// Simulate app handle visible.
@@ -194,13 +194,14 @@ class AppHandleEducationControllerTest : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
- fun overridePrerequisite_educationViewedAlready_shouldCallShowEducationTooltip() =
+ fun overridePrerequisite_appHandleHintViewedAlready_shouldCallShowEducationTooltip() =
testScope.runTest {
- // App handle is visible but education has been viewed before. But as we are overriding
- // prerequisite conditions, we should show education tooltip.
- // Mark education viewed.
+ // App handle is visible but app handle hint has been viewed before.
+ // But as we are overriding prerequisite conditions, we should show app
+ // handle tooltip.
+ // Mark app handle hint viewed.
testDataStoreFlow.value =
- createWindowingEducationProto(educationViewedTimestampMillis = 123L)
+ createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L)
val systemPropertiesKey =
"persist.desktop_windowing_app_handle_education_override_conditions"
whenever(SystemProperties.getBoolean(eq(systemPropertiesKey), anyBoolean()))
@@ -217,7 +218,7 @@ class AppHandleEducationControllerTest : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
- fun init_appHandleExpanded_shouldMarkFeatureViewed() =
+ fun init_appHandleExpanded_shouldMarkAppHandleHintUsed() =
testScope.runTest {
setShouldShowAppHandleEducation(false)
@@ -226,12 +227,12 @@ class AppHandleEducationControllerTest : ShellTestCase() {
// Wait for some time before verifying
waitForBufferDelay()
- verify(mockDataStoreRepository, times(1)).updateFeatureUsedTimestampMillis(eq(true))
+ verify(mockDataStoreRepository, times(1)).updateAppHandleHintUsedTimestampMillis(eq(true))
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
- fun init_showFirstTooltip_shouldMarkEducationViewed() =
+ fun init_showFirstTooltip_shouldMarkAppHandleHintViewed() =
testScope.runTest {
// App handle is visible. Should show education tooltip.
setShouldShowAppHandleEducation(true)
@@ -241,7 +242,7 @@ class AppHandleEducationControllerTest : ShellTestCase() {
// Wait for first tooltip to showup.
waitForBufferDelay()
- verify(mockDataStoreRepository, times(1)).updateEducationViewedTimestampMillis(eq(true))
+ verify(mockDataStoreRepository, times(1)).updateAppHandleHintViewedTimestampMillis(eq(true))
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt
index c2865441d7a6..963890d1caa4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt
@@ -81,8 +81,8 @@ class AppHandleEducationDatastoreRepositoryTest {
runTest(StandardTestDispatcher()) {
val windowingEducationProto =
createWindowingEducationProto(
- educationViewedTimestampMillis = 123L,
- featureUsedTimestampMillis = 124L,
+ appHandleHintViewedTimestampMillis = 123L,
+ appHandleHintUsedTimestampMillis = 124L,
appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 2),
appUsageStatsLastUpdateTimestampMillis = 125L)
testDatastore.updateData { windowingEducationProto }
@@ -110,20 +110,20 @@ class AppHandleEducationDatastoreRepositoryTest {
}
@Test
- fun updateEducationViewedTimestampMillis_updatesDatastoreProto() =
+ fun updateAppHandleHintViewedTimestampMillis_updatesDatastoreProto() =
runTest(StandardTestDispatcher()) {
- datastoreRepository.updateEducationViewedTimestampMillis(true)
+ datastoreRepository.updateAppHandleHintViewedTimestampMillis(true)
- val result = testDatastore.data.first().hasEducationViewedTimestampMillis()
+ val result = testDatastore.data.first().hasAppHandleHintViewedTimestampMillis()
assertThat(result).isEqualTo(true)
}
@Test
- fun updateFeatureUsedTimestampMillis_updatesDatastoreProto() =
+ fun updateAppHandleHintUsedTimestampMillis_updatesDatastoreProto() =
runTest(StandardTestDispatcher()) {
- datastoreRepository.updateFeatureUsedTimestampMillis(true)
+ datastoreRepository.updateAppHandleHintUsedTimestampMillis(true)
- val result = testDatastore.data.first().hasFeatureUsedTimestampMillis()
+ val result = testDatastore.data.first().hasAppHandleHintUsedTimestampMillis()
assertThat(result).isEqualTo(true)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt
index a3e74e8aed5d..e5edd69155b5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt
@@ -134,12 +134,12 @@ class AppHandleEducationFilterTest : ShellTestCase() {
}
@Test
- fun shouldShowAppHandleEducation_educationViewedBefore_returnsFalse() = runTest {
- // Education has been viewed before, hence #shouldShowAppHandleEducation should return false
+ fun shouldShowAppHandleEducation_appHandleHintViewedBefore_returnsFalse() = runTest {
+ // App handle hint has been viewed before, hence #shouldShowAppHandleEducation should return false
val windowingEducationProto =
createWindowingEducationProto(
appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4),
- educationViewedTimestampMillis = 123L,
+ appHandleHintViewedTimestampMillis = 123L,
appUsageStatsLastUpdateTimestampMillis = Long.MAX_VALUE)
`when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto)
@@ -149,12 +149,12 @@ class AppHandleEducationFilterTest : ShellTestCase() {
}
@Test
- fun shouldShowAppHandleEducation_featureUsedBefore_returnsFalse() = runTest {
- // Feature has been used before, hence #shouldShowAppHandleEducation should return false
+ fun shouldShowAppHandleEducation_appHandleHintUsedBefore_returnsFalse() = runTest {
+ // App handle hint has been used before, hence #shouldShowAppHandleEducation should return false
val windowingEducationProto =
createWindowingEducationProto(
appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4),
- featureUsedTimestampMillis = 123L,
+ appHandleHintUsedTimestampMillis = 123L,
appUsageStatsLastUpdateTimestampMillis = Long.MAX_VALUE)
`when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
index 2cfce6933e1b..0cf15baf30b0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
@@ -24,6 +24,7 @@ import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
import static com.android.wm.shell.draganddrop.DragTestUtils.createAppClipData;
import static com.android.wm.shell.draganddrop.DragTestUtils.createIntentClipData;
import static com.android.wm.shell.draganddrop.DragTestUtils.createTaskInfo;
@@ -226,7 +227,7 @@ public class SplitDragPolicyTest extends ShellTestCase {
mPolicy.onDropped(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
verify(mFullscreenStarter).startIntent(any(), anyInt(), any(),
- eq(SPLIT_POSITION_UNDEFINED), any(), any());
+ eq(SPLIT_POSITION_UNDEFINED), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
}
private void dragOverFullscreenApp_expectSplitScreenTargets(ClipData data) {
@@ -241,12 +242,12 @@ public class SplitDragPolicyTest extends ShellTestCase {
mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
- eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
+ eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
reset(mSplitScreenStarter);
mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
}
private void dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(ClipData data) {
@@ -261,13 +262,13 @@ public class SplitDragPolicyTest extends ShellTestCase {
mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
- eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
+ eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
reset(mSplitScreenStarter);
mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 5f58265b45f5..289fd2d838fd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -36,6 +36,8 @@ import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Rational;
@@ -46,6 +48,7 @@ import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.MockSurfaceControlHelper;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -67,6 +70,8 @@ import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
@@ -81,7 +86,13 @@ import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
+@DisableFlags(Flags.FLAG_ENABLE_PIP2)
public class PipTaskOrganizerTest extends ShellTestCase {
+ @ClassRule
+ public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
+
private PipTaskOrganizer mPipTaskOrganizer;
@Mock private DisplayController mMockDisplayController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 96003515a485..b123f4dfac9e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -42,11 +42,14 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
@@ -74,6 +77,8 @@ import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -88,7 +93,11 @@ import java.util.Set;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
+@DisableFlags(Flags.FLAG_ENABLE_PIP2)
public class PipControllerTest extends ShellTestCase {
+ @ClassRule public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
+ @Rule public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
+
private PipController mPipController;
private ShellInit mShellInit;
private ShellController mShellController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
index a4008c1e6995..72c466663a56 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -39,6 +40,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.wm.shell.R;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip2.phone.PipAppIconOverlay;
@@ -49,33 +51,25 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * Unit test again {@link PipEnterAnimator}.
+ * Unit test against {@link PipEnterAnimator}.
*/
@SmallTest
@TestableLooper.RunWithLooper
@RunWith(AndroidTestingRunner.class)
public class PipEnterAnimatorTest {
+ private static final float TEST_CORNER_RADIUS = 1f;
+ private static final float TEST_SHADOW_RADIUS = 2f;
@Mock private Context mMockContext;
-
@Mock private Resources mMockResources;
-
@Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
-
@Mock private SurfaceControl.Transaction mMockAnimateTransaction;
-
@Mock private SurfaceControl.Transaction mMockStartTransaction;
-
@Mock private SurfaceControl.Transaction mMockFinishTransaction;
-
@Mock private Runnable mMockStartCallback;
-
@Mock private Runnable mMockEndCallback;
-
@Mock private PipAppIconOverlay mMockPipAppIconOverlay;
-
@Mock private SurfaceControl mMockAppIconOverlayLeash;
-
@Mock private ActivityInfo mMockActivityInfo;
@Surface.Rotation private int mRotation;
@@ -89,13 +83,15 @@ public class PipEnterAnimatorTest {
when(mMockContext.getResources()).thenReturn(mMockResources);
when(mMockResources.getInteger(anyInt())).thenReturn(0);
when(mMockFactory.getTransaction()).thenReturn(mMockAnimateTransaction);
- when(mMockAnimateTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
- .thenReturn(mMockAnimateTransaction);
- when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
- .thenReturn(mMockStartTransaction);
- when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
- .thenReturn(mMockFinishTransaction);
when(mMockPipAppIconOverlay.getLeash()).thenReturn(mMockAppIconOverlayLeash);
+ when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius))
+ .thenReturn((int) TEST_CORNER_RADIUS);
+ when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius))
+ .thenReturn((int) TEST_SHADOW_RADIUS);
+
+ prepareTransaction(mMockAnimateTransaction);
+ prepareTransaction(mMockStartTransaction);
+ prepareTransaction(mMockFinishTransaction);
mTestLeash = new SurfaceControl.Builder()
.setContainerLayer()
@@ -122,6 +118,12 @@ public class PipEnterAnimatorTest {
verify(mMockStartCallback).run();
verifyZeroInteractions(mMockEndCallback);
+
+ // Check corner and shadow radii were set
+ verify(mMockAnimateTransaction, atLeastOnce())
+ .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+ verify(mMockAnimateTransaction, atLeastOnce())
+ .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
}
@Test
@@ -142,6 +144,12 @@ public class PipEnterAnimatorTest {
verify(mMockStartCallback).run();
verify(mMockEndCallback).run();
+
+ // Check corner and shadow radii were set
+ verify(mMockAnimateTransaction, atLeastOnce())
+ .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+ verify(mMockAnimateTransaction, atLeastOnce())
+ .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
}
@Test
@@ -197,5 +205,21 @@ public class PipEnterAnimatorTest {
verify(mMockPipAppIconOverlay).onAnimationUpdate(
eq(mMockAnimateTransaction), anyFloat(), eq(fraction), eq(mEndBounds));
+
+ // Check corner and shadow radii were set
+ verify(mMockAnimateTransaction, atLeastOnce())
+ .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+ verify(mMockAnimateTransaction, atLeastOnce())
+ .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
+ }
+
+ // set up transaction chaining
+ private void prepareTransaction(SurfaceControl.Transaction tx) {
+ when(tx.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+ .thenReturn(tx);
+ when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat()))
+ .thenReturn(tx);
+ when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat()))
+ .thenReturn(tx);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
index 0adb50b81896..23fbad05ec99 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
@@ -16,15 +16,18 @@
package com.android.wm.shell.pip2.animation;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.kotlin.MatchersKt.eq;
-import static org.junit.Assert.assertEquals;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
@@ -34,12 +37,14 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.wm.shell.R;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -52,40 +57,40 @@ import org.mockito.MockitoAnnotations;
public class PipResizeAnimatorTest {
private static final float FLOAT_COMPARISON_DELTA = 0.001f;
+ private static final float TEST_CORNER_RADIUS = 1f;
+ private static final float TEST_SHADOW_RADIUS = 2f;
@Mock private Context mMockContext;
-
+ @Mock private Resources mMockResources;
@Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
-
@Mock private SurfaceControl.Transaction mMockTransaction;
-
@Mock private SurfaceControl.Transaction mMockStartTransaction;
-
@Mock private SurfaceControl.Transaction mMockFinishTransaction;
-
@Mock private Runnable mMockStartCallback;
-
@Mock private Runnable mMockEndCallback;
+ @Captor private ArgumentCaptor<Matrix> mArgumentCaptor;
+
private PipResizeAnimator mPipResizeAnimator;
private Rect mBaseBounds;
private Rect mStartBounds;
private Rect mEndBounds;
private SurfaceControl mTestLeash;
- private ArgumentCaptor<Matrix> mArgumentCaptor;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mMockFactory.getTransaction()).thenReturn(mMockTransaction);
- when(mMockTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
- .thenReturn(mMockTransaction);
- when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
- .thenReturn(mMockStartTransaction);
- when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
- .thenReturn(mMockFinishTransaction);
-
- mArgumentCaptor = ArgumentCaptor.forClass(Matrix.class);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius))
+ .thenReturn((int) TEST_CORNER_RADIUS);
+ when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius))
+ .thenReturn((int) TEST_SHADOW_RADIUS);
+
+ prepareTransaction(mMockTransaction);
+ prepareTransaction(mMockStartTransaction);
+ prepareTransaction(mMockFinishTransaction);
+
mTestLeash = new SurfaceControl.Builder()
.setContainerLayer()
.setName("PipResizeAnimatorTest")
@@ -187,6 +192,12 @@ public class PipResizeAnimatorTest {
assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+
+ // Check corner and shadow radii were set
+ verify(mMockTransaction, atLeastOnce())
+ .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+ verify(mMockTransaction, atLeastOnce())
+ .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
}
@Test
@@ -237,6 +248,12 @@ public class PipResizeAnimatorTest {
assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+
+ // Check corner and shadow radii were set
+ verify(mMockTransaction, atLeastOnce())
+ .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+ verify(mMockTransaction, atLeastOnce())
+ .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
}
@Test
@@ -272,5 +289,21 @@ public class PipResizeAnimatorTest {
mArgumentCaptor.getValue().getValues(matrix);
assertEquals(matrix[Matrix.MSKEW_X], 0f, FLOAT_COMPARISON_DELTA);
assertEquals(matrix[Matrix.MSKEW_Y], 0f, FLOAT_COMPARISON_DELTA);
+
+ // Check corner and shadow radii were set
+ verify(mMockTransaction, atLeastOnce())
+ .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+ verify(mMockTransaction, atLeastOnce())
+ .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
+ }
+
+ // set up transaction chaining
+ private void prepareTransaction(SurfaceControl.Transaction tx) {
+ when(tx.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+ .thenReturn(tx);
+ when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat()))
+ .thenReturn(tx);
+ when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat()))
+ .thenReturn(tx);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
new file mode 100644
index 000000000000..cab625216236
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip2.phone;
+
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
+import static org.mockito.kotlin.MatchersKt.eq;
+import static org.mockito.kotlin.VerificationKt.times;
+import static org.mockito.kotlin.VerificationKt.verify;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.SurfaceControl;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit test against {@link PipScheduler}
+ */
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+public class PipSchedulerTest {
+ private static final int TEST_RESIZE_DURATION = 1;
+ private static final Rect TEST_STARTING_BOUNDS = new Rect(0, 0, 10, 10);
+ private static final Rect TEST_BOUNDS = new Rect(0, 0, 20, 20);
+
+ @Mock private Context mMockContext;
+ @Mock private Resources mMockResources;
+ @Mock private PipBoundsState mMockPipBoundsState;
+ @Mock private ShellExecutor mMockMainExecutor;
+ @Mock private PipTransitionState mMockPipTransitionState;
+ @Mock private PipTransitionController mMockPipTransitionController;
+ @Mock private Runnable mMockUpdateMovementBoundsRunnable;
+ @Mock private WindowContainerToken mMockPipTaskToken;
+ @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
+ @Mock private SurfaceControl.Transaction mMockTransaction;
+ @Mock private PipAlphaAnimator mMockAlphaAnimator;
+
+ @Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
+ @Captor private ArgumentCaptor<WindowContainerTransaction> mWctArgumentCaptor;
+
+ private PipScheduler mPipScheduler;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockResources.getInteger(anyInt())).thenReturn(0);
+ when(mMockPipBoundsState.getBounds()).thenReturn(TEST_STARTING_BOUNDS);
+ when(mMockFactory.getTransaction()).thenReturn(mMockTransaction);
+ when(mMockTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+ .thenReturn(mMockTransaction);
+
+ mPipScheduler = new PipScheduler(mMockContext, mMockPipBoundsState, mMockMainExecutor,
+ mMockPipTransitionState);
+ mPipScheduler.setPipTransitionController(mMockPipTransitionController);
+ mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory);
+ mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, tx, direction) ->
+ mMockAlphaAnimator);
+
+ SurfaceControl testLeash = new SurfaceControl.Builder()
+ .setContainerLayer()
+ .setName("PipSchedulerTest")
+ .setCallsite("PipSchedulerTest")
+ .build();
+ when(mMockPipTransitionState.getPinnedTaskLeash()).thenReturn(testLeash);
+ }
+
+ @Test
+ public void scheduleExitPipViaExpand_nullTaskToken_noop() {
+ setNullPipTaskToken();
+
+ mPipScheduler.scheduleExitPipViaExpand();
+
+ verify(mMockMainExecutor, never()).execute(any());
+ }
+
+ @Test
+ public void scheduleExitPipViaExpand_exitTransitionCalled() {
+ setMockPipTaskToken();
+
+ mPipScheduler.scheduleExitPipViaExpand();
+
+ verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
+ assertNotNull(mRunnableArgumentCaptor.getValue());
+ mRunnableArgumentCaptor.getValue().run();
+
+ verify(mMockPipTransitionController, times(1))
+ .startExitTransition(eq(TRANSIT_EXIT_PIP), any(), isNull());
+ }
+
+ @Test
+ public void removePipAfterAnimation() {
+ //TODO: Update once this is changed to run animation as part of transition
+ setMockPipTaskToken();
+
+ mPipScheduler.removePipAfterAnimation();
+ verify(mMockAlphaAnimator, times(1))
+ .setAnimationEndCallback(mRunnableArgumentCaptor.capture());
+ assertNotNull(mRunnableArgumentCaptor.getValue());
+ verify(mMockAlphaAnimator, times(1)).start();
+
+ mRunnableArgumentCaptor.getValue().run();
+
+ verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
+ assertNotNull(mRunnableArgumentCaptor.getValue());
+
+ mRunnableArgumentCaptor.getValue().run();
+
+ verify(mMockPipTransitionController, times(1))
+ .startExitTransition(eq(TRANSIT_REMOVE_PIP), any(), isNull());
+ }
+
+ @Test
+ public void scheduleAnimateResizePip_bounds_nullTaskToken_noop() {
+ setNullPipTaskToken();
+
+ mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS);
+
+ verify(mMockPipTransitionController, never()).startResizeTransition(any(), anyInt());
+ }
+
+ @Test
+ public void scheduleAnimateResizePip_boundsConfig_nullTaskToken_noop() {
+ setNullPipTaskToken();
+
+ mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS, true);
+
+ verify(mMockPipTransitionController, never()).startResizeTransition(any(), anyInt());
+ }
+
+ @Test
+ public void scheduleAnimateResizePip_boundsConfig_setsConfigAtEnd() {
+ setMockPipTaskToken();
+ when(mMockPipTransitionState.isInPip()).thenReturn(true);
+
+ mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS, true);
+
+ verify(mMockPipTransitionController, times(1))
+ .startResizeTransition(mWctArgumentCaptor.capture(), anyInt());
+ assertNotNull(mWctArgumentCaptor.getValue());
+ assertNotNull(mWctArgumentCaptor.getValue().getChanges());
+ boolean hasConfigAtEndChange = false;
+ for (WindowContainerTransaction.Change change :
+ mWctArgumentCaptor.getValue().getChanges().values()) {
+ if (change.getConfigAtTransitionEnd()) {
+ hasConfigAtEndChange = true;
+ break;
+ }
+ }
+ assertTrue(hasConfigAtEndChange);
+ }
+
+ @Test
+ public void scheduleAnimateResizePip_boundsConfigDuration_nullTaskToken_noop() {
+ setNullPipTaskToken();
+
+ mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS, true, TEST_RESIZE_DURATION);
+
+ verify(mMockPipTransitionController, never()).startResizeTransition(any(), anyInt());
+ }
+
+ @Test
+ public void scheduleAnimateResizePip_notInPip_noop() {
+ setMockPipTaskToken();
+ when(mMockPipTransitionState.isInPip()).thenReturn(false);
+
+ mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS, true, TEST_RESIZE_DURATION);
+
+ verify(mMockPipTransitionController, never()).startResizeTransition(any(), anyInt());
+ }
+
+ @Test
+ public void scheduleAnimateResizePip_resizeTransition() {
+ setMockPipTaskToken();
+ when(mMockPipTransitionState.isInPip()).thenReturn(true);
+
+ mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS, true, TEST_RESIZE_DURATION);
+
+ verify(mMockPipTransitionController, times(1))
+ .startResizeTransition(any(), eq(TEST_RESIZE_DURATION));
+ }
+
+ @Test
+ public void scheduleUserResizePip_emptyBounds_noop() {
+ setMockPipTaskToken();
+
+ mPipScheduler.scheduleUserResizePip(new Rect());
+
+ verify(mMockTransaction, never()).apply();
+ }
+
+ @Test
+ public void scheduleUserResizePip_rotation_emptyBounds_noop() {
+ setMockPipTaskToken();
+
+ mPipScheduler.scheduleUserResizePip(new Rect(), 90);
+
+ verify(mMockTransaction, never()).apply();
+ }
+
+ @Test
+ public void scheduleUserResizePip_applyTransaction() {
+ setMockPipTaskToken();
+
+ mPipScheduler.scheduleUserResizePip(TEST_BOUNDS, 90);
+
+ verify(mMockTransaction, times(1)).apply();
+ }
+
+ @Test
+ public void finishResize_movementBoundsRunnableCalled() {
+ mPipScheduler.setUpdateMovementBoundsRunnable(mMockUpdateMovementBoundsRunnable);
+ mPipScheduler.scheduleFinishResizePip(TEST_BOUNDS);
+
+ verify(mMockUpdateMovementBoundsRunnable, times(1)).run();
+ }
+
+ private void setNullPipTaskToken() {
+ when(mMockPipTransitionState.getPipTaskToken()).thenReturn(null);
+ }
+
+ private void setMockPipTaskToken() {
+ when(mMockPipTransitionState.getPipTaskToken()).thenReturn(mMockPipTaskToken);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
index 2b30bc360d06..fd3adabfd44b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
@@ -176,6 +176,30 @@ class GroupedTaskInfoTest : ShellTestCase() {
assertThat(recentTaskInfoParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray())
}
+ @Test
+ fun testGetTaskById_singleTasks() {
+ val task1 = createTaskInfo(id = 1234)
+
+ val taskInfo = GroupedTaskInfo.forFullscreenTasks(task1)
+
+ assertThat(taskInfo.getTaskById(1234)).isEqualTo(task1)
+ assertThat(taskInfo.containsTask(1234)).isTrue()
+ }
+
+ @Test
+ fun testGetTaskById_multipleTasks() {
+ val task1 = createTaskInfo(id = 1)
+ val task2 = createTaskInfo(id = 2)
+ val splitBounds = SplitBounds(Rect(), Rect(), 1, 2, SNAP_TO_2_50_50)
+
+ val taskInfo = GroupedTaskInfo.forSplitTasks(task1, task2, splitBounds)
+
+ assertThat(taskInfo.getTaskById(1)).isEqualTo(task1)
+ assertThat(taskInfo.getTaskById(2)).isEqualTo(task2)
+ assertThat(taskInfo.containsTask(1)).isTrue()
+ assertThat(taskInfo.containsTask(2)).isTrue()
+ }
+
private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply {
taskId = id
token = WindowContainerToken(mock(IWindowContainerToken::class.java))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index dede583ca970..68c8aab8849d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.launcher3.Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL;
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
@@ -51,6 +52,7 @@ import android.app.ActivityTaskManager;
import android.app.KeyguardManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
@@ -72,6 +74,7 @@ import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
import com.android.wm.shell.shared.GroupedTaskInfo;
import com.android.wm.shell.shared.ShellSharedConstants;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -237,6 +240,19 @@ public class RecentTasksControllerTest extends ShellTestCase {
t3.taskId, -1);
}
+ @EnableFlags(FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL)
+ @Test
+ public void testGetRecentTasks_removesDesktopWallpaperActivity() {
+ RecentTaskInfo t1 = makeTaskInfo(1);
+ RecentTaskInfo desktopWallpaperTaskInfo = makeDesktopWallpaperTaskInfo(2);
+ RecentTaskInfo t3 = makeTaskInfo(3);
+ setRawList(t1, desktopWallpaperTaskInfo, t3);
+
+ ArrayList<GroupedTaskInfo> recentTasks =
+ mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+ assertGroupedTasksListEquals(recentTasks, t1.taskId, -1, t3.taskId, -1);
+ }
+
@Test
public void testGetRecentTasks_withPairs() {
RecentTaskInfo t1 = makeTaskInfo(1);
@@ -610,7 +626,7 @@ public class RecentTasksControllerTest extends ShellTestCase {
mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo);
GroupedTaskInfo runningTask = GroupedTaskInfo.forFullscreenTasks(taskInfo);
- verify(mRecentTasksListener).onTaskMovedToFront(eq(new GroupedTaskInfo[] { runningTask }));
+ verify(mRecentTasksListener).onTaskMovedToFront(eq(runningTask));
}
@Test
@@ -656,17 +672,60 @@ public class RecentTasksControllerTest extends ShellTestCase {
assertEquals(splitBounds4, pair2Bounds);
}
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ public void shellTopTaskTracker_onTaskStackChanged_expectNoRecentsChanged() throws Exception {
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+ mRecentTasksControllerReal.onTaskStackChanged();
+ verify(mRecentTasksListener, never()).onRecentTasksChanged();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ public void shellTopTaskTracker_onTaskRemoved_expectNoRecentsChanged() throws Exception {
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+ ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.onTaskRemoved(taskInfo);
+ verify(mRecentTasksListener, never()).onRecentTasksChanged();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ public void shellTopTaskTracker_onVisibleTasksChanged() throws Exception {
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+ ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.onVisibleTasksChanged(List.of(taskInfo));
+ verify(mRecentTasksListener, never()).onVisibleTasksChanged(any());
+ }
+
/**
* Helper to create a task with a given task id.
*/
private RecentTaskInfo makeTaskInfo(int taskId) {
RecentTaskInfo info = new RecentTaskInfo();
info.taskId = taskId;
+
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName("com." + taskId, "Activity" + taskId));
+ info.baseIntent = intent;
+
info.lastNonFullscreenBounds = new Rect();
return info;
}
/**
+ * Helper to create a desktop wallpaper activity with a given task id.
+ */
+ private RecentTaskInfo makeDesktopWallpaperTaskInfo(int taskId) {
+ RecentTaskInfo info = makeTaskInfo(taskId);
+ info.baseIntent.setComponent(DesktopWallpaperActivity.getWallpaperActivityComponent());
+ return info;
+ }
+
+ /**
* Helper to create a running task with a given task id.
*/
private ActivityManager.RunningTaskInfo makeRunningTaskInfo(int taskId) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
index 6087763b4978..f0f5fe159069 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
@@ -16,7 +16,16 @@
package com.android.wm.shell.recents;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_ANIMATING;
+import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING;
+import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_START_RECENTS_TRANSITION;
+
+import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
@@ -27,6 +36,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IApplicationThread;
import android.app.KeyguardManager;
@@ -38,7 +48,10 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -47,6 +60,7 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.os.IResultReceiver;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -56,7 +70,9 @@ import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.HomeTransitionObserver;
+import com.android.wm.shell.transition.TransitionInfoBuilder;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.util.StubTransaction;
import org.junit.After;
import org.junit.Before;
@@ -93,6 +109,8 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
private IRecentTasksListener mRecentTasksListener;
@Mock
private TaskStackTransitionObserver mTaskStackTransitionObserver;
+ @Mock
+ private Transitions mTransitions;
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -129,10 +147,9 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController),
mMainExecutor);
- final Transitions transitions = mock(Transitions.class);
- doReturn(mMainExecutor).when(transitions).getMainExecutor();
+ doReturn(mMainExecutor).when(mTransitions).getMainExecutor();
mRecentsTransitionHandler = new RecentsTransitionHandler(mShellInit, mShellTaskOrganizer,
- transitions, mRecentTasksController, mock(HomeTransitionObserver.class));
+ mTransitions, mRecentTasksController, mock(HomeTransitionObserver.class));
mShellInit.init();
}
@@ -146,12 +163,8 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
public void testStartSyntheticRecentsTransition_callsOnAnimationStartAndFinishCallback() throws Exception {
final IRecentsAnimationRunner runner = mock(IRecentsAnimationRunner.class);
final IResultReceiver finishCallback = mock(IResultReceiver.class);
- doReturn(new Binder()).when(runner).asBinder();
- Bundle options = new Bundle();
- options.putBoolean("is_synthetic_recents_transition", true);
- IBinder transition = mRecentsTransitionHandler.startRecentsTransition(
- mock(PendingIntent.class), new Intent(), options, mock(IApplicationThread.class),
- runner);
+
+ final IBinder transition = startRecentsTransition(/* synthetic= */ true, runner);
verify(runner).onAnimationStart(any(), any(), any(), any(), any(), any());
// Finish and verify no transition remains and that the provided finish callback is called
@@ -165,12 +178,8 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
@Test
public void testStartSyntheticRecentsTransition_callsOnAnimationCancel() throws Exception {
final IRecentsAnimationRunner runner = mock(IRecentsAnimationRunner.class);
- doReturn(new Binder()).when(runner).asBinder();
- Bundle options = new Bundle();
- options.putBoolean("is_synthetic_recents_transition", true);
- IBinder transition = mRecentsTransitionHandler.startRecentsTransition(
- mock(PendingIntent.class), new Intent(), options, mock(IApplicationThread.class),
- runner);
+
+ final IBinder transition = startRecentsTransition(/* synthetic= */ true, runner);
verify(runner).onAnimationStart(any(), any(), any(), any(), any(), any());
mRecentsTransitionHandler.findController(transition).cancel("test");
@@ -178,4 +187,137 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
verify(runner).onAnimationCanceled(any(), any());
assertNull(mRecentsTransitionHandler.findController(transition));
}
+
+ @Test
+ public void testStartTransition_updatesStateListeners() {
+ final TestTransitionStateListener listener = new TestTransitionStateListener();
+ mRecentsTransitionHandler.addTransitionStateListener(listener);
+
+ startRecentsTransition(/* synthetic= */ false);
+ mMainExecutor.flushAll();
+
+ assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_REQUESTED);
+ }
+
+ @Test
+ public void testStartAnimation_updatesStateListeners() {
+ final TestTransitionStateListener listener = new TestTransitionStateListener();
+ mRecentsTransitionHandler.addTransitionStateListener(listener);
+
+ final IBinder transition = startRecentsTransition(/* synthetic= */ false);
+ mRecentsTransitionHandler.startAnimation(
+ transition, createTransitionInfo(), new StubTransaction(), new StubTransaction(),
+ mock(Transitions.TransitionFinishCallback.class));
+ mMainExecutor.flushAll();
+
+ assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_ANIMATING);
+ }
+
+ @Test
+ public void testFinishTransition_updatesStateListeners() {
+ final TestTransitionStateListener listener = new TestTransitionStateListener();
+ mRecentsTransitionHandler.addTransitionStateListener(listener);
+
+ final IBinder transition = startRecentsTransition(/* synthetic= */ false);
+ mRecentsTransitionHandler.startAnimation(
+ transition, createTransitionInfo(), new StubTransaction(), new StubTransaction(),
+ mock(Transitions.TransitionFinishCallback.class));
+ mRecentsTransitionHandler.findController(transition).finish(true /* toHome */,
+ false /* sendUserLeaveHint */, mock(IResultReceiver.class));
+ mMainExecutor.flushAll();
+
+ assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
+ }
+
+ @Test
+ public void testCancelTransition_updatesStateListeners() {
+ final TestTransitionStateListener listener = new TestTransitionStateListener();
+ mRecentsTransitionHandler.addTransitionStateListener(listener);
+
+ final IBinder transition = startRecentsTransition(/* synthetic= */ false);
+ mRecentsTransitionHandler.findController(transition).cancel("test");
+ mMainExecutor.flushAll();
+
+ assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
+ }
+
+ @Test
+ public void testStartAnimation_synthetic_updatesStateListeners() {
+ final TestTransitionStateListener listener = new TestTransitionStateListener();
+ mRecentsTransitionHandler.addTransitionStateListener(listener);
+
+ startRecentsTransition(/* synthetic= */ true);
+ mMainExecutor.flushAll();
+
+ assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_ANIMATING);
+ }
+
+ @Test
+ public void testFinishTransition_synthetic_updatesStateListeners() {
+ final TestTransitionStateListener listener = new TestTransitionStateListener();
+ mRecentsTransitionHandler.addTransitionStateListener(listener);
+
+ final IBinder transition = startRecentsTransition(/* synthetic= */ true);
+ mRecentsTransitionHandler.findController(transition).finish(true /* toHome */,
+ false /* sendUserLeaveHint */, mock(IResultReceiver.class));
+ mMainExecutor.flushAll();
+
+ assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
+ }
+
+ @Test
+ public void testCancelTransition_synthetic_updatesStateListeners() {
+ final TestTransitionStateListener listener = new TestTransitionStateListener();
+ mRecentsTransitionHandler.addTransitionStateListener(listener);
+
+ final IBinder transition = startRecentsTransition(/* synthetic= */ true);
+ mRecentsTransitionHandler.findController(transition).cancel("test");
+ mMainExecutor.flushAll();
+
+ assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
+ }
+
+ private IBinder startRecentsTransition(boolean synthetic) {
+ return startRecentsTransition(synthetic, mock(IRecentsAnimationRunner.class));
+ }
+
+ private IBinder startRecentsTransition(boolean synthetic,
+ @NonNull IRecentsAnimationRunner runner) {
+ doReturn(new Binder()).when(runner).asBinder();
+ final Bundle options = new Bundle();
+ options.putBoolean("is_synthetic_recents_transition", synthetic);
+ final IBinder transition = new Binder();
+ when(mTransitions.startTransition(anyInt(), any(), any())).thenReturn(transition);
+ return mRecentsTransitionHandler.startRecentsTransition(
+ mock(PendingIntent.class), new Intent(), options, mock(IApplicationThread.class),
+ runner);
+ }
+
+ private TransitionInfo createTransitionInfo() {
+ final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
+ .setTopActivityType(ACTIVITY_TYPE_HOME)
+ .build();
+ final TransitionInfo.Change homeChange = new TransitionInfo.Change(
+ task.token, new SurfaceControl());
+ homeChange.setMode(TRANSIT_TO_FRONT);
+ homeChange.setTaskInfo(task);
+ return new TransitionInfoBuilder(TRANSIT_START_RECENTS_TRANSITION)
+ .addChange(homeChange)
+ .build();
+ }
+
+ private static class TestTransitionStateListener implements RecentsTransitionStateListener {
+ @RecentsTransitionState
+ private int mState = TRANSITION_STATE_NOT_RUNNING;
+
+ @Override
+ public void onTransitionStateChanged(int state) {
+ mState = state;
+ }
+
+ @RecentsTransitionState
+ int getState() {
+ return mState;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
index efe4fb18f273..99194620c313 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
@@ -16,21 +16,36 @@
package com.android.wm.shell.recents
-import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.TaskInfo
import android.app.WindowConfiguration
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
+import android.content.ComponentName
+import android.content.Intent
import android.os.IBinder
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.view.SurfaceControl
import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TRANSIT_CLOSE
+import android.view.WindowManager.TRANSIT_FIRST_CUSTOM
+import android.view.WindowManager.TRANSIT_OPEN
+import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.IWindowContainerToken
import android.window.TransitionInfo
+import android.window.TransitionInfo.FLAG_MOVED_TO_TOP
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
import com.android.window.flags.Flags
+import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.TestSyncExecutor
import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.TransitionInfoBuilder
import com.android.wm.shell.transition.Transitions
@@ -61,7 +76,10 @@ class TaskStackTransitionObserverTest {
@JvmField @Rule val setFlagsRule = SetFlagsRule()
@Mock private lateinit var shellInit: ShellInit
- @Mock lateinit var testExecutor: ShellExecutor
+ @Mock private lateinit var shellTaskOrganizerLazy: Lazy<ShellTaskOrganizer>
+ @Mock private lateinit var shellTaskOrganizer: ShellTaskOrganizer
+ @Mock private lateinit var shellCommandHandler: ShellCommandHandler
+ @Mock private lateinit var testExecutor: ShellExecutor
@Mock private lateinit var transitionsLazy: Lazy<Transitions>
@Mock private lateinit var transitions: Transitions
@Mock private lateinit var mockTransitionBinder: IBinder
@@ -73,24 +91,23 @@ class TaskStackTransitionObserverTest {
MockitoAnnotations.initMocks(this)
shellInit = Mockito.spy(ShellInit(testExecutor))
whenever(transitionsLazy.get()).thenReturn(transitions)
- transitionObserver = TaskStackTransitionObserver(transitionsLazy, shellInit)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
- verify(shellInit)
- .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
- initRunnableCaptor.value.run()
- } else {
- transitionObserver.onInit()
- }
+ whenever(shellTaskOrganizerLazy.get()).thenReturn(shellTaskOrganizer)
+ transitionObserver = TaskStackTransitionObserver(shellInit, shellTaskOrganizerLazy,
+ shellCommandHandler, transitionsLazy)
+
+ val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+ verify(shellInit)
+ .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+ initRunnableCaptor.value.run()
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun testRegistersObserverAtInit() {
verify(transitions).registerObserver(same(transitionObserver))
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun taskCreated_freeformWindow_listenerNotified() {
val listener = TestListener()
@@ -98,11 +115,11 @@ class TaskStackTransitionObserverTest {
transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
val change =
createChange(
- WindowManager.TRANSIT_OPEN,
+ TRANSIT_OPEN,
createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val transitionInfo =
- TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+ TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
callOnTransitionReady(transitionInfo)
callOnTransitionFinished()
@@ -114,6 +131,7 @@ class TaskStackTransitionObserverTest {
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun taskCreated_fullscreenWindow_listenerNotified() {
val listener = TestListener()
@@ -121,11 +139,11 @@ class TaskStackTransitionObserverTest {
transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
val change =
createChange(
- WindowManager.TRANSIT_OPEN,
- createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+ TRANSIT_OPEN,
+ createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
)
val transitionInfo =
- TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+ TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
callOnTransitionReady(transitionInfo)
callOnTransitionFinished()
@@ -133,10 +151,11 @@ class TaskStackTransitionObserverTest {
assertThat(listener.taskInfoOnTaskMovedToFront.taskId).isEqualTo(1)
assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode)
- .isEqualTo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+ .isEqualTo(WINDOWING_MODE_FULLSCREEN)
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun taskCreated_freeformWindowOnTopOfFreeform_listenerNotified() {
val listener = TestListener()
@@ -144,7 +163,7 @@ class TaskStackTransitionObserverTest {
transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
val freeformOpenChange =
createChange(
- WindowManager.TRANSIT_OPEN,
+ TRANSIT_OPEN,
createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val freeformReorderChange =
@@ -153,7 +172,7 @@ class TaskStackTransitionObserverTest {
createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val transitionInfo =
- TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0)
+ TransitionInfoBuilder(TRANSIT_OPEN, 0)
.addChange(freeformOpenChange)
.addChange(freeformReorderChange)
.build()
@@ -169,6 +188,7 @@ class TaskStackTransitionObserverTest {
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun transitionMerged_withChange_onlyOpenChangeIsNotified() {
val listener = TestListener()
@@ -178,11 +198,11 @@ class TaskStackTransitionObserverTest {
// Create open transition
val change =
createChange(
- WindowManager.TRANSIT_OPEN,
+ TRANSIT_OPEN,
createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val transitionInfo =
- TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+ TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
// create change transition to be merged to above transition
val mergedChange =
@@ -212,6 +232,7 @@ class TaskStackTransitionObserverTest {
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun transitionMerged_withOpen_lastOpenChangeIsNotified() {
val listener = TestListener()
@@ -221,20 +242,20 @@ class TaskStackTransitionObserverTest {
// Create open transition
val change =
createChange(
- WindowManager.TRANSIT_OPEN,
+ TRANSIT_OPEN,
createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val transitionInfo =
- TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+ TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
// create change transition to be merged to above transition
val mergedChange =
createChange(
- WindowManager.TRANSIT_OPEN,
+ TRANSIT_OPEN,
createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val mergedTransitionInfo =
- TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(mergedChange).build()
+ TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(mergedChange).build()
val mergedTransition = Mockito.mock(IBinder::class.java)
callOnTransitionReady(transitionInfo)
@@ -250,6 +271,7 @@ class TaskStackTransitionObserverTest {
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun taskChange_freeformWindowToFullscreenWindow_listenerNotified() {
val listener = TestListener()
@@ -257,11 +279,11 @@ class TaskStackTransitionObserverTest {
transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
val freeformState =
createChange(
- WindowManager.TRANSIT_OPEN,
+ TRANSIT_OPEN,
createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val transitionInfoOpen =
- TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(freeformState).build()
+ TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(freeformState).build()
callOnTransitionReady(transitionInfoOpen)
callOnTransitionFinished()
executor.flushAll()
@@ -276,7 +298,7 @@ class TaskStackTransitionObserverTest {
val fullscreenState =
createChange(
WindowManager.TRANSIT_CHANGE,
- createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+ createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
)
val transitionInfoChange =
TransitionInfoBuilder(WindowManager.TRANSIT_CHANGE, 0)
@@ -301,6 +323,7 @@ class TaskStackTransitionObserverTest {
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun singleTransition_withOpenAndChange_onlyOpenIsNotified() {
val listener = TestListener()
@@ -310,13 +333,13 @@ class TaskStackTransitionObserverTest {
// Creating multiple changes to be fired in a single transition
val freeformState =
createChange(
- mode = WindowManager.TRANSIT_OPEN,
+ mode = TRANSIT_OPEN,
taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
)
val fullscreenState =
createChange(
mode = WindowManager.TRANSIT_CHANGE,
- taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+ taskInfo = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
)
val transitionInfoWithChanges =
@@ -336,6 +359,7 @@ class TaskStackTransitionObserverTest {
}
@Test
+ @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
fun singleTransition_withMultipleChanges_listenerNotified_forEachChange() {
val listener = TestListener()
@@ -349,7 +373,7 @@ class TaskStackTransitionObserverTest {
listOf(
WindowConfiguration.WINDOWING_MODE_FREEFORM,
WindowConfiguration.WINDOW_CONFIG_DISPLAY_ROTATION,
- WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+ WINDOWING_MODE_FULLSCREEN
)
.map { change ->
createChange(
@@ -376,19 +400,259 @@ class TaskStackTransitionObserverTest {
}
}
- class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener {
- var taskInfoOnTaskMovedToFront = ActivityManager.RunningTaskInfo()
- var taskInfoOnTaskChanged = mutableListOf<ActivityManager.RunningTaskInfo>()
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ fun openTransition_visibleTasksChanged() {
+ val listener = TestListener()
+ val executor = TestSyncExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+ // Model an opening task
+ val firstOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(firstOpeningTransition)
+ callOnTransitionFinished()
+ // Assert that the task is reported visible
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+ assertVisibleTasks(listener, listOf(1))
+
+ // Model opening another task
+ val nextOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN),
+ createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(nextOpeningTransition)
+ // Assert that the visible list from top to bottom is valid (opening, closing)
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+ assertVisibleTasks(listener, listOf(2, 1))
+
+ callOnTransitionFinished()
+ // Assert that after the transition finishes, there is only the opening task remaining
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(3)
+ assertVisibleTasks(listener, listOf(2))
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ fun toFrontTransition_visibleTasksChanged() {
+ val listener = TestListener()
+ val executor = TestSyncExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+ // Model an opening task
+ val firstOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(firstOpeningTransition)
+ callOnTransitionFinished()
+ // Assert that the task is reported visible
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+ assertVisibleTasks(listener, listOf(1))
+
+ // Model opening another task
+ val nextOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(nextOpeningTransition)
+ callOnTransitionFinished()
+ // Assert that the visible list from top to bottom is valid
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+ assertVisibleTasks(listener, listOf(2, 1))
+
+ // Model the first task moving to front
+ val toFrontTransition =
+ createTransitionInfo(TRANSIT_TO_FRONT,
+ listOf(
+ createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN,
+ FLAG_MOVED_TO_TOP),
+ )
+ )
+
+ callOnTransitionReady(toFrontTransition)
+ callOnTransitionFinished()
+ // Assert that the visible list from top to bottom is valid
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(3)
+ assertVisibleTasks(listener, listOf(1, 2))
+ }
- override fun onTaskMovedToFrontThroughTransition(
- taskInfo: ActivityManager.RunningTaskInfo
- ) {
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ fun closeTransition_visibleTasksChanged() {
+ val listener = TestListener()
+ val executor = TestSyncExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+ // Model an opening task
+ val firstOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(firstOpeningTransition)
+ callOnTransitionFinished()
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+
+ // Model a closing task
+ val nextOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(nextOpeningTransition)
+ // Assert that the visible list hasn't changed (the close is pending)
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+
+ callOnTransitionFinished()
+ // Assert that after the transition finishes, there is only the opening task remaining
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+ assertVisibleTasks(listener, listOf())
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ fun changeTransition_visibleTasksUnchanged() {
+ val listener = TestListener()
+ val executor = TestSyncExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+ // Model an opening task
+ val firstOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(firstOpeningTransition)
+ callOnTransitionFinished()
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+
+ // Model a closing task
+ val nextOpeningTransition =
+ createTransitionInfo(
+ TRANSIT_FIRST_CUSTOM,
+ listOf(
+ createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(nextOpeningTransition)
+ // Assert that the visible list hasn't changed
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ fun taskVanished_visibleTasksChanged() {
+ val listener = TestListener()
+ val executor = TestSyncExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+ // Model an opening task
+ val firstOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(firstOpeningTransition)
+ callOnTransitionFinished()
+ // Assert that the task is reported visible
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+ assertVisibleTasks(listener, listOf(1))
+
+ // Trigger task vanished
+ val removedTaskInfo = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
+ transitionObserver.onTaskVanished(removedTaskInfo)
+
+ // Assert that the visible list is now empty
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+ assertVisibleTasks(listener, listOf())
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+ fun alwaysOnTop_taskIsTopMostVisible() {
+ val listener = TestListener()
+ val executor = TestSyncExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+ // Model an opening PIP task
+ val pipOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_PINNED),
+ )
+ )
+
+ callOnTransitionReady(pipOpeningTransition)
+ callOnTransitionFinished()
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+ assertVisibleTasks(listener, listOf(1))
+
+ // Model an opening fullscreen task
+ val firstOpeningTransition =
+ createTransitionInfo(TRANSIT_OPEN,
+ listOf(
+ createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN),
+ )
+ )
+
+ callOnTransitionReady(firstOpeningTransition)
+ callOnTransitionFinished()
+ assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+ assertVisibleTasks(listener, listOf(1, 2))
+ }
+
+ class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener {
+ // Only used if FLAG_ENABLE_SHELL_TOP_TASK_TRACKING is disabled
+ var taskInfoOnTaskMovedToFront = RunningTaskInfo()
+ var taskInfoOnTaskChanged = mutableListOf<RunningTaskInfo>()
+ // Only used if FLAG_ENABLE_SHELL_TOP_TASK_TRACKING is enabled
+ var visibleTasks = mutableListOf<TaskInfo>()
+ var visibleTasksUpdatedCount = 0
+
+ override fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {
taskInfoOnTaskMovedToFront = taskInfo
}
- override fun onTaskChangedThroughTransition(taskInfo: ActivityManager.RunningTaskInfo) {
+ override fun onTaskChangedThroughTransition(taskInfo: RunningTaskInfo) {
taskInfoOnTaskChanged += taskInfo
}
+
+ override fun onVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) {
+ this.visibleTasks.clear()
+ this.visibleTasks.addAll(visibleTasks)
+ visibleTasksUpdatedCount++
+ }
}
/** Simulate calling the onTransitionReady() method */
@@ -412,27 +676,64 @@ class TaskStackTransitionObserverTest {
transitionObserver.onTransitionMerged(merged, playing)
}
+ /**
+ * Asserts that the listener has the given expected task ids (in order).
+ */
+ private fun assertVisibleTasks(
+ listener: TestListener,
+ expectedVisibleTaskIds: List<Int>
+ ) {
+ assertThat(listener.visibleTasks.size).isEqualTo(expectedVisibleTaskIds.size)
+ expectedVisibleTaskIds.forEachIndexed { index, taskId ->
+ assertThat(listener.visibleTasks[index].taskId).isEqualTo(taskId)
+ }
+ }
+
companion object {
- fun createTaskInfo(taskId: Int, windowingMode: Int): ActivityManager.RunningTaskInfo {
- val taskInfo = ActivityManager.RunningTaskInfo()
+ fun createTaskInfo(taskId: Int, windowingMode: Int): RunningTaskInfo {
+ val taskInfo = RunningTaskInfo()
+ taskInfo.baseIntent = Intent().setComponent(
+ ComponentName(javaClass.packageName, "Test"))
taskInfo.taskId = taskId
taskInfo.configuration.windowConfiguration.windowingMode = windowingMode
-
+ if (windowingMode == WINDOWING_MODE_PINNED) {
+ taskInfo.configuration.windowConfiguration.isAlwaysOnTop = true
+ }
return taskInfo
}
fun createChange(
mode: Int,
- taskInfo: ActivityManager.RunningTaskInfo
+ taskInfo: RunningTaskInfo,
+ flags: Int = 0,
): TransitionInfo.Change {
val change =
TransitionInfo.Change(
WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java)),
Mockito.mock(SurfaceControl::class.java)
)
+ change.flags = flags
change.mode = mode
change.taskInfo = taskInfo
return change
}
+
+ fun createChange(
+ mode: Int,
+ taskId: Int,
+ windowingMode: Int,
+ flags: Int = 0,
+ ): TransitionInfo.Change {
+ return createChange(mode, createTaskInfo(taskId, windowingMode), flags)
+ }
+
+ fun createTransitionInfo(
+ transitionType: Int,
+ changes: List<TransitionInfo.Change>
+ ): TransitionInfo {
+ return TransitionInfoBuilder(transitionType, 0)
+ .apply { changes.forEach { c -> this@apply.addChange(c) } }
+ .build()
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 966651f19711..72a7a3f5ec99 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -200,10 +201,11 @@ public class SplitScreenControllerTests extends ShellTestCase {
PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
- SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+ SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+ SPLIT_INDEX_0);
verify(mStageCoordinator).startIntent(eq(pendingIntent), mIntentCaptor.capture(),
- eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull());
+ eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull(), eq(SPLIT_INDEX_0));
assertEquals(FLAG_ACTIVITY_NO_USER_ACTION,
mIntentCaptor.getValue().getFlags() & FLAG_ACTIVITY_NO_USER_ACTION);
}
@@ -220,10 +222,11 @@ public class SplitScreenControllerTests extends ShellTestCase {
doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask(any());
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
- SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+ SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+ SPLIT_INDEX_0);
verify(mStageCoordinator).startIntent(eq(pendingIntent), mIntentCaptor.capture(),
- eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull());
+ eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull(), eq(SPLIT_INDEX_0));
assertEquals(FLAG_ACTIVITY_MULTIPLE_TASK,
mIntentCaptor.getValue().getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK);
}
@@ -243,10 +246,11 @@ public class SplitScreenControllerTests extends ShellTestCase {
doReturn(sameTaskInfo).when(mRecentTasks).findTaskInBackground(any(), anyInt(), any());
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
- SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+ SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+ SPLIT_INDEX_0);
verify(mStageCoordinator).startTask(anyInt(), eq(SPLIT_POSITION_TOP_OR_LEFT),
- isNull(), isNull());
+ isNull(), isNull(), eq(SPLIT_INDEX_0));
verify(mMultiInstanceHelper, never()).supportsMultiInstanceSplit(any());
verify(mStageCoordinator, never()).switchSplitPosition(any());
}
@@ -269,10 +273,11 @@ public class SplitScreenControllerTests extends ShellTestCase {
.findTaskInBackground(any(), anyInt(), any());
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
- SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+ SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+ SPLIT_INDEX_0);
verify(mMultiInstanceHelper, never()).supportsMultiInstanceSplit(any());
verify(mStageCoordinator).startTask(anyInt(), eq(SPLIT_POSITION_TOP_OR_LEFT),
- isNull(), isNull());
+ isNull(), isNull(), eq(SPLIT_INDEX_0));
}
@Test
@@ -289,7 +294,8 @@ public class SplitScreenControllerTests extends ShellTestCase {
SPLIT_POSITION_BOTTOM_OR_RIGHT);
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
- SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+ SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+ SPLIT_INDEX_0);
verify(mStageCoordinator).switchSplitPosition(anyString());
}
@@ -301,7 +307,7 @@ public class SplitScreenControllerTests extends ShellTestCase {
PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
- true /* forceLaunchNewTask */);
+ true /* forceLaunchNewTask */, SPLIT_INDEX_0);
verify(mRecentTasks, never()).findTaskInBackground(any(), anyInt(), any());
}
@@ -312,7 +318,7 @@ public class SplitScreenControllerTests extends ShellTestCase {
PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
- false /* forceLaunchNewTask */);
+ false /* forceLaunchNewTask */, SPLIT_INDEX_0);
verify(mRecentTasks).findTaskInBackground(any(), anyInt(), any());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index 66dcef6f14cc..d13a8888edc7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -53,8 +53,8 @@ public class SplitTestUtils {
doReturn(dividerBounds).when(out).getDividerBounds();
doReturn(dividerBounds).when(out).getRefDividerBounds();
doReturn(leash).when(out).getDividerLeash();
- doReturn(bounds1).when(out).getBounds1();
- doReturn(bounds2).when(out).getBounds2();
+ doReturn(bounds1).when(out).getTopLeftBounds();
+ doReturn(bounds2).when(out).getBottomRightBounds();
return out;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index ce3944a5855e..e32cf3899a03 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -27,6 +27,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
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_DRAG_DIVIDER;
@@ -133,11 +134,11 @@ public class SplitTransitionTests extends ShellTestCase {
mSplitLayout = SplitTestUtils.createMockSplitLayout();
mMainStage = spy(new StageTaskListener(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue,
- mIconProvider, Optional.of(mWindowDecorViewModel)));
+ mIconProvider, Optional.of(mWindowDecorViewModel), STAGE_TYPE_MAIN));
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mSideStage = spy(new StageTaskListener(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue,
- mIconProvider, Optional.of(mWindowDecorViewModel)));
+ mIconProvider, Optional.of(mWindowDecorViewModel), STAGE_TYPE_SIDE));
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index a252a9db7095..1e739cd446ae 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -33,6 +34,7 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -140,8 +142,8 @@ public class StageCoordinatorTests extends ShellTestCase {
Optional.empty()));
mDividerLeash = new SurfaceControl.Builder().setName("fakeDivider").build();
- when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
- when(mSplitLayout.getBounds2()).thenReturn(mBounds2);
+ when(mSplitLayout.getTopLeftBounds()).thenReturn(mBounds1);
+ when(mSplitLayout.getBottomRightBounds()).thenReturn(mBounds2);
when(mSplitLayout.getRootBounds()).thenReturn(mRootBounds);
when(mSplitLayout.isLeftRightSplit()).thenReturn(false);
when(mSplitLayout.applyTaskChanges(any(), any(), any())).thenReturn(true);
@@ -165,8 +167,9 @@ public class StageCoordinatorTests extends ShellTestCase {
final WindowContainerTransaction wct = spy(new WindowContainerTransaction());
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ // TODO(b/349828130) Address this once we remove index_undefined called
verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED));
verify(mMainStage).reparentTopTask(eq(wct));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
@@ -183,8 +186,9 @@ public class StageCoordinatorTests extends ShellTestCase {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ // TODO(b/349828130) Address this once we remove index_undefined called
verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
}
@@ -195,8 +199,9 @@ public class StageCoordinatorTests extends ShellTestCase {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ // TODO(b/349828130) Address this once we remove index_undefined called
verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
}
@@ -292,7 +297,8 @@ public class StageCoordinatorTests extends ShellTestCase {
public void testFinishEnterSplitScreen_applySurfaceLayout() {
mStageCoordinator.finishEnterSplitScreen(new SurfaceControl.Transaction());
- verify(mSplitLayout).applySurfaceChanges(any(), any(), any(), any(), any(), eq(false));
+ verify(mSplitLayout, atLeastOnce())
+ .applySurfaceChanges(any(), any(), any(), any(), any(), eq(false));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 7144a1e038f9..fe91440b106f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -19,6 +19,8 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
@@ -93,7 +95,8 @@ public final class StageTaskListenerTests extends ShellTestCase {
mCallbacks,
mSyncQueue,
mIconProvider,
- Optional.of(mWindowDecorViewModel));
+ Optional.of(mWindowDecorViewModel),
+ STAGE_TYPE_UNDEFINED);
mRootTask = new TestRunningTaskInfoBuilder().build();
mRootTask.parentTaskId = INVALID_TASK_ID;
mSurfaceControl = new SurfaceControl.Builder().setName("test").build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index c36b88e34835..71af97e5add3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -43,6 +43,7 @@ import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
+import com.android.wm.shell.TestSyncExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
@@ -475,27 +476,6 @@ public class UnfoldTransitionHandlerTest {
}
}
- private static class TestSyncExecutor implements ShellExecutor {
- @Override
- public void execute(Runnable runnable) {
- runnable.run();
- }
-
- @Override
- public void executeDelayed(Runnable runnable, long delayMillis) {
- runnable.run();
- }
-
- @Override
- public void removeCallbacks(Runnable runnable) {
- }
-
- @Override
- public boolean hasCallback(Runnable runnable) {
- return false;
- }
- }
-
private TransitionInfo createUnfoldTransitionInfo() {
TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt
new file mode 100644
index 000000000000..3e26ee0deed0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.util
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.ComponentName
+import android.content.Intent
+import android.os.IBinder
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.view.WindowManager.TRANSIT_NONE
+import android.view.WindowManager.TransitionFlags
+import android.view.WindowManager.TransitionType
+import android.window.IWindowContainerToken
+import android.window.TransitionInfo
+import android.window.TransitionInfo.Change
+import android.window.TransitionInfo.ChangeFlags
+import android.window.TransitionInfo.FLAG_NONE
+import android.window.TransitionInfo.TransitionMode
+import android.window.WindowContainerToken
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
+import com.android.wm.shell.transition.Transitions.TransitionObserver
+import org.mockito.Mockito
+import org.mockito.kotlin.mock
+
+@DslMarker
+annotation class TransitionObserverTagMarker
+
+/**
+ * Abstraction for all the phases of the [TransitionObserver] test.
+ */
+interface TransitionObserverTestStep
+
+/**
+ * Encapsulates the values for the [TransitionObserver#onTransitionReady] input parameters.
+ */
+class TransitionObserverTransitionReadyInput(
+ val transition: IBinder,
+ val info: TransitionInfo,
+ val startTransaction: Transaction,
+ val finishTransaction: Transaction
+)
+
+@TransitionObserverTagMarker
+class TransitionObserverTestContext : TransitionObserverTestStep {
+
+ lateinit var transitionObserver: TransitionObserver
+ lateinit var transitionReadyInput: TransitionObserverTransitionReadyInput
+
+ fun inputBuilder(builderInput: TransitionObserverInputBuilder.() -> Unit) {
+ val inputFactoryObj = TransitionObserverInputBuilder()
+ inputFactoryObj.builderInput()
+ transitionReadyInput = inputFactoryObj.build()
+ }
+
+ fun validateOutput(
+ validate:
+ TransitionObserverResultValidation.() -> Unit
+ ) {
+ val validateObj = TransitionObserverResultValidation()
+ invokeObservable()
+ validateObj.validate()
+ }
+
+ fun invokeObservable() {
+ transitionObserver.onTransitionReady(
+ transitionReadyInput.transition,
+ transitionReadyInput.info,
+ transitionReadyInput.startTransaction,
+ transitionReadyInput.finishTransaction
+ )
+ }
+}
+
+/**
+ * Phase responsible for the input parameters for [TransitionObserver].
+ */
+class TransitionObserverInputBuilder : TransitionObserverTestStep {
+
+ private val transition = Mockito.mock(IBinder::class.java)
+ private var transitionInfo: TransitionInfo? = null
+ private val startTransaction = Mockito.mock(Transaction::class.java)
+ private val finishTransaction = Mockito.mock(Transaction::class.java)
+
+ fun buildTransitionInfo(
+ @TransitionType type: Int = TRANSIT_NONE,
+ @TransitionFlags flags: Int = 0
+ ) {
+ transitionInfo = TransitionInfo(type, flags)
+ spyOn(transitionInfo)
+ }
+
+ fun addChange(
+ token: WindowContainerToken? = mock(),
+ leash: SurfaceControl = mock(),
+ @TransitionMode changeMode: Int = TRANSIT_NONE,
+ parentToken: WindowContainerToken? = null,
+ changeTaskInfo: RunningTaskInfo? = null,
+ @ChangeFlags changeFlags: Int = FLAG_NONE
+ ) = addChange(Change(token, leash).apply {
+ mode = changeMode
+ parent = parentToken
+ taskInfo = changeTaskInfo
+ flags = changeFlags
+ })
+
+ fun createChange(
+ token: WindowContainerToken? = mock(),
+ leash: SurfaceControl = mock(),
+ @TransitionMode changeMode: Int = TRANSIT_NONE,
+ parentToken: WindowContainerToken? = null,
+ changeTaskInfo: RunningTaskInfo? = null,
+ @ChangeFlags changeFlags: Int = FLAG_NONE
+ ) = Change(token, leash).apply {
+ mode = changeMode
+ parent = parentToken
+ taskInfo = changeTaskInfo
+ flags = changeFlags
+ }
+
+ fun addChange(change: Change) {
+ transitionInfo!!.addChange(change)
+ }
+
+ fun createTaskInfo(id: Int = 0, windowingMode: Int = WINDOWING_MODE_FREEFORM) =
+ RunningTaskInfo().apply {
+ taskId = id
+ displayId = DEFAULT_DISPLAY
+ configuration.windowConfiguration.windowingMode = windowingMode
+ token = WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java))
+ baseIntent = Intent().apply {
+ component = ComponentName("package", "component.name")
+ }
+ }
+
+ fun build(): TransitionObserverTransitionReadyInput = TransitionObserverTransitionReadyInput(
+ transition = transition,
+ info = transitionInfo!!,
+ startTransaction = startTransaction,
+ finishTransaction = finishTransaction
+ )
+}
+
+/**
+ * Phase responsible for the execution of validation methods.
+ */
+class TransitionObserverResultValidation : TransitionObserverTestStep
+
+/**
+ * Allows to run a test about a specific [TransitionObserver] passing the specific
+ * implementation and input value as parameters for the [TransitionObserver#onTransitionReady]
+ * method.
+ * @param observerFactory The Factory for the TransitionObserver
+ * @param inputFactory The Builder for the onTransitionReady input parameters
+ * @param init The test code itself.
+ */
+fun executeTransitionObserverTest(
+ observerFactory: () -> TransitionObserver,
+ init: TransitionObserverTestContext.() -> Unit
+): TransitionObserverTestContext {
+ val testContext = TransitionObserverTestContext().apply {
+ transitionObserver = observerFactory()
+ }
+ testContext.init()
+ return testContext
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt
index 99e82959fcd6..b9d91e7895db 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt
@@ -78,18 +78,18 @@ fun createTaskInfo(
* Any fields without corresponding parameters will retain their default values.
*/
fun createWindowingEducationProto(
- educationViewedTimestampMillis: Long? = null,
- featureUsedTimestampMillis: Long? = null,
+ appHandleHintViewedTimestampMillis: Long? = null,
+ appHandleHintUsedTimestampMillis: Long? = null,
appUsageStats: Map<String, Int>? = null,
appUsageStatsLastUpdateTimestampMillis: Long? = null
): WindowingEducationProto =
WindowingEducationProto.newBuilder()
.apply {
- if (educationViewedTimestampMillis != null) {
- setEducationViewedTimestampMillis(educationViewedTimestampMillis)
+ if (appHandleHintViewedTimestampMillis != null) {
+ setAppHandleHintViewedTimestampMillis(appHandleHintViewedTimestampMillis)
}
- if (featureUsedTimestampMillis != null) {
- setFeatureUsedTimestampMillis(featureUsedTimestampMillis)
+ if (appHandleHintUsedTimestampMillis != null) {
+ setAppHandleHintUsedTimestampMillis(appHandleHintUsedTimestampMillis)
}
setAppHandleEducation(
createAppHandleEducationProto(appUsageStats, appUsageStatsLastUpdateTimestampMillis))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt
new file mode 100644
index 000000000000..a15b61122713
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.windowdecor
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
+import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WindowingMode
+import android.content.ComponentName
+import android.content.pm.ActivityInfo
+import android.platform.test.annotations.EnableFlags
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.SurfaceControl
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.window.flags.Flags
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.times
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.verify
+import org.mockito.quality.Strictness
+
+/**
+ * Tests of [DesktopModeWindowDecorViewModelAppHandleOnlyTest]
+ *
+ * A subset of tests from [DesktopModeWindowDecorViewModel] for when DesktopMode is not active
+ * but we still need to show AppHandle
+ * Usage: atest WMShellUnitTests:DesktopModeWindowDecorViewModelAppHandleOnlyTest
+ */
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@EnableFlags(Flags.FLAG_UNIVERSAL_RESIZABLE_BY_DEFAULT)
+@RunWithLooper
+class DesktopModeWindowDecorViewModelAppHandleOnlyTest :
+ DesktopModeWindowDecorViewModelTestsBase() {
+
+ @Before
+ fun setUp() {
+ mockitoSession =
+ mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java)
+ .spyStatic(DragPositioningCallbackUtility::class.java)
+ .startMocking()
+ doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+ doReturn(true).`when` { DesktopModeStatus.overridesShowAppHandle(any())}
+ setUpCommon()
+ }
+
+ @Test
+ fun testWindowDecor_showAppHandle_decorCreated() {
+ val task = createTask()
+
+ setUpMockDecorationForTask(task)
+
+ onTaskOpening(task)
+ assertTrue(windowDecorByTaskIdSpy.contains(task.taskId))
+ }
+
+ @Test
+ fun testWindowDecor_dontShowAppHandle_decorNotCreated() {
+ // Simulate device that doesn't support showing app handle
+ doReturn(false).`when` { DesktopModeStatus.overridesShowAppHandle(any())}
+
+ val task = createTask()
+
+ onTaskOpening(task)
+ assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
+ }
+
+ @Test
+ fun testDeleteDecorationOnChangeTransitionWhenNecessary() {
+ val task = createTask()
+ val taskSurface = SurfaceControl()
+ val decoration = setUpMockDecorationForTask(task)
+
+ onTaskOpening(task, taskSurface)
+ assertTrue(windowDecorByTaskIdSpy.contains(task.taskId))
+ task.setActivityType(ACTIVITY_TYPE_UNDEFINED)
+ onTaskChanging(task, taskSurface)
+
+ assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
+ verify(decoration).close()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ fun testDecor_invokeOpenHandleMenuCallback_openHandleMenu() {
+ val task = createTask()
+ val decor = setUpMockDecorationForTask(task)
+ val openHandleMenuCallbackCaptor = argumentCaptor<(Int) -> Unit>()
+ // Set task as gmail
+ val gmailPackageName = "com.google.android.gm"
+ val baseComponent = ComponentName(gmailPackageName, /* class */ "")
+ task.baseActivity = baseComponent
+
+ onTaskOpening(task)
+ verify(
+ mockAppHandleEducationController,
+ times(1)
+ ).setAppHandleEducationTooltipCallbacks(openHandleMenuCallbackCaptor.capture(), any())
+ openHandleMenuCallbackCaptor.lastValue.invoke(task.taskId)
+
+ verify(decor, times(1)).createHandleMenu(anyBoolean())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ fun testDecorationIsNotCreatedForSystemUIActivities() {
+ val task = createTask()
+
+ // Set task as systemUI package
+ val systemUIPackageName = context.resources.getString(
+ com.android.internal.R.string.config_systemUi)
+ val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
+ task.baseActivity = baseComponent
+
+ onTaskOpening(task)
+
+ assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
+ }
+
+ @Test
+ fun testAppHandleShowsOnlyOnLargeDisplay() {
+ val task = createTask()
+ val taskSurface = SurfaceControl()
+ setUpMockDecorationForTask(task)
+ onTaskOpening(task, taskSurface)
+ assertTrue(windowDecorByTaskIdSpy.contains(task.taskId))
+
+
+ task.setOnLargeScreen(false)
+ setUpMockDecorationForTask(task)
+ onTaskChanging(task, taskSurface)
+ assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
+ }
+
+ private fun createTask(
+ displayId: Int = DEFAULT_DISPLAY,
+ @WindowingMode windowingMode: Int = WINDOWING_MODE_FULLSCREEN,
+ activityType: Int = ACTIVITY_TYPE_STANDARD,
+ activityInfo: ActivityInfo = ActivityInfo(),
+ requestingImmersive: Boolean = false,
+ shouldShowAspectRatioButton: Boolean = true
+ ): RunningTaskInfo {
+ val task = createTask(
+ displayId, windowingMode, activityType, activityInfo, requestingImmersive)
+ task.setOnLargeScreen(shouldShowAspectRatioButton)
+ return task
+ }
+
+ private fun RunningTaskInfo.setOnLargeScreen(large: Boolean) {
+ configuration.smallestScreenWidthDp = if (large) 1000 else 100
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index be664f86e9f5..b873162e6fe3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -28,31 +28,19 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_MAIN
-import android.content.pm.ActivityInfo
import android.graphics.Rect
import android.graphics.Region
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.hardware.input.InputManager
import android.net.Uri
-import android.os.Handler
import android.os.SystemClock
-import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.CheckFlagsRule
-import android.platform.test.flag.junit.DeviceFlagsValueProvider
-import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
-import android.testing.TestableContext
import android.testing.TestableLooper.RunWithLooper
-import android.util.SparseArray
-import android.view.Choreographer
import android.view.Display.DEFAULT_DISPLAY
import android.view.ISystemGestureExclusionListener
-import android.view.IWindowManager
-import android.view.InputChannel
-import android.view.InputMonitor
import android.view.InsetsSource
import android.view.InsetsState
import android.view.KeyEvent
@@ -63,74 +51,35 @@ import android.view.SurfaceView
import android.view.View
import android.view.ViewRootImpl
import android.view.WindowInsets.Type.statusBars
-import android.widget.Toast
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean
import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.android.dx.mockito.inline.extended.StaticMockitoSession
-import com.android.internal.jank.InteractionJankMonitor
import com.android.window.flags.Flags
import com.android.wm.shell.R
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer
-import com.android.wm.shell.ShellTaskOrganizer
-import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.TestRunningTaskInfoBuilder
-import com.android.wm.shell.TestShellExecutor
-import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser
-import com.android.wm.shell.apptoweb.AssistContentRequester
-import com.android.wm.shell.common.DisplayChangeController
-import com.android.wm.shell.common.DisplayController
-import com.android.wm.shell.common.DisplayInsetsController
-import com.android.wm.shell.common.DisplayLayout
-import com.android.wm.shell.common.MultiInstanceHelper
-import com.android.wm.shell.common.SyncTransactionQueue
-import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
-import com.android.wm.shell.desktopmode.DesktopRepository
-import com.android.wm.shell.desktopmode.DesktopTasksController
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
-import com.android.wm.shell.desktopmode.DesktopTasksLimiter
-import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository
-import com.android.wm.shell.desktopmode.education.AppHandleEducationController
-import com.android.wm.shell.desktopmode.education.AppToWebEducationController
-import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.splitscreen.SplitScreenController
-import com.android.wm.shell.sysui.ShellCommandHandler
-import com.android.wm.shell.sysui.ShellController
-import com.android.wm.shell.sysui.ShellInit
-import com.android.wm.shell.transition.FocusTransitionObserver
-import com.android.wm.shell.transition.Transitions
-import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
-import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
-import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder
-import java.util.Optional
-import java.util.function.Consumer
-import java.util.function.Supplier
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentCaptor.forClass
-import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.kotlin.KArgumentCaptor
-import org.mockito.kotlin.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.argThat
@@ -138,9 +87,10 @@ import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doNothing
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
-import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
+import java.util.function.Consumer
/**
@@ -151,73 +101,7 @@ import org.mockito.quality.Strictness
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
-class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
- @JvmField
- @Rule
- val setFlagsRule = SetFlagsRule()
-
- @JvmField
- @Rule
- val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
-
- @Mock private lateinit var mockDesktopModeWindowDecorFactory:
- DesktopModeWindowDecoration.Factory
- @Mock private lateinit var mockMainHandler: Handler
- @Mock private lateinit var mockMainChoreographer: Choreographer
- @Mock private lateinit var mockTaskOrganizer: ShellTaskOrganizer
- @Mock private lateinit var mockDisplayController: DisplayController
- @Mock private lateinit var mockSplitScreenController: SplitScreenController
- @Mock private lateinit var mockDesktopRepository: DesktopRepository
- @Mock private lateinit var mockDisplayLayout: DisplayLayout
- @Mock private lateinit var displayInsetsController: DisplayInsetsController
- @Mock private lateinit var mockSyncQueue: SyncTransactionQueue
- @Mock private lateinit var mockDesktopTasksController: DesktopTasksController
- @Mock private lateinit var mockInputMonitor: InputMonitor
- @Mock private lateinit var mockTransitions: Transitions
- @Mock private lateinit var mockInputMonitorFactory:
- DesktopModeWindowDecorViewModel.InputMonitorFactory
- @Mock private lateinit var mockShellController: ShellController
- private val testShellExecutor = TestShellExecutor()
- @Mock private lateinit var mockAppHeaderViewHolderFactory: AppHeaderViewHolder.Factory
- @Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
- @Mock private lateinit var mockShellCommandHandler: ShellCommandHandler
- @Mock private lateinit var mockWindowManager: IWindowManager
- @Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
- @Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser
- @Mock private lateinit var mockUserHandle: UserHandle
- @Mock private lateinit var mockAssistContentRequester: AssistContentRequester
- @Mock private lateinit var mockToast: Toast
- private val bgExecutor = TestShellExecutor()
- @Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper
- @Mock private lateinit var mockTasksLimiter: DesktopTasksLimiter
- @Mock private lateinit var mockFreeformTaskTransitionStarter: FreeformTaskTransitionStarter
- @Mock private lateinit var mockActivityOrientationChangeHandler:
- DesktopActivityOrientationChangeHandler
- @Mock private lateinit var mockInputManager: InputManager
- @Mock private lateinit var mockTaskPositionerFactory:
- DesktopModeWindowDecorViewModel.TaskPositionerFactory
- @Mock private lateinit var mockTaskPositioner: TaskPositioner
- @Mock private lateinit var mockAppHandleEducationController: AppHandleEducationController
- @Mock private lateinit var mockAppToWebEducationController: AppToWebEducationController
- @Mock private lateinit var mockFocusTransitionObserver: FocusTransitionObserver
- @Mock private lateinit var mockCaptionHandleRepository: WindowDecorCaptionHandleRepository
- @Mock private lateinit var motionEvent: MotionEvent
- @Mock lateinit var displayController: DisplayController
- @Mock lateinit var displayLayout: DisplayLayout
- private lateinit var spyContext: TestableContext
- private lateinit var desktopModeEventLogger: DesktopModeEventLogger
-
- private val transactionFactory = Supplier<SurfaceControl.Transaction> {
- SurfaceControl.Transaction()
- }
- private val windowDecorByTaskIdSpy = spy(SparseArray<DesktopModeWindowDecoration>())
-
- private lateinit var mockitoSession: StaticMockitoSession
- private lateinit var shellInit: ShellInit
- private lateinit var desktopModeOnInsetsChangedListener: DesktopModeOnInsetsChangedListener
- private lateinit var displayChangingListener: DisplayChangeController.OnDisplayChangingListener
- private lateinit var desktopModeOnKeyguardChangedListener: DesktopModeKeyguardChangeListener
- private lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel
+class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTestsBase() {
@Before
fun setUp() {
@@ -226,102 +110,12 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
.strictness(Strictness.LENIENT)
.spyStatic(DesktopModeStatus::class.java)
.spyStatic(DragPositioningCallbackUtility::class.java)
- .spyStatic(Toast::class.java)
.startMocking()
- doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) }
- spyContext = spy(mContext)
- doNothing().`when`(spyContext).startActivity(any())
- shellInit = ShellInit(testShellExecutor)
- windowDecorByTaskIdSpy.clear()
- spyContext.addMockSystemService(InputManager::class.java, mockInputManager)
- desktopModeEventLogger = mock<DesktopModeEventLogger>()
- desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
- spyContext,
- testShellExecutor,
- mockMainHandler,
- mockMainChoreographer,
- bgExecutor,
- shellInit,
- mockShellCommandHandler,
- mockWindowManager,
- mockTaskOrganizer,
- mockDesktopRepository,
- mockDisplayController,
- mockShellController,
- displayInsetsController,
- mockSyncQueue,
- mockTransitions,
- Optional.of(mockDesktopTasksController),
- mockGenericLinksParser,
- mockAssistContentRequester,
- mockMultiInstanceHelper,
- mockDesktopModeWindowDecorFactory,
- mockInputMonitorFactory,
- transactionFactory,
- mockAppHeaderViewHolderFactory,
- mockRootTaskDisplayAreaOrganizer,
- windowDecorByTaskIdSpy,
- mockInteractionJankMonitor,
- Optional.of(mockTasksLimiter),
- mockAppHandleEducationController,
- mockAppToWebEducationController,
- mockCaptionHandleRepository,
- Optional.of(mockActivityOrientationChangeHandler),
- mockTaskPositionerFactory,
- mockFocusTransitionObserver,
- desktopModeEventLogger
- )
- desktopModeWindowDecorViewModel.setSplitScreenController(mockSplitScreenController)
- whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
- whenever(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS)
- whenever(mockInputMonitorFactory.create(any(), any())).thenReturn(mockInputMonitor)
- whenever(
- mockTaskPositionerFactory.create(
- any(),
- any(),
- any(),
- any(),
- any(),
- any(),
- any(),
- any()
- )
- )
- .thenReturn(mockTaskPositioner)
-
- doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
-
- // InputChannel cannot be mocked because it passes to InputEventReceiver.
- val inputChannels = InputChannel.openInputChannelPair(TAG)
- inputChannels.first().dispose()
- whenever(mockInputMonitor.inputChannel).thenReturn(inputChannels[1])
-
- shellInit.init()
-
- val displayChangingListenerCaptor =
- argumentCaptor<DisplayChangeController.OnDisplayChangingListener>()
- verify(mockDisplayController)
- .addDisplayChangingController(displayChangingListenerCaptor.capture())
- displayChangingListener = displayChangingListenerCaptor.firstValue
- val insetsChangedCaptor =
- argumentCaptor<DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener>()
- verify(displayInsetsController)
- .addGlobalInsetsChangedListener(insetsChangedCaptor.capture())
- desktopModeOnInsetsChangedListener = insetsChangedCaptor.firstValue
- val keyguardChangedCaptor =
- argumentCaptor<DesktopModeKeyguardChangeListener>()
- verify(mockShellController).addKeyguardChangeListener(keyguardChangedCaptor.capture())
- desktopModeOnKeyguardChangedListener = keyguardChangedCaptor.firstValue
- whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
- whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
- (i.arguments.first() as Rect).set(STABLE_BOUNDS)
- }
- }
+ doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) }
+ doReturn(false).`when` { DesktopModeStatus.overridesShowAppHandle(Mockito.any()) }
- @After
- fun tearDown() {
- mockitoSession.finishMocking()
+ setUpCommon()
}
@Test
@@ -564,20 +358,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun testWindowDecor_desktopModeUnsupportedOnDevice_decorNotCreated() {
- // Simulate default enforce device restrictions system property
- whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
-
- val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
- // Simulate device that doesn't support desktop mode
- doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
-
- onTaskOpening(task)
- assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
fun testWindowDecor_desktopModeUnsupportedOnDevice_deviceRestrictionsOverridden_decorCreated() {
// Simulate enforce device restrictions system property overridden to false
whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(false)
@@ -619,7 +399,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
verify(mockDesktopTasksController).toggleDesktopTaskSize(
decor.mTaskInfo,
ResizeTrigger.MAXIMIZE_MENU,
- null
+ InputMethod.UNKNOWN_INPUT_METHOD
)
}
@@ -640,7 +420,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
@Test
fun testOnDecorSnappedLeft_snapResizes() {
- val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
val onLeftSnapClickListenerCaptor = forClass(Function0::class.java)
as ArgumentCaptor<Function0<Unit>>
val decor = createOpenTaskDecoration(
@@ -648,19 +427,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor
)
- val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
onLeftSnapClickListenerCaptor.value.invoke()
- verify(mockDesktopTasksController).snapToHalfScreen(
+ verify(mockDesktopTasksController).handleInstantSnapResizingTask(
eq(decor.mTaskInfo),
- taskSurfaceCaptor.capture(),
- eq(currentBounds),
eq(SnapPosition.LEFT),
eq(ResizeTrigger.SNAP_LEFT_MENU),
- eq(null),
+ eq(InputMethod.UNKNOWN_INPUT_METHOD),
eq(decor)
)
- assertEquals(taskSurfaceCaptor.firstValue, decor.mTaskSurface)
}
@Test
@@ -681,7 +456,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
@Test
@DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
fun testOnSnapResizeLeft_nonResizable_decorSnappedLeft() {
- val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
val onLeftSnapClickListenerCaptor = forClass(Function0::class.java)
as ArgumentCaptor<Function0<Unit>>
val decor = createOpenTaskDecoration(
@@ -689,19 +463,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor
).also { it.mTaskInfo.isResizeable = false }
- val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
onLeftSnapClickListenerCaptor.value.invoke()
- verify(mockDesktopTasksController).snapToHalfScreen(
+ verify(mockDesktopTasksController).handleInstantSnapResizingTask(
eq(decor.mTaskInfo),
- taskSurfaceCaptor.capture(),
- eq(currentBounds),
eq(SnapPosition.LEFT),
eq(ResizeTrigger.SNAP_LEFT_MENU),
- eq(null),
+ eq(InputMethod.UNKNOWN_INPUT_METHOD),
eq(decor),
)
- assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
}
@Test
@@ -720,15 +490,13 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
verify(mockDesktopTasksController, never())
.snapToHalfScreen(eq(decor.mTaskInfo), any(), eq(currentBounds), eq(SnapPosition.LEFT),
eq(ResizeTrigger.MAXIMIZE_BUTTON),
- eq(null),
+ eq(InputMethod.UNKNOWN_INPUT_METHOD),
eq(decor),
)
- verify(mockToast).show()
}
@Test
fun testOnDecorSnappedRight_snapResizes() {
- val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
val onRightSnapClickListenerCaptor = forClass(Function0::class.java)
as ArgumentCaptor<Function0<Unit>>
val decor = createOpenTaskDecoration(
@@ -736,19 +504,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor
)
- val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
onRightSnapClickListenerCaptor.value.invoke()
- verify(mockDesktopTasksController).snapToHalfScreen(
+ verify(mockDesktopTasksController).handleInstantSnapResizingTask(
eq(decor.mTaskInfo),
- taskSurfaceCaptor.capture(),
- eq(currentBounds),
eq(SnapPosition.RIGHT),
eq(ResizeTrigger.SNAP_RIGHT_MENU),
- eq(null),
+ eq(InputMethod.UNKNOWN_INPUT_METHOD),
eq(decor),
)
- assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
}
@Test
@@ -769,7 +533,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
@Test
@DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
fun testOnSnapResizeRight_nonResizable_decorSnappedRight() {
- val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
val onRightSnapClickListenerCaptor = forClass(Function0::class.java)
as ArgumentCaptor<Function0<Unit>>
val decor = createOpenTaskDecoration(
@@ -777,19 +540,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor
).also { it.mTaskInfo.isResizeable = false }
- val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
onRightSnapClickListenerCaptor.value.invoke()
- verify(mockDesktopTasksController).snapToHalfScreen(
+ verify(mockDesktopTasksController).handleInstantSnapResizingTask(
eq(decor.mTaskInfo),
- taskSurfaceCaptor.capture(),
- eq(currentBounds),
eq(SnapPosition.RIGHT),
eq(ResizeTrigger.SNAP_RIGHT_MENU),
- eq(null),
+ eq(InputMethod.UNKNOWN_INPUT_METHOD),
eq(decor),
)
- assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
}
@Test
@@ -808,10 +567,9 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
verify(mockDesktopTasksController, never())
.snapToHalfScreen(eq(decor.mTaskInfo), any(), eq(currentBounds), eq(SnapPosition.RIGHT),
eq(ResizeTrigger.MAXIMIZE_BUTTON),
- eq(null),
+ eq(InputMethod.UNKNOWN_INPUT_METHOD),
eq(decor),
)
- verify(mockToast).show()
}
@Test
@@ -1275,7 +1033,11 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
onClickListenerCaptor.value.onClick(view)
verify(mockDesktopTasksController)
- .toggleDesktopTaskSize(decor.mTaskInfo, ResizeTrigger.MAXIMIZE_BUTTON, null)
+ .toggleDesktopTaskSize(
+ decor.mTaskInfo,
+ ResizeTrigger.MAXIMIZE_BUTTON,
+ InputMethod.UNKNOWN_INPUT_METHOD
+ )
}
@Test
@@ -1446,64 +1208,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
return decor
}
- private fun onTaskOpening(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) {
- desktopModeWindowDecorViewModel.onTaskOpening(
- task,
- leash,
- SurfaceControl.Transaction(),
- SurfaceControl.Transaction()
- )
- }
-
- private fun onTaskChanging(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) {
- desktopModeWindowDecorViewModel.onTaskChanging(
- task,
- leash,
- SurfaceControl.Transaction(),
- SurfaceControl.Transaction()
- )
- }
-
- private fun createTask(
- displayId: Int = DEFAULT_DISPLAY,
- @WindowingMode windowingMode: Int,
- activityType: Int = ACTIVITY_TYPE_STANDARD,
- activityInfo: ActivityInfo = ActivityInfo(),
- requestingImmersive: Boolean = false
- ): RunningTaskInfo {
- return TestRunningTaskInfoBuilder()
- .setDisplayId(displayId)
- .setWindowingMode(windowingMode)
- .setVisible(true)
- .setActivityType(activityType)
- .build().apply {
- topActivityInfo = activityInfo
- isResizeable = true
- requestedVisibleTypes = if (requestingImmersive) {
- statusBars().inv()
- } else {
- statusBars()
- }
- }
- }
-
- private fun setUpMockDecorationForTask(task: RunningTaskInfo): DesktopModeWindowDecoration {
- val decoration = mock(DesktopModeWindowDecoration::class.java)
- whenever(
- mockDesktopModeWindowDecorFactory.create(
- any(), any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(),
- any(), any(), any(), any(), any(), any(), any(), any())
- ).thenReturn(decoration)
- decoration.mTaskInfo = task
- whenever(decoration.user).thenReturn(mockUserHandle)
- if (task.windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
- whenever(mockSplitScreenController.isTaskInSplitScreen(task.taskId))
- .thenReturn(true)
- }
- whenever(decoration.calculateValidDragArea()).thenReturn(Rect(0, 60, 2560, 1600))
- return decoration
- }
-
private fun setUpMockDecorationsForTasks(vararg tasks: RunningTaskInfo) {
tasks.forEach { setUpMockDecorationForTask(it) }
}
@@ -1520,19 +1224,4 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
)
}
-
- private fun RunningTaskInfo.setWindowingMode(@WindowingMode mode: Int) {
- configuration.windowConfiguration.windowingMode = mode
- }
-
- private fun RunningTaskInfo.setActivityType(type: Int) {
- configuration.windowConfiguration.activityType = type
- }
-
- companion object {
- private const val TAG = "DesktopModeWindowDecorViewModelTests"
- private val STABLE_INSETS = Rect(0, 100, 0, 0)
- private val INITIAL_BOUNDS = Rect(0, 0, 100, 100)
- private val STABLE_BOUNDS = Rect(0, 0, 1000, 1000)
- }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
new file mode 100644
index 000000000000..1670f2a6815b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
+import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
+import android.app.WindowConfiguration.WindowingMode
+import android.content.pm.ActivityInfo
+import android.graphics.Rect
+import android.hardware.input.InputManager
+import android.os.Handler
+import android.os.UserHandle
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.TestableContext
+import android.util.SparseArray
+import android.view.Choreographer
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.IWindowManager
+import android.view.InputChannel
+import android.view.InputMonitor
+import android.view.MotionEvent
+import android.view.SurfaceControl
+import android.view.WindowInsets.Type.statusBars
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser
+import com.android.wm.shell.apptoweb.AssistContentRequester
+import com.android.wm.shell.common.DisplayChangeController
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayInsetsController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.MultiInstanceHelper
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger
+import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopTasksController
+import com.android.wm.shell.desktopmode.DesktopTasksLimiter
+import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository
+import com.android.wm.shell.desktopmode.education.AppHandleEducationController
+import com.android.wm.shell.desktopmode.education.AppToWebEducationController
+import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
+import com.android.wm.shell.splitscreen.SplitScreenController
+import com.android.wm.shell.sysui.ShellCommandHandler
+import com.android.wm.shell.sysui.ShellController
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.FocusTransitionObserver
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.util.StubTransaction
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder
+import org.junit.After
+import org.junit.Rule
+import org.mockito.Mockito
+import org.mockito.Mockito.anyInt
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+import java.util.Optional
+import java.util.function.Supplier
+
+/**
+ * Utility class for tests of [DesktopModeWindowDecorViewModel]
+ */
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() {
+ @JvmField
+ @Rule
+ val setFlagsRule = SetFlagsRule()
+
+ @JvmField
+ @Rule
+ val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
+ private val mockDesktopModeWindowDecorFactory = mock<DesktopModeWindowDecoration.Factory>()
+ protected val mockMainHandler = mock<Handler>()
+ protected val mockMainChoreographer = mock<Choreographer>()
+ protected val mockTaskOrganizer = mock<ShellTaskOrganizer>()
+ protected val mockDisplayController = mock<DisplayController>()
+ protected val mockSplitScreenController = mock<SplitScreenController>()
+ protected val mockDesktopRepository = mock<DesktopRepository>()
+ protected val mockDisplayLayout = mock<DisplayLayout>()
+ protected val displayInsetsController = mock<DisplayInsetsController>()
+ protected val mockSyncQueue = mock<SyncTransactionQueue>()
+ protected val mockDesktopTasksController = mock<DesktopTasksController>()
+ protected val mockInputMonitor = mock<InputMonitor>()
+ protected val mockTransitions = mock<Transitions>()
+ internal val mockInputMonitorFactory =
+ mock<DesktopModeWindowDecorViewModel.InputMonitorFactory>()
+ protected val mockShellController = mock<ShellController>()
+ protected val testShellExecutor = TestShellExecutor()
+ protected val mockAppHeaderViewHolderFactory = mock<AppHeaderViewHolder.Factory>()
+ protected val mockRootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>()
+ protected val mockShellCommandHandler = mock<ShellCommandHandler>()
+ protected val mockWindowManager = mock<IWindowManager>()
+ protected val mockInteractionJankMonitor = mock<InteractionJankMonitor>()
+ protected val mockGenericLinksParser = mock<AppToWebGenericLinksParser>()
+ protected val mockUserHandle = mock<UserHandle>()
+ protected val mockAssistContentRequester = mock<AssistContentRequester>()
+ protected val bgExecutor = TestShellExecutor()
+ protected val mockMultiInstanceHelper = mock<MultiInstanceHelper>()
+ protected val mockTasksLimiter = mock<DesktopTasksLimiter>()
+ protected val mockFreeformTaskTransitionStarter = mock<FreeformTaskTransitionStarter>()
+ protected val mockActivityOrientationChangeHandler =
+ mock<DesktopActivityOrientationChangeHandler>()
+ protected val mockInputManager = mock<InputManager>()
+ private val mockTaskPositionerFactory =
+ mock<DesktopModeWindowDecorViewModel.TaskPositionerFactory>()
+ protected val mockTaskPositioner = mock<TaskPositioner>()
+ protected val mockAppHandleEducationController = mock<AppHandleEducationController>()
+ protected val mockAppToWebEducationController = mock<AppToWebEducationController>()
+ protected val mockFocusTransitionObserver = mock<FocusTransitionObserver>()
+ protected val mockCaptionHandleRepository = mock<WindowDecorCaptionHandleRepository>()
+ protected val motionEvent = mock<MotionEvent>()
+ val displayController = mock<DisplayController>()
+ val displayLayout = mock<DisplayLayout>()
+ protected lateinit var spyContext: TestableContext
+ private lateinit var desktopModeEventLogger: DesktopModeEventLogger
+
+ private val transactionFactory = Supplier<SurfaceControl.Transaction> {
+ SurfaceControl.Transaction()
+ }
+ protected val windowDecorByTaskIdSpy = spy(SparseArray<DesktopModeWindowDecoration>())
+
+ protected lateinit var mockitoSession: StaticMockitoSession
+ protected lateinit var shellInit: ShellInit
+ internal lateinit var desktopModeOnInsetsChangedListener: DesktopModeOnInsetsChangedListener
+ protected lateinit var displayChangingListener:
+ DisplayChangeController.OnDisplayChangingListener
+ internal lateinit var desktopModeOnKeyguardChangedListener: DesktopModeKeyguardChangeListener
+ protected lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel
+
+ fun setUpCommon() {
+ spyContext = spy(mContext)
+ doNothing().`when`(spyContext).startActivity(any())
+ shellInit = ShellInit(testShellExecutor)
+ windowDecorByTaskIdSpy.clear()
+ spyContext.addMockSystemService(InputManager::class.java, mockInputManager)
+ desktopModeEventLogger = mock<DesktopModeEventLogger>()
+ desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
+ spyContext,
+ testShellExecutor,
+ mockMainHandler,
+ mockMainChoreographer,
+ bgExecutor,
+ shellInit,
+ mockShellCommandHandler,
+ mockWindowManager,
+ mockTaskOrganizer,
+ mockDesktopRepository,
+ mockDisplayController,
+ mockShellController,
+ displayInsetsController,
+ mockSyncQueue,
+ mockTransitions,
+ Optional.of(mockDesktopTasksController),
+ mockGenericLinksParser,
+ mockAssistContentRequester,
+ mockMultiInstanceHelper,
+ mockDesktopModeWindowDecorFactory,
+ mockInputMonitorFactory,
+ transactionFactory,
+ mockAppHeaderViewHolderFactory,
+ mockRootTaskDisplayAreaOrganizer,
+ windowDecorByTaskIdSpy,
+ mockInteractionJankMonitor,
+ Optional.of(mockTasksLimiter),
+ mockAppHandleEducationController,
+ mockAppToWebEducationController,
+ mockCaptionHandleRepository,
+ Optional.of(mockActivityOrientationChangeHandler),
+ mockTaskPositionerFactory,
+ mockFocusTransitionObserver,
+ desktopModeEventLogger,
+ mock<DesktopModeUiEventLogger>()
+ )
+ desktopModeWindowDecorViewModel.setSplitScreenController(mockSplitScreenController)
+ whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS)
+ whenever(mockInputMonitorFactory.create(any(), any())).thenReturn(mockInputMonitor)
+ whenever(
+ mockTaskPositionerFactory.create(
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ )
+ .thenReturn(mockTaskPositioner)
+
+ // InputChannel cannot be mocked because it passes to InputEventReceiver.
+ val inputChannels = InputChannel.openInputChannelPair(TAG)
+ inputChannels.first().dispose()
+ whenever(mockInputMonitor.inputChannel).thenReturn(inputChannels[1])
+
+ shellInit.init()
+
+ val displayChangingListenerCaptor =
+ argumentCaptor<DisplayChangeController.OnDisplayChangingListener>()
+ verify(mockDisplayController)
+ .addDisplayChangingController(displayChangingListenerCaptor.capture())
+ displayChangingListener = displayChangingListenerCaptor.firstValue
+ val insetsChangedCaptor =
+ argumentCaptor<DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener>()
+ verify(displayInsetsController)
+ .addGlobalInsetsChangedListener(insetsChangedCaptor.capture())
+ desktopModeOnInsetsChangedListener = insetsChangedCaptor.firstValue
+ val keyguardChangedCaptor =
+ argumentCaptor<DesktopModeKeyguardChangeListener>()
+ verify(mockShellController).addKeyguardChangeListener(keyguardChangedCaptor.capture())
+ desktopModeOnKeyguardChangedListener = keyguardChangedCaptor.firstValue
+ whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
+ whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ }
+
+ protected fun createTask(
+ displayId: Int = DEFAULT_DISPLAY,
+ @WindowingMode windowingMode: Int,
+ activityType: Int = ACTIVITY_TYPE_STANDARD,
+ activityInfo: ActivityInfo = ActivityInfo(),
+ requestingImmersive: Boolean = false
+ ): RunningTaskInfo {
+ return TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
+ .setWindowingMode(windowingMode)
+ .setVisible(true)
+ .setActivityType(activityType)
+ .build().apply {
+ topActivityInfo = activityInfo
+ isResizeable = true
+ requestedVisibleTypes = if (requestingImmersive) {
+ statusBars().inv()
+ } else {
+ statusBars()
+ }
+ }
+ }
+
+ protected fun setUpMockDecorationForTask(task: RunningTaskInfo): DesktopModeWindowDecoration {
+ val decoration = Mockito.mock(DesktopModeWindowDecoration::class.java)
+ whenever(
+ mockDesktopModeWindowDecorFactory.create(
+ any(), any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(),
+ any(), any(), any(), any(), any(), any(), any(), any())
+ ).thenReturn(decoration)
+ decoration.mTaskInfo = task
+ whenever(decoration.user).thenReturn(mockUserHandle)
+ if (task.windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ whenever(mockSplitScreenController.isTaskInSplitScreen(task.taskId))
+ .thenReturn(true)
+ }
+ whenever(decoration.calculateValidDragArea()).thenReturn(Rect(0, 60, 2560, 1600))
+ return decoration
+ }
+
+
+ protected fun onTaskOpening(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) {
+ desktopModeWindowDecorViewModel.onTaskOpening(
+ task,
+ leash,
+ StubTransaction(),
+ StubTransaction()
+ )
+ }
+
+ protected fun onTaskChanging(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) {
+ desktopModeWindowDecorViewModel.onTaskChanging(
+ task,
+ leash,
+ StubTransaction(),
+ StubTransaction()
+ )
+ }
+
+ protected fun RunningTaskInfo.setWindowingMode(@WindowingMode mode: Int) {
+ configuration.windowConfiguration.windowingMode = mode
+ }
+
+ protected fun RunningTaskInfo.setActivityType(type: Int) {
+ configuration.windowConfiguration.activityType = type
+ }
+
+ companion object {
+ const val TAG = "DesktopModeWindowDecorViewModelTestsBase"
+ val STABLE_INSETS = Rect(0, 100, 0, 0)
+ val INITIAL_BOUNDS = Rect(0, 0, 100, 100)
+ val STABLE_BOUNDS = Rect(0, 0, 1000, 1000)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 1d2d0f078817..e390fbbd751f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -30,6 +30,7 @@ import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
import static com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.CLOSE_MAXIMIZE_MENU_DELAY_MS;
+import static com.android.wm.shell.windowdecor.WindowDecoration.INVALID_CORNER_RADIUS;
import static com.google.common.truth.Truth.assertThat;
@@ -219,7 +220,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
@Captor
private ArgumentCaptor<Runnable> mCloseMaxMenuRunnable;
- private final InsetsState mInsetsState = new InsetsState();
+ private final InsetsState mInsetsState = createInsetsState(statusBars(), /* visible= */true);
private SurfaceControl.Transaction mMockTransaction;
private StaticMockitoSession mMockitoSession;
private TestableContext mTestableContext;
@@ -264,8 +265,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY);
doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
when(mMockHandleMenuFactory.create(any(), any(), anyInt(), any(), any(), any(),
- anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), any(),
- anyInt(), anyInt(), anyInt(), anyInt()))
+ anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
+ any(), anyInt(), anyInt(), anyInt(), anyInt()))
.thenReturn(mMockHandleMenu);
when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())).thenReturn(false);
when(mMockAppHeaderViewHolderFactory.create(any(), any(), any(), any(), any(), any(), any(),
@@ -312,8 +313,9 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersAreEnabled() {
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
fillRoundedCornersResources(/* fillValue= */ 30);
RelayoutParams relayoutParams = new RelayoutParams();
@@ -334,6 +336,29 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ fillRoundedCornersResources(/* fillValue= */ 30);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false,
+ /* isStatusBarVisible */ true,
+ /* isKeyguardVisibleAndOccluded */ false,
+ /* inFullImmersiveMode */ false,
+ new InsetsState(),
+ /* hasGlobalFocus= */ true,
+ mExclusionRegion);
+
+ assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS);
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
public void updateRelayoutParams_appHeader_usesTaskDensity() {
final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
@@ -1408,8 +1433,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
public void notifyCaptionStateChanged_flagDisabled_doNoNotify() {
when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- when(mMockDisplayController.getInsetsState(taskInfo.displayId))
- .thenReturn(createInsetsState(statusBars(), /* visible= */true));
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -1423,8 +1446,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
public void notifyCaptionStateChanged_inFullscreenMode_notifiesAppHandleVisible() {
when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- when(mMockDisplayController.getInsetsState(taskInfo.displayId))
- .thenReturn(createInsetsState(statusBars(), /* visible= */true));
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
@@ -1444,8 +1465,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
public void notifyCaptionStateChanged_inWindowingMode_notifiesAppHeaderVisible() {
when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- when(mMockDisplayController.getInsetsState(taskInfo.displayId))
- .thenReturn(createInsetsState(statusBars(), /* visible= */true));
when(mMockAppHeaderViewHolder.getAppChipLocationInWindow()).thenReturn(
new Rect(/* left= */ 0, /* top= */ 1, /* right= */ 2, /* bottom= */ 3));
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
@@ -1473,8 +1492,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
public void notifyCaptionStateChanged_taskNotVisible_notifiesNoCaptionVisible() {
when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ false);
- when(mMockDisplayController.getInsetsState(taskInfo.displayId))
- .thenReturn(createInsetsState(statusBars(), /* visible= */true));
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED);
ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
@@ -1493,8 +1510,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
public void notifyCaptionStateChanged_captionHandleExpanded_notifiesHandleMenuExpanded() {
when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- when(mMockDisplayController.getInsetsState(taskInfo.displayId))
- .thenReturn(createInsetsState(statusBars(), /* visible= */true));
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
@@ -1518,8 +1533,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
public void notifyCaptionStateChanged_captionHandleClosed_notifiesHandleMenuClosed() {
when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- when(mMockDisplayController.getInsetsState(taskInfo.displayId))
- .thenReturn(createInsetsState(statusBars(), /* visible= */true));
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
@@ -1564,7 +1577,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
private void verifyHandleMenuCreated(@Nullable Uri uri) {
verify(mMockHandleMenuFactory).create(any(), any(), anyInt(), any(), any(),
any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
- argThat(intent -> (uri == null && intent == null) || intent.getData().equals(uri)),
+ anyBoolean(), argThat(intent ->
+ (uri == null && intent == null) || intent.getData().equals(uri)),
anyInt(), anyInt(), anyInt(), anyInt());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
index 7ec2cbf9460e..6babf817686a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
@@ -266,8 +266,8 @@ class HandleMenuTest : ShellTestCase() {
WindowManagerWrapper(mockWindowManager),
layoutId, appIcon, appName, splitScreenController, shouldShowWindowingPill = true,
shouldShowNewWindowButton = true, shouldShowManageWindowsButton = false,
- shouldShowChangeAspectRatioButton = false, isBrowserApp = false,
- null /* openInAppOrBrowserIntent */, captionWidth = HANDLE_WIDTH,
+ shouldShowChangeAspectRatioButton = false, shouldShowDesktopModeButton = true,
+ isBrowserApp = false, null /* openInAppOrBrowserIntent */, captionWidth = HANDLE_WIDTH,
captionHeight = 50,
captionX = captionX,
captionY = 0,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
index d8c1a11de452..d29002199f9d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
@@ -27,7 +27,7 @@ import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopModeEventLogger
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.desktopmode.DesktopTasksController
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
import com.android.wm.shell.transition.Transitions
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
index 3143946fa828..121e0e915d08 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
@@ -122,6 +122,6 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() {
companion object {
private val BOUNDS = Rect(1, 2, 3, 4)
- private val CORNER_RADIUS = 28
+ private const val CORNER_RADIUS = 28
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
index d7b971de94ac..3b39f1e4a25a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
@@ -38,7 +38,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.desktopmode.DesktopTasksController
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
import com.android.wm.shell.transition.Transitions
@@ -124,7 +124,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskTiled_toCorrectBounds_leftTile() {
- val task1 = createFreeformTask()
+ val task1 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -151,7 +151,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskTiled_toCorrectBounds_rightTile() {
// Setup
- val task1 = createFreeformTask()
+ val task1 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -177,7 +177,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskTiled_notAnimated_whenTilingPositionNotChange() {
- val task1 = createFreeformTask()
+ val task1 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -213,8 +213,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskNotTiled_notBroughtToFront_tilingNotInitialised() {
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -236,9 +236,9 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskNotTiled_notBroughtToFront_taskNotTiled() {
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
- val task3 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
+ val task3 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -265,9 +265,9 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
}
@Test
- fun taskTiled_broughtToFront_alreadyInFrontNoAction() {
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
+ fun taskTiled_broughtToFront_alreadyInFrontStillReorder() {
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -275,6 +275,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
}
whenever(context.resources).thenReturn(resources)
whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width)
+ whenever(desktopRepository.isVisibleTask(eq(task1.taskId))).thenReturn(true)
+ whenever(desktopRepository.isVisibleTask(eq(task2.taskId))).thenReturn(true)
tilingDecoration.onAppTiled(
task1,
@@ -290,15 +292,15 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
)
task1.isFocused = true
- assertThat(tilingDecoration.moveTiledPairToFront(task1)).isFalse()
- verify(transitions, never()).startTransition(any(), any(), any())
+ assertThat(tilingDecoration.moveTiledPairToFront(task1, isTaskFocused = true)).isTrue()
+ verify(transitions, times(1)).startTransition(eq(TRANSIT_TO_FRONT), any(), eq(null))
}
@Test
fun taskTiled_broughtToFront_bringToFront() {
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
- val task3 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
+ val task3 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(stableBounds)
@@ -329,9 +331,9 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskTiled_broughtToFront_taskInfoNotUpdated_bringToFront() {
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
- val task3 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
+ val task3 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(stableBounds)
@@ -361,8 +363,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskTiledTasks_NotResized_BeforeTouchEndArrival() {
// Setup
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -428,8 +430,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun tiledTasksResizedUsingDividerHandle_shouldLogResizingEvents() {
// Setup
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -464,8 +466,10 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
// this test, so we verify the same log twice.
verify(desktopModeEventLogger, times(2)).logTaskResizingStarted(
ResizeTrigger.TILING_DIVIDER,
- motionEvent,
+ DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD,
task1,
+ BOUNDS.width() / 2,
+ BOUNDS.height(),
displayController,
)
@@ -475,17 +479,17 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
// this test, so we verify the same log twice.
verify(desktopModeEventLogger, times(2)).logTaskResizingEnded(
ResizeTrigger.TILING_DIVIDER,
- motionEvent,
+ DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD,
task1,
- BOUNDS.height(),
BOUNDS.width(),
+ BOUNDS.height(),
displayController,
)
}
@Test
fun taskTiled_shouldBeRemoved_whenTileBroken() {
- val task1 = createFreeformTask()
+ val task1 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -514,8 +518,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun taskNotTiled_shouldNotBeRemoved_whenNotTiled() {
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -543,8 +547,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
@Test
fun tasksTiled_shouldBeRemoved_whenSessionDestroyed() {
- val task1 = createFreeformTask()
- val task2 = createFreeformTask()
+ val task1 = createVisibleTask()
+ val task2 = createVisibleTask()
val stableBounds = STABLE_BOUNDS_MOCK
whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -608,6 +612,11 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
return Rect(stableBounds.left, stableBounds.top, rightBound, stableBounds.bottom)
}
+ private fun createVisibleTask() =
+ createFreeformTask().also {
+ whenever(desktopRepository.isVisibleTask(eq(it.taskId))).thenReturn(true)
+ }
+
companion object {
private val NON_STABLE_BOUNDS_MOCK = Rect(50, 55, 100, 100)
private val STABLE_BOUNDS_MOCK = Rect(0, 0, 100, 100)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
index 734815cdd915..9a9d05a72442 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
@@ -19,9 +19,12 @@ package com.android.wm.shell.windowdecor.tiling
import android.graphics.Rect
import android.os.SystemClock
import android.testing.AndroidTestingRunner
+import android.util.Size
+import android.view.Display
import android.view.InputDevice
import android.view.LayoutInflater
import android.view.MotionEvent
+import android.view.RoundedCorner
import android.view.View
import androidx.test.annotation.UiThreadTest
import androidx.test.filters.SmallTest
@@ -46,16 +49,19 @@ class TilingDividerViewTest : ShellTestCase() {
private val dividerMoveCallbackMock = mock<DividerMoveCallback>()
private val viewMock = mock<View>()
+ private val display = mock<Display>()
+ private val roundedCorner = mock<RoundedCorner>()
@Before
@UiThreadTest
fun setUp() {
+ whenever(display.getRoundedCorner(any())).thenReturn(roundedCorner)
+ whenever(roundedCorner.radius).thenReturn(CORNER_RADIUS)
tilingDividerView =
LayoutInflater.from(mContext).inflate(R.layout.tiling_split_divider, /* root= */ null)
as TilingDividerView
- tilingDividerView.setup(dividerMoveCallbackMock, BOUNDS)
- tilingDividerView.handleStartY = 0
- tilingDividerView.handleEndY = 1500
+ tilingDividerView.setup(dividerMoveCallbackMock, DIVIDER_BOUNDS, HANDLE_SIZE)
+ tilingDividerView.handleY = 0..1500
}
@Test
@@ -130,6 +136,8 @@ class TilingDividerViewTest : ShellTestCase() {
}
companion object {
- private val BOUNDS = Rect(0, 0, 1500, 1500)
+ private val DIVIDER_BOUNDS = Rect(15, 0, 35, 1500)
+ private val HANDLE_SIZE = Size(800, 300)
+ private const val CORNER_RADIUS = 15
}
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index fcb7efc35c94..e2db2c9e3827 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -355,6 +355,7 @@ cc_defaults {
"jni/AnimatedImageDrawable.cpp",
"jni/Bitmap.cpp",
"jni/BitmapRegionDecoder.cpp",
+ "jni/RuntimeXfermode.cpp",
"jni/BufferUtils.cpp",
"jni/HardwareBufferHelpers.cpp",
"jni/BitmapFactory.cpp",
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index fb58a69747b3..b72e066e64ae 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -84,6 +84,7 @@ public:
// this value is only valid after the GPU has been initialized and there is a valid graphics
// context or if you are using the HWUI_NULL_GPU
int maxTextureSize() const;
+ bool hasMaxTextureSize() const { return mMaxTextureSize > 0; }
sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
SkColorType getWideColorType() {
static std::once_flag kFlag;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 2c23864317a4..4801bd1038a3 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -186,7 +186,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
// If we are not a layer OR we cannot be rendered (eg, view was detached)
// we need to destroy any Layers we may have had previously
if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable()) ||
- CC_UNLIKELY(properties().getWidth() == 0) || CC_UNLIKELY(properties().getHeight() == 0) ||
+ CC_UNLIKELY(properties().getWidth() <= 0) || CC_UNLIKELY(properties().getHeight() <= 0) ||
CC_UNLIKELY(!properties().fitsOnLayer())) {
if (CC_UNLIKELY(hasLayer())) {
this->setLayerSurface(nullptr);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index b1ad8b2eb1b9..4dc57004e401 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -545,7 +545,8 @@ public:
bool fitsOnLayer() const {
const DeviceInfo* deviceInfo = DeviceInfo::get();
return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize() &&
- mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+ mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize() &&
+ mPrimitiveFields.mWidth > 0 && mPrimitiveFields.mHeight > 0;
}
bool promotedToLayer() const {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 7c150862a422..7f5ca44f7ceb 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -622,18 +622,13 @@ bool SkiaCanvas::useGainmapShader(Bitmap& bitmap) {
auto colorSpace = info.colorSpace();
// If we don't have a colorspace, we can't apply a gainmap
if (!colorSpace) return false;
- skcms_TransferFunction tfn;
- colorSpace->transferFn(&tfn);
-
- auto transferType = skcms_TransferFunction_getType(&tfn);
- switch (transferType) {
- case skcms_TFType_HLGish:
- case skcms_TFType_HLGinvish:
- case skcms_TFType_PQish:
- return true;
- case skcms_TFType_Invalid:
- case skcms_TFType_sRGBish:
- return false;
+
+ const float targetRatio = uirenderer::getTargetHdrSdrRatio(colorSpace);
+
+ if (bitmap.gainmap()->info.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) {
+ return targetRatio < bitmap.gainmap()->info.fDisplayRatioHdr;
+ } else {
+ return targetRatio > bitmap.gainmap()->info.fDisplayRatioSdr;
}
}
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 15b2bac50c79..56de56805be4 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -28,6 +28,7 @@
extern int register_android_graphics_Bitmap(JNIEnv*);
extern int register_android_graphics_BitmapFactory(JNIEnv*);
extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
+extern int register_android_graphics_RuntimeXfermode(JNIEnv*);
extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
extern int register_android_graphics_Camera(JNIEnv* env);
extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
@@ -107,6 +108,7 @@ extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env);
REG_JNI(register_android_graphics_Bitmap),
REG_JNI(register_android_graphics_BitmapFactory),
REG_JNI(register_android_graphics_BitmapRegionDecoder),
+ REG_JNI(register_android_graphics_RuntimeXfermode),
REG_JNI(register_android_graphics_ByteBufferStreamAdaptor),
REG_JNI(register_android_graphics_Camera),
REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
diff --git a/libs/hwui/effects/GainmapRenderer.cpp b/libs/hwui/effects/GainmapRenderer.cpp
index eac03609d72f..18b77bc51aca 100644
--- a/libs/hwui/effects/GainmapRenderer.cpp
+++ b/libs/hwui/effects/GainmapRenderer.cpp
@@ -73,7 +73,9 @@ void DrawGainmapBitmap(SkCanvas* c, const sk_sp<const SkImage>& image, const SkR
#ifdef __ANDROID__
auto destColorspace = c->imageInfo().refColorSpace();
float targetSdrHdrRatio = getTargetHdrSdrRatio(destColorspace.get());
- if (targetSdrHdrRatio > 1.f && gainmapImage) {
+ const bool baseImageHdr = gainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR;
+ if (gainmapImage && ((baseImageHdr && targetSdrHdrRatio < gainmapInfo.fDisplayRatioHdr) ||
+ (!baseImageHdr && targetSdrHdrRatio > gainmapInfo.fDisplayRatioSdr))) {
SkPaint gainmapPaint = *paint;
float sX = gainmapImage->width() / (float)image->width();
float sY = gainmapImage->height() / (float)image->height();
@@ -183,7 +185,10 @@ private:
baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB();
// Determine the color space in which the gainmap math is to be applied.
- sk_sp<SkColorSpace> gainmapMathColorSpace = baseColorSpace->makeLinearGamma();
+ sk_sp<SkColorSpace> gainmapMathColorSpace =
+ mGainmapInfo.fGainmapMathColorSpace
+ ? mGainmapInfo.fGainmapMathColorSpace->makeLinearGamma()
+ : baseColorSpace->makeLinearGamma();
// Create a color filter to transform from the base image's color space to the color space
// in which the gainmap is to be applied.
@@ -266,6 +271,10 @@ private:
W = 1.f;
}
}
+
+ if (mGainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) {
+ W -= 1.f;
+ }
mBuilder.uniform("W") = W;
uniforms = mBuilder.uniforms();
}
@@ -317,4 +326,4 @@ sk_sp<SkShader> MakeGainmapShader(const sk_sp<const SkImage>& image,
#endif // __ANDROID__
-} // namespace android::uirenderer \ No newline at end of file
+} // namespace android::uirenderer
diff --git a/libs/hwui/jni/ColorFilter.cpp b/libs/hwui/jni/ColorFilter.cpp
index 20301d2c76ec..1c6d886f18b7 100644
--- a/libs/hwui/jni/ColorFilter.cpp
+++ b/libs/hwui/jni/ColorFilter.cpp
@@ -163,6 +163,20 @@ public:
filter->updateChild(env, name.c_str(), child);
}
}
+
+ static void RuntimeColorFilter_updateInputColorFilter(JNIEnv* env, jobject,
+ jlong colorFilterPtr, jstring childName,
+ jlong childFilterPtr) {
+ auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr);
+ ScopedUtfChars name(env, childName);
+ auto* child = reinterpret_cast<ColorFilter*>(childFilterPtr);
+ if (filter && child) {
+ auto childInput = child->getInstance();
+ if (childInput) {
+ filter->updateChild(env, name.c_str(), childInput.release());
+ }
+ }
+ }
};
static const JNINativeMethod colorfilter_methods[] = {
@@ -193,7 +207,9 @@ static const JNINativeMethod runtime_color_filter_methods[] = {
{"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
(void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsInts},
{"nativeUpdateChild", "(JLjava/lang/String;J)V",
- (void*)ColorFilterGlue::RuntimeColorFilter_updateChild}};
+ (void*)ColorFilterGlue::RuntimeColorFilter_updateChild},
+ {"nativeUpdateInputColorFilter", "(JLjava/lang/String;J)V",
+ (void*)ColorFilterGlue::RuntimeColorFilter_updateInputColorFilter}};
int register_android_graphics_ColorFilter(JNIEnv* env) {
android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods,
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index da237928e5e1..8d3a5eb2b4af 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -619,7 +619,16 @@ namespace PaintGlue {
// restore the original settings.
font->setSkewX(saveSkewX);
font->setEmbolden(savefakeBold);
- if (paint->getFamilyVariant() == minikin::FamilyVariant::ELEGANT) {
+
+ // Don't use hard coded vertical metrics if target SDK is 35 or later.
+#ifdef __ANDROID__
+ uint32_t isTargetSdk35OrLater = android_get_application_target_sdk_version() >= 35;
+#else
+ uint32_t isTargetSdk35OrLater = true;
+#endif // __ANDROID
+ bool useHardCodedMetrics = !isTargetSdk35OrLater &&
+ (paint->getFamilyVariant() == minikin::FamilyVariant::ELEGANT);
+ if (useHardCodedMetrics) {
SkScalar size = font->getSize();
metrics->fTop = -size * kElegantTop / 2048;
metrics->fBottom = -size * kElegantBottom / 2048;
@@ -906,6 +915,13 @@ namespace PaintGlue {
paint->setBlendMode(mode);
}
+ static void setRuntimeXfermode(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle,
+ jlong xfermodeHandle) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ SkBlender* blender = reinterpret_cast<SkBlender*>(xfermodeHandle);
+ paint->setBlender(sk_ref_sp(blender));
+ }
+
static jlong setPathEffect(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong effectHandle) {
Paint* obj = reinterpret_cast<Paint*>(objHandle);
SkPathEffect* effect = reinterpret_cast<SkPathEffect*>(effectHandle);
@@ -1233,6 +1249,7 @@ static const JNINativeMethod methods[] = {
{"nSetShader", "(JJ)J", (void*)PaintGlue::setShader},
{"nSetColorFilter", "(JJ)J", (void*)PaintGlue::setColorFilter},
{"nSetXfermode", "(JI)V", (void*)PaintGlue::setXfermode},
+ {"nSetXfermode", "(JJ)V", (void*)PaintGlue::setRuntimeXfermode},
{"nSetPathEffect", "(JJ)J", (void*)PaintGlue::setPathEffect},
{"nSetMaskFilter", "(JJ)J", (void*)PaintGlue::setMaskFilter},
{"nSetTypeface", "(JJ)V", (void*)PaintGlue::setTypeface},
diff --git a/libs/hwui/jni/RuntimeEffectUtils.cpp b/libs/hwui/jni/RuntimeEffectUtils.cpp
index 46db8633c66e..ad0e540b5b40 100644
--- a/libs/hwui/jni/RuntimeEffectUtils.cpp
+++ b/libs/hwui/jni/RuntimeEffectUtils.cpp
@@ -90,7 +90,7 @@ void UpdateChild(JNIEnv* env, SkRuntimeEffectBuilder* builder, const char* child
SkFlattenable* childEffect) {
SkRuntimeShaderBuilder::BuilderChild builderChild = builder->child(childName);
if (builderChild.fChild == nullptr) {
- ThrowIAEFmt(env, "unable to find shader named %s", childName);
+ ThrowIAEFmt(env, "unable to find child named %s", childName);
return;
}
diff --git a/libs/hwui/jni/RuntimeXfermode.cpp b/libs/hwui/jni/RuntimeXfermode.cpp
new file mode 100644
index 000000000000..17bee8fb8b15
--- /dev/null
+++ b/libs/hwui/jni/RuntimeXfermode.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "ColorFilter.h"
+#include "GraphicsJNI.h"
+#include "RuntimeEffectUtils.h"
+#include "SkBlender.h"
+
+using namespace android::uirenderer;
+
+static void SkRuntimeEffectBuilder_delete(SkRuntimeEffectBuilder* builder) {
+ delete builder;
+}
+
+static jlong RuntimeXfermode_getNativeFinalizer(JNIEnv*, jobject) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeEffectBuilder_delete));
+}
+
+static jlong RuntimeXfermode_createBuilder(JNIEnv* env, jobject, jstring sksl) {
+ ScopedUtfChars strSksl(env, sksl);
+ auto result =
+ SkRuntimeEffect::MakeForBlender(SkString(strSksl.c_str()), SkRuntimeEffect::Options{});
+ if (result.effect.get() == nullptr) {
+ doThrowIAE(env, result.errorText.c_str());
+ return 0;
+ }
+ return reinterpret_cast<jlong>(new SkRuntimeEffectBuilder(std::move(result.effect)));
+}
+
+static jlong RuntimeXfermode_create(JNIEnv* env, jobject, jlong builderPtr) {
+ auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+ sk_sp<SkBlender> blender = builder->makeBlender();
+ if (!blender) {
+ doThrowIAE(env);
+ }
+ return reinterpret_cast<jlong>(blender.release());
+}
+
+static void RuntimeXfermode_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong builderPtr,
+ jstring uniformName, jfloatArray uniforms,
+ jboolean isColor) {
+ auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+ ScopedUtfChars name(env, uniformName);
+ AutoJavaFloatArray autoValues(env, uniforms, 0, kRO_JNIAccess);
+ UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
+}
+
+static void RuntimeXfermode_updateFloatUniforms(JNIEnv* env, jobject, jlong builderPtr,
+ jstring uniformName, jfloat value1, jfloat value2,
+ jfloat value3, jfloat value4, jint count) {
+ auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+ ScopedUtfChars name(env, uniformName);
+ const float values[4] = {value1, value2, value3, value4};
+ UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
+}
+
+static void RuntimeXfermode_updateIntArrayUniforms(JNIEnv* env, jobject, jlong builderPtr,
+ jstring uniformName, jintArray uniforms) {
+ auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+ ScopedUtfChars name(env, uniformName);
+ AutoJavaIntArray autoValues(env, uniforms, 0);
+ UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
+}
+
+static void RuntimeXfermode_updateIntUniforms(JNIEnv* env, jobject, jlong builderPtr,
+ jstring uniformName, jint value1, jint value2,
+ jint value3, jint value4, jint count) {
+ auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+ ScopedUtfChars name(env, uniformName);
+ const int values[4] = {value1, value2, value3, value4};
+ UpdateIntUniforms(env, builder, name.c_str(), values, count);
+}
+
+static void RuntimeXfermode_updateChild(JNIEnv* env, jobject, jlong builderPtr, jstring childName,
+ jlong childPtr) {
+ auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+ ScopedUtfChars name(env, childName);
+ auto* child = reinterpret_cast<SkFlattenable*>(childPtr);
+ if (child) {
+ UpdateChild(env, builder, name.c_str(), child);
+ }
+}
+
+static void RuntimeXfermode_updateColorFilter(JNIEnv* env, jobject, jlong builderPtr,
+ jstring childName, jlong colorFilterPtr) {
+ auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+ ScopedUtfChars name(env, childName);
+ auto* child = reinterpret_cast<ColorFilter*>(colorFilterPtr);
+ if (child) {
+ auto childInput = child->getInstance();
+ if (childInput) {
+ UpdateChild(env, builder, name.c_str(), childInput.release());
+ }
+ }
+}
+
+static const JNINativeMethod gRuntimeXfermodeMethods[] = {
+ {"nativeGetFinalizer", "()J", (void*)RuntimeXfermode_getNativeFinalizer},
+ {"nativeCreateBlenderBuilder", "(Ljava/lang/String;)J",
+ (void*)RuntimeXfermode_createBuilder},
+ {"nativeCreateNativeInstance", "(J)J", (void*)RuntimeXfermode_create},
+ {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
+ (void*)RuntimeXfermode_updateFloatArrayUniforms},
+ {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
+ (void*)RuntimeXfermode_updateFloatUniforms},
+ {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
+ (void*)RuntimeXfermode_updateIntArrayUniforms},
+ {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
+ (void*)RuntimeXfermode_updateIntUniforms},
+ {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeXfermode_updateChild},
+ {"nativeUpdateColorFilter", "(JLjava/lang/String;J)V",
+ (void*)RuntimeXfermode_updateColorFilter},
+};
+
+int register_android_graphics_RuntimeXfermode(JNIEnv* env) {
+ android::RegisterMethodsOrDie(env, "android/graphics/RuntimeXfermode", gRuntimeXfermodeMethods,
+ NELEM(gRuntimeXfermodeMethods));
+
+ return 0;
+}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 2a057e7a4cdc..eadb9dea566f 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -1,7 +1,9 @@
#include <vector>
+#include "ColorFilter.h"
#include "Gainmap.h"
#include "GraphicsJNI.h"
+#include "RuntimeEffectUtils.h"
#include "SkBitmap.h"
#include "SkBlendMode.h"
#include "SkColor.h"
@@ -280,50 +282,6 @@ static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
return ret;
}
-static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
- switch (type) {
- case SkRuntimeEffect::Uniform::Type::kFloat:
- case SkRuntimeEffect::Uniform::Type::kFloat2:
- case SkRuntimeEffect::Uniform::Type::kFloat3:
- case SkRuntimeEffect::Uniform::Type::kFloat4:
- case SkRuntimeEffect::Uniform::Type::kFloat2x2:
- case SkRuntimeEffect::Uniform::Type::kFloat3x3:
- case SkRuntimeEffect::Uniform::Type::kFloat4x4:
- return false;
- case SkRuntimeEffect::Uniform::Type::kInt:
- case SkRuntimeEffect::Uniform::Type::kInt2:
- case SkRuntimeEffect::Uniform::Type::kInt3:
- case SkRuntimeEffect::Uniform::Type::kInt4:
- return true;
- }
-}
-
-static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
- const char* uniformName, const float values[], int count,
- bool isColor) {
- SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
- if (uniform.fVar == nullptr) {
- ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
- } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
- if (isColor) {
- jniThrowExceptionFmt(
- env, "java/lang/IllegalArgumentException",
- "attempting to set a color uniform using the non-color specific APIs: %s %x",
- uniformName, uniform.fVar->flags);
- } else {
- ThrowIAEFmt(env,
- "attempting to set a non-color uniform using the setColorUniform APIs: %s",
- uniformName);
- }
- } else if (isIntUniformType(uniform.fVar->type)) {
- ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
- uniformName);
- } else if (!uniform.set<float>(values, count)) {
- ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
- uniform.fVar->sizeInBytes(), sizeof(float) * count);
- }
-}
-
static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
jstring jUniformName, jfloat value1, jfloat value2,
jfloat value3, jfloat value4, jint count) {
@@ -342,20 +300,6 @@ static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong s
UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
}
-static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
- const int values[], int count) {
- SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
- if (uniform.fVar == nullptr) {
- ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
- } else if (!isIntUniformType(uniform.fVar->type)) {
- ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
- uniformName);
- } else if (!uniform.set<int>(values, count)) {
- ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
- uniform.fVar->sizeInBytes(), sizeof(float) * count);
- }
-}
-
static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
jstring jUniformName, jint value1, jint value2,
jint value3, jint value4, jint count) {
@@ -388,6 +332,24 @@ static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder
builder->child(name.c_str()) = sk_ref_sp(shader);
}
+static void RuntimeShader_updateColorFilter(JNIEnv* env, jobject, jlong shaderBuilder,
+ jstring jUniformName, jlong colorFilterHandle) {
+ SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
+ ScopedUtfChars name(env, jUniformName);
+ auto* childEffect = reinterpret_cast<ColorFilter*>(colorFilterHandle);
+
+ UpdateChild(env, builder, name.c_str(), childEffect->getInstance().release());
+}
+
+static void RuntimeShader_updateChild(JNIEnv* env, jobject, jlong shaderBuilder,
+ jstring jUniformName, jlong childHandle) {
+ SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
+ ScopedUtfChars name(env, jUniformName);
+ auto* childEffect = reinterpret_cast<SkFlattenable*>(childHandle);
+
+ UpdateChild(env, builder, name.c_str(), childEffect);
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gShaderMethods[] = {
@@ -428,6 +390,9 @@ static const JNINativeMethod gRuntimeShaderMethods[] = {
{"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
(void*)RuntimeShader_updateIntUniforms},
{"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
+ {"nativeUpdateColorFilter", "(JLjava/lang/String;J)V",
+ (void*)RuntimeShader_updateColorFilter},
+ {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateChild},
};
int register_android_graphics_Shader(JNIEnv* env)
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8ec04304a808..b36b8be10779 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -418,6 +418,11 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
RenderNode* target) {
mRenderThread.removeFrameCallback(this);
+ // Make sure we have a valid device info
+ if (!DeviceInfo::get()->hasMaxTextureSize()) {
+ (void)mRenderThread.requireGrContext();
+ }
+
// If the previous frame was dropped we don't need to hold onto it, so
// just keep using the previous frame's structure instead
const auto reason = wasSkipped(mCurrentFrameInfo);
diff --git a/libs/hwui/tests/unit/RenderPropertiesTests.cpp b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
index 3e8e0576bf49..6ec042cf23b0 100644
--- a/libs/hwui/tests/unit/RenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
@@ -40,7 +40,11 @@ TEST(RenderProperties, layerValidity) {
props.setLeftTopRightBottom(0, 0, maxTextureSize + 1, maxTextureSize + 1);
ASSERT_FALSE(props.fitsOnLayer());
- // Too small, but still 'fits'. Not fitting is an error case, so don't report empty as such.
+ // Too small, we can't create a layer for a 0 width or height
props.setLeftTopRightBottom(0, 0, 100, 0);
- ASSERT_TRUE(props.fitsOnLayer());
+ ASSERT_FALSE(props.fitsOnLayer());
+
+ // Can't create a negative-sized layer
+ props.setLeftTopRightBottom(0, 0, -100, 300);
+ ASSERT_FALSE(props.fitsOnLayer());
}
diff --git a/libs/input/SpriteIcon.cpp b/libs/input/SpriteIcon.cpp
index 59e36e4b0d1e..2f8d4735c69b 100644
--- a/libs/input/SpriteIcon.cpp
+++ b/libs/input/SpriteIcon.cpp
@@ -25,6 +25,8 @@
namespace android {
bool SpriteIcon::draw(sp<Surface> surface) const {
+ LOG_ALWAYS_FATAL_IF(!isValid(), "Cannot draw SpriteIcon: not valid");
+
ANativeWindow_Buffer outBuffer;
status_t status = surface->lock(&outBuffer, NULL);
if (status) {
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 2da8eecedc4d..b41f40f412d2 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -17,6 +17,7 @@
package android.media;
import static android.media.audio.Flags.FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE;
+import static android.media.audio.Flags.FLAG_SPEAKER_LAYOUT_API;
import android.Manifest;
import android.annotation.FlaggedApi;
@@ -548,6 +549,19 @@ public final class AudioDeviceInfo {
}
/**
+ * @return A ChannelMask representing the physical output speaker layout of the device.
+ *
+ * The layout channel mask only indicates which speaker channels are present, the
+ * physical layout of the speakers should be informed by a standard for multi-channel
+ * sound playback systems, such as ITU-R BS.2051.
+ * @see AudioFormat
+ */
+ @FlaggedApi(FLAG_SPEAKER_LAYOUT_API)
+ public int getSpeakerLayoutChannelMask() {
+ return mPort.speakerLayoutChannelMask();
+ }
+
+ /**
* @return An array of audio encodings (e.g. {@link AudioFormat#ENCODING_PCM_16BIT},
* {@link AudioFormat#ENCODING_PCM_FLOAT}) supported by the audio device.
* <code>ENCODING_PCM_FLOAT</code> indicates the device supports more
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index ab5c54b5cd7e..4b3962e6dd74 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -22,6 +22,7 @@ import android.os.Build;
import com.android.aconfig.annotations.VisibleForTesting;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -60,8 +61,27 @@ public class AudioDevicePort extends AudioPort {
/* encapsulationMetadataTypes= */ null);
}
+ /** @hide */
+ // TODO: b/316864909 - Remove this method once there's a way to fake audio device ports further
+ // down the stack.
+ @VisibleForTesting
+ public static AudioDevicePort createForTesting(int speakerLayoutChannelMask) {
+ return new AudioDevicePort(
+ new AudioHandle(/* id= */ 0),
+ /* name= */ "testAudioDevicePort",
+ /* profiles= */ new ArrayList<>(),
+ /* gains= */ null,
+ /* type= */ AudioManager.DEVICE_OUT_SPEAKER,
+ /* address= */ "testAddress",
+ /* speakerLayoutChannelMask= */ speakerLayoutChannelMask,
+ /* encapsulationModes= */ null,
+ /* encapsulationMetadataTypes= */ null,
+ /* descriptors= */ new ArrayList<>());
+ }
+
private final int mType;
private final String mAddress;
+ private final int mSpeakerLayoutChannelMask;
private final int[] mEncapsulationModes;
private final int[] mEncapsulationMetadataTypes;
@@ -76,12 +96,20 @@ public class AudioDevicePort extends AudioPort {
deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains);
mType = type;
mAddress = address;
+ mSpeakerLayoutChannelMask = AudioFormat.CHANNEL_INVALID;
mEncapsulationModes = encapsulationModes;
mEncapsulationMetadataTypes = encapsulationMetadataTypes;
}
- AudioDevicePort(AudioHandle handle, String deviceName, List<AudioProfile> profiles,
- AudioGain[] gains, int type, String address, int[] encapsulationModes,
+ AudioDevicePort(
+ AudioHandle handle,
+ String deviceName,
+ List<AudioProfile> profiles,
+ AudioGain[] gains,
+ int type,
+ String address,
+ int speakerLayoutChannelMask,
+ int[] encapsulationModes,
@AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes,
List<AudioDescriptor> descriptors) {
super(handle,
@@ -89,6 +117,7 @@ public class AudioDevicePort extends AudioPort {
deviceName, profiles, gains, descriptors);
mType = type;
mAddress = address;
+ mSpeakerLayoutChannelMask = speakerLayoutChannelMask;
mEncapsulationModes = encapsulationModes;
mEncapsulationMetadataTypes = encapsulationMetadataTypes;
}
@@ -119,6 +148,16 @@ public class AudioDevicePort extends AudioPort {
return mAddress;
}
+ /** Get the channel mask representing the physical output speaker layout of the device.
+ *
+ * The layout channel mask only indicates which speaker channels are present, the
+ * physical layout of the speakers should be informed by a standard for multi-channel
+ * sound playback systems, such as ITU-R BS.2051.
+ */
+ public int speakerLayoutChannelMask() {
+ return mSpeakerLayoutChannelMask;
+ }
+
/**
* Get supported encapsulation modes.
*/
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 3cd5f5266ef2..62fb0120a97d 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -19,6 +19,7 @@ package android.media;
import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_ALL;
import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_NONE;
import static android.media.audio.Flags.FLAG_MUTED_BY_PORT_VOLUME_API;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -39,6 +40,9 @@ import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -56,6 +60,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
public static final int PLAYER_UPID_INVALID = -1;
/** @hide */
public static final int PLAYER_DEVICEID_INVALID = 0;
+ /** @hide */
+ public static final int[] PLAYER_DEVICEIDS_INVALID = new int[0];
// information about the implementation
/**
@@ -305,12 +311,18 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_PORT_VOLUME = (1 << 6);
+ /**
+ * @hide
+ * Flag used when playback is muted by AppOpsManager#OP_CONTROL_AUDIO.
+ */
+ public static final int MUTED_BY_OP_CONTROL_AUDIO = (1 << 7);
+
/** @hide */
@IntDef(
flag = true,
value = {MUTED_BY_MASTER, MUTED_BY_STREAM_VOLUME, MUTED_BY_STREAM_MUTED,
MUTED_BY_APP_OPS, MUTED_BY_CLIENT_VOLUME, MUTED_BY_VOLUME_SHAPER,
- MUTED_BY_PORT_VOLUME})
+ MUTED_BY_PORT_VOLUME, MUTED_BY_OP_CONTROL_AUDIO})
@Retention(RetentionPolicy.SOURCE)
public @interface PlayerMuteEvent {
}
@@ -332,7 +344,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
private final Object mUpdateablePropLock = new Object();
@GuardedBy("mUpdateablePropLock")
- private int mDeviceId;
+ private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
@GuardedBy("mUpdateablePropLock")
private int mSessionId;
@GuardedBy("mUpdateablePropLock")
@@ -361,7 +373,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
mClientUid = uid;
mClientPid = pid;
mMutedState = 0;
- mDeviceId = PLAYER_DEVICEID_INVALID;
+ mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
mPlayerState = PLAYER_STATE_IDLE;
mPlayerAttr = pic.mAttributes;
if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) {
@@ -385,10 +397,11 @@ public final class AudioPlaybackConfiguration implements Parcelable {
}
// sets the fields that are updateable and require synchronization
- private void setUpdateableFields(int deviceId, int sessionId, int mutedState, FormatInfo format)
+ private void setUpdateableFields(int[] deviceIds, int sessionId, int mutedState,
+ FormatInfo format)
{
synchronized (mUpdateablePropLock) {
- mDeviceId = deviceId;
+ mDeviceIds = deviceIds;
mSessionId = sessionId;
mMutedState = mutedState;
mFormatInfo = format;
@@ -424,7 +437,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
anonymCopy.mClientPid = PLAYER_UPID_INVALID;
anonymCopy.mIPlayerShell = null;
anonymCopy.setUpdateableFields(
- /*deviceId*/ PLAYER_DEVICEID_INVALID,
+ /*deviceIds*/ new int[0],
/*sessionId*/ AudioSystem.AUDIO_SESSION_ALLOCATE,
/*mutedState*/ 0,
FormatInfo.DEFAULT);
@@ -461,17 +474,46 @@ public final class AudioPlaybackConfiguration implements Parcelable {
/**
* Returns information about the {@link AudioDeviceInfo} used for this playback.
- * @return the audio playback device or null if the device is not available at the time of query
+ * @return the audio playback device or null if the device is not available at the time of
+ * query.
+ * @deprecated this information was never populated
*/
+ @Deprecated
+ @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
public @Nullable AudioDeviceInfo getAudioDeviceInfo() {
- final int deviceId;
+ final int[] deviceIds;
synchronized (mUpdateablePropLock) {
- deviceId = mDeviceId;
+ deviceIds = mDeviceIds;
}
- if (deviceId == PLAYER_DEVICEID_INVALID) {
+ if (deviceIds.length == 0) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+ return AudioManager.getDeviceForPortId(deviceIds[0], AudioManager.GET_DEVICES_OUTPUTS);
+ }
+
+ /**
+ * @hide
+ * Returns information about the List of {@link AudioDeviceInfo} used for this playback.
+ * @return the audio playback devices
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public @NonNull List<AudioDeviceInfo> getAudioDeviceInfos() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds;
+ synchronized (mUpdateablePropLock) {
+ deviceIds = mDeviceIds;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_OUTPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
}
/**
@@ -677,15 +719,15 @@ public final class AudioPlaybackConfiguration implements Parcelable {
* @hide
* Handle a player state change
* @param event
- * @param deviceId active device id or {@Code PLAYER_DEVICEID_INVALID}
- * <br>Note device id is valid for {@code PLAYER_UPDATE_DEVICE_ID} or
- * <br>{@code PLAYER_STATE_STARTED} events, as the device id will be reset to none when
- * <br>pausing or stopping playback. It will be set to active device when playback starts or
+ * @param deviceIds an array of device ids. This can be empty.
+ * <br>Note device ids are non-empty for {@code PLAYER_UPDATE_DEVICE_ID} or
+ * <br>{@code PLAYER_STATE_STARTED} events, as the device ids will be emptied when pausing
+ * <br>or stopping playback. It will be set to active devices when playback starts or
* <br>it will be changed when PLAYER_UPDATE_DEVICE_ID is sent. The latter can happen if the
- * <br>device changes in the middle of playback.
+ * <br>devices change in the middle of playback.
* @return true if the state changed, false otherwise
*/
- public boolean handleStateEvent(int event, int deviceId) {
+ public boolean handleStateEvent(int event, int[] deviceIds) {
boolean changed = false;
synchronized (mUpdateablePropLock) {
@@ -696,8 +738,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
}
if (event == PLAYER_STATE_STARTED || event == PLAYER_UPDATE_DEVICE_ID) {
- changed = changed || (mDeviceId != deviceId);
- mDeviceId = deviceId;
+ changed = changed || !Arrays.equals(mDeviceIds, deviceIds);
+ mDeviceIds = deviceIds;
}
if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) {
@@ -777,8 +819,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public int hashCode() {
synchronized (mUpdateablePropLock) {
- return Objects.hash(mPlayerIId, mDeviceId, mMutedState, mPlayerType, mClientUid,
- mClientPid, mSessionId);
+ return Objects.hash(mPlayerIId, Arrays.toString(mDeviceIds), mMutedState, mPlayerType,
+ mClientUid, mClientPid, mSessionId);
}
}
@@ -791,7 +833,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
synchronized (mUpdateablePropLock) {
dest.writeInt(mPlayerIId);
- dest.writeInt(mDeviceId);
+ dest.writeIntArray(mDeviceIds);
dest.writeInt(mMutedState);
dest.writeInt(mPlayerType);
dest.writeInt(mClientUid);
@@ -810,7 +852,10 @@ public final class AudioPlaybackConfiguration implements Parcelable {
private AudioPlaybackConfiguration(Parcel in) {
mPlayerIId = in.readInt();
- mDeviceId = in.readInt();
+ mDeviceIds = new int[in.readInt()];
+ for (int i = 0; i < mDeviceIds.length; i++) {
+ mDeviceIds[i] = in.readInt();
+ }
mMutedState = in.readInt();
mPlayerType = in.readInt();
mClientUid = in.readInt();
@@ -831,7 +876,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
AudioPlaybackConfiguration that = (AudioPlaybackConfiguration) o;
return ((mPlayerIId == that.mPlayerIId)
- && (mDeviceId == that.mDeviceId)
+ && Arrays.equals(mDeviceIds, that.mDeviceIds)
&& (mMutedState == that.mMutedState)
&& (mPlayerType == that.mPlayerType)
&& (mClientUid == that.mClientUid)
@@ -844,7 +889,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
StringBuilder apcToString = new StringBuilder();
synchronized (mUpdateablePropLock) {
apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append(
- " deviceId:").append(mDeviceId).append(" type:").append(
+ " deviceIds:").append(Arrays.toString(mDeviceIds)).append(" type:").append(
toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append(
mClientUid).append(
"/").append(mClientPid).append(" state:").append(
@@ -875,6 +920,9 @@ public final class AudioPlaybackConfiguration implements Parcelable {
if ((mMutedState & MUTED_BY_PORT_VOLUME) != 0) {
apcToString.append("portVolume ");
}
+ if ((mMutedState & MUTED_BY_OP_CONTROL_AUDIO) != 0) {
+ apcToString.append("opControlAudio ");
+ }
}
apcToString.append(" ").append(mFormatInfo);
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 80e57193d0dc..cacd59f42ec4 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -20,8 +20,10 @@ import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAUL
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -1906,17 +1908,49 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_INPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
* Note: The query is only valid if the AudioRecord is currently recording. If it is not,
* <code>getRoutedDevice()</code> will return null.
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
+ return audioDeviceInfos.get(0);
+ }
+
+ /**
+ * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+ * AudioRecord.
+ * Note: The query is only valid if the AudioRecord is currently playing. If it is not,
+ * <code>getRoutedDevices()</code> will return an empty list.
+ */
+ @Override
+ @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+ public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+ return getRoutedDevicesInternal();
}
/**
@@ -2494,7 +2528,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
int sampleRateInHz, int channelCount, int audioFormat);
private native final boolean native_setInputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java
index 26fa631ac6ac..22aa9a09d560 100644
--- a/media/java/android/media/AudioRouting.java
+++ b/media/java/android/media/AudioRouting.java
@@ -16,9 +16,16 @@
package android.media;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.os.Handler;
import android.os.Looper;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* AudioRouting defines an interface for controlling routing and routing notifications in
* AudioTrack and AudioRecord objects.
@@ -49,6 +56,22 @@ public interface AudioRouting {
public AudioDeviceInfo getRoutedDevice();
/**
+ * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+ * AudioTrack/AudioRecord.
+ * Note: The query is only valid if the AudioTrack/AudioRecord is currently playing.
+ * If it is not, <code>getRoutedDevices()</code> will return an empty List.
+ */
+ @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+ default @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ return new ArrayList<AudioDeviceInfo>();
+ }
+
+ /**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
* changes on this AudioTrack/AudioRecord.
* @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 03cd53580b1b..a5d9adb5cadc 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -17,8 +17,10 @@
package android.media;
import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -54,7 +56,9 @@ import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.NioUtils;
+import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -3019,7 +3023,7 @@ public class AudioTrack extends PlayerBase
}
}
synchronized(mPlayStateLock) {
- baseStart(0); // unknown device at this point
+ baseStart(new int[0]); // unknown device at this point
native_start();
// FIXME see b/179218630
//baseStart(native_getRoutedDeviceId());
@@ -3780,17 +3784,51 @@ public class AudioTrack extends PlayerBase
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_OUTPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack.
* Note: The query is only valid if the AudioTrack is currently playing. If it is not,
* <code>getRoutedDevice()</code> will return null.
+ * Audio may play on multiple devices simultaneously (e.g. an alarm playing on headphones and
+ * speaker on a phone), so prefer using {@link #getRoutedDevices}.
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+ return audioDeviceInfos.get(0);
+ }
+
+ /**
+ * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+ * AudioTrack.
+ * Note: The query is only valid if the AudioTrack is currently playing. If it is not,
+ * <code>getRoutedDevices()</code> will return an empty list.
+ */
+ @Override
+ @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+ public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+ return getRoutedDevicesInternal();
}
private void tryToDisableNativeRoutingCallback() {
@@ -3950,7 +3988,7 @@ public class AudioTrack extends PlayerBase
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
- baseUpdateDeviceId(getRoutedDevice());
+ baseUpdateDeviceIds(getRoutedDevicesInternal());
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
delegate.notifyClient();
@@ -4507,7 +4545,7 @@ public class AudioTrack extends PlayerBase
private native final int native_setAuxEffectSendLevel(float level);
private native final boolean native_setOutputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index 167ab6535843..68a3aa7eb834 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -145,7 +145,14 @@ public class HwAudioSource extends PlayerBase {
mAudioAttributes);
if (isPlaying()) {
// FIXME: b/174876389 clean up device id reporting
- baseStart(getDeviceId());
+ // Set as deviceIds empty and create an array with element if device id is valid.
+ int[] deviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
+ int deviceId = getDeviceId();
+ if (deviceId != 0) {
+ deviceIds = new int[1];
+ deviceIds[0] = deviceId;
+ }
+ baseStart(deviceIds);
}
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9fd3f5beb25c..54a87ad7fd39 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -87,7 +87,7 @@ interface IAudioService {
oneway void playerAttributes(in int piid, in AudioAttributes attr);
- oneway void playerEvent(in int piid, in int event, in int eventId);
+ oneway void playerEvent(in int piid, in int event, in int[] eventId);
oneway void releasePlayer(in int piid);
@@ -640,6 +640,9 @@ interface IAudioService {
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
+ /* Returns a List<Integer> */
+ List getSpatializedChannelMasks();
+
void registerSpatializerCallback(in ISpatializerCallback cb);
void unregisterSpatializerCallback(in ISpatializerCallback cb);
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 93259992d339..0a79f41e1ff0 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -1157,7 +1157,11 @@ public class ImageWriter implements AutoCloseable {
@Override
public void setFence(@NonNull SyncFence fence) throws IOException {
throwISEIfImageIsInvalid();
- nativeSetFenceFd(fence.getFdDup().detachFd());
+ if (fence.isValid()) {
+ nativeSetFenceFd(fence.getFdDup().detachFd());
+ } else {
+ nativeSetFenceFd(-1);
+ }
}
@Override
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 3f9126aa9456..1ecba31ce07f 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -16,10 +16,9 @@
package android.media;
+import static android.media.tv.flags.Flags.FLAG_MEDIACAS_UPDATE_CLIENT_PROFILE_PRIORITY;
import static android.media.tv.flags.Flags.FLAG_SET_RESOURCE_HOLDER_RETAIN;
-import static com.android.media.flags.Flags.FLAG_UPDATE_CLIENT_PROFILE_PRIORITY;
-
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -996,7 +995,7 @@ public final class MediaCas implements AutoCloseable {
* @param niceValue the nice value.
* @hide
*/
- @FlaggedApi(FLAG_UPDATE_CLIENT_PROFILE_PRIORITY)
+ @FlaggedApi(FLAG_MEDIACAS_UPDATE_CLIENT_PROFILE_PRIORITY)
@SystemApi
@RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
public boolean updateResourcePriority(int priority, int niceValue) {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 2ae89d3300c1..82e950365850 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,6 +16,7 @@
package android.media;
+import static android.media.codec.Flags.FLAG_CODEC_AVAILABILITY;
import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import static android.media.codec.Flags.FLAG_SUBSESSION_METRICS;
@@ -29,6 +30,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.ImageFormat;
import android.graphics.Rect;
@@ -1843,6 +1845,12 @@ final public class MediaCodec {
*/
private static final int CB_METRICS_FLUSHED = 8;
+ /**
+ * Callback ID to notify the change in resource requirement
+ * for the codec component.
+ */
+ private static final int CB_REQUIRED_RESOURCES_CHANGE = 9;
+
private class EventHandler extends Handler {
private MediaCodec mCodec;
@@ -2017,13 +2025,19 @@ final public class MediaCodec {
case CB_METRICS_FLUSHED:
{
-
if (GetFlag(() -> android.media.codec.Flags.subsessionMetrics())) {
mCallback.onMetricsFlushed(mCodec, (PersistableBundle)msg.obj);
}
break;
}
+ case CB_REQUIRED_RESOURCES_CHANGE: {
+ if (android.media.codec.Flags.codecAvailability()) {
+ mCallback.onRequiredResourcesChanged(mCodec);
+ }
+ break;
+ }
+
default:
{
break;
@@ -2302,6 +2316,70 @@ final public class MediaCodec {
}
/**
+ * @hide
+ * Abstraction for the Global Codec resources.
+ * This encapsulates all the available codec resources on the device.
+ *
+ * To be able to enforce and test the implementation of codec availability hal APIs,
+ * globally available codec resources are exposed only as TestApi.
+ * This will be tracked and verified through cts.
+ */
+ @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+ @TestApi
+ public static final class GlobalResourceInfo {
+ /**
+ * Identifier for the Resource type.
+ */
+ String mName;
+ /**
+ * Total count/capacity of resources of this type.
+ */
+ long mCapacity;
+ /**
+ * Available count of this resource type.
+ */
+ long mAvailable;
+
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ public long getCapacity() {
+ return mCapacity;
+ }
+
+ public long getAvailable() {
+ return mAvailable;
+ }
+ };
+
+ /**
+ * @hide
+ * Get a list of globally available codec resources.
+ *
+ * To be able to enforce and test the implementation of codec availability hal APIs,
+ * it is exposed only as TestApi.
+ * This will be tracked and verified through cts.
+ *
+ * This returns a {@link java.util.List} list of codec resources.
+ * For every {@link GlobalResourceInfo} in the list, it encapsulates the
+ * information about each resources available globaly on device.
+ *
+ * @return A list of available device codec resources; an empty list if no
+ * device codec resources are available.
+ * @throws UnsupportedOperationException if not implemented.
+ */
+ @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+ @TestApi
+ public static @NonNull List<GlobalResourceInfo> getGloballyAvailableResources() {
+ return native_getGloballyAvailableResources();
+ }
+
+ @NonNull
+ private static native List<GlobalResourceInfo> native_getGloballyAvailableResources();
+
+ /**
* Configures a component.
*
* @param format The format of the input data (decoder) or the desired
@@ -2443,6 +2521,73 @@ final public class MediaCodec {
}
/**
+ * @hide
+ * Abstraction for the resources associated with a codec instance.
+ * This encapsulates the required codec resources for a configured codec instance.
+ *
+ * To be able to enforce and test the implementation of codec availability hal APIs,
+ * required codec resources are exposed only as TestApi.
+ * This will be tracked and verified through cts.
+ */
+ @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+ @TestApi
+ public static final class InstanceResourceInfo {
+ /**
+ * Identifier for the Resource type.
+ */
+ String mName;
+ /**
+ * Required resource count of this type.
+ */
+ long mStaticCount;
+ /**
+ * Per frame resource requirement of this resource type.
+ */
+ long mPerFrameCount;
+
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ public long getStaticCount() {
+ return mStaticCount;
+ }
+
+ public long getPerFrameCount() {
+ return mPerFrameCount;
+ }
+ };
+
+ /**
+ * @hide
+ * Get a list of required codec resources for this configuration.
+ *
+ * To be able to enforce and test the implementation of codec availability hal APIs,
+ * it is exposed only as TestApi.
+ * This will be tracked and verified through cts.
+ *
+ * This returns a {@link java.util.List} list of codec resources.
+ * For every {@link GlobalResourceInfo} in the list, it encapsulates the
+ * information about each resources required for the current configuration.
+ *
+ * NOTE: This may only be called after {@link #configure}.
+ *
+ * @return A list of required device codec resources; an empty list if no
+ * device codec resources are required.
+ * @throws IllegalStateException if the codec wasn't configured yet.
+ * @throws UnsupportedOperationException if not implemented.
+ */
+ @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+ @TestApi
+ public @NonNull List<InstanceResourceInfo> getRequiredResources() {
+ return native_getRequiredResources();
+ }
+
+ @NonNull
+ private native List<InstanceResourceInfo> native_getRequiredResources();
+
+ /**
* Dynamically sets the output surface of a codec.
* <p>
* This can only be used if the codec was configured with an output surface. The
@@ -5740,6 +5885,25 @@ final public class MediaCodec {
@NonNull MediaCodec codec, @NonNull PersistableBundle metrics) {
// default implementation ignores this callback.
}
+
+ /**
+ * @hide
+ * Called when there is a change in the required resources for the codec.
+ * <p>
+ * Upon receiving this notification, the updated resource requirement
+ * can be queried through {@link #getRequiredResources}.
+ *
+ * @param codec The MediaCodec object.
+ */
+ @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+ @TestApi
+ public void onRequiredResourcesChanged(@NonNull MediaCodec codec) {
+ /*
+ * A default implementation for backward compatibility.
+ * Since this is a TestApi, we are not enforcing the callback to be
+ * overridden.
+ */
+ }
}
private void postEventFromNative(
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 96edd63a9b12..302969f58ba8 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -16,14 +16,15 @@
package android.media;
-import static android.media.Utils.intersectSortedDistinctRanges;
-import static android.media.Utils.sortDistinctRanges;
+import static android.media.audio.Flags.FLAG_IAMF_DEFINITIONS_API;
import static android.media.codec.Flags.FLAG_DYNAMIC_COLOR_ASPECTS;
import static android.media.codec.Flags.FLAG_HLG_EDITING;
import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import static android.media.codec.Flags.FLAG_APV_SUPPORT;
+import static android.media.Utils.intersectSortedDistinctRanges;
+import static android.media.Utils.sortDistinctRanges;
import static android.media.MediaCodec.GetFlag;
import android.annotation.FlaggedApi;
@@ -1876,6 +1877,8 @@ public final class MediaCodecInfo {
* Codecs with this security model is not included in
* {@link MediaCodecList#REGULAR_CODECS}, but included in
* {@link MediaCodecList#ALL_CODECS}.
+ *
+ * @hide
*/
@FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2;
@@ -4756,6 +4759,139 @@ public final class MediaCodecInfo {
@FlaggedApi(FLAG_APV_SUPPORT)
public static final int APVLevel71Band3 = 0x200008;
+ // IAMF profiles are defined as the combination of the (listed from LSB to MSB):
+ // - audio codec (2 bytes)
+ // - profile (1 byte, offset 16)
+ // - specification version (1 byte, offset 24)
+ private static final int IAMF_CODEC_OPUS = 0x1;
+ private static final int IAMF_CODEC_AAC = 0x1 << 1;
+ private static final int IAMF_CODEC_FLAC = 0x1 << 2;
+ private static final int IAMF_CODEC_PCM = 0x1 << 3;
+ private static final int IAMF_PROFILE_SIMPLE = 0x1 << 16;
+ private static final int IAMF_PROFILE_BASE = 0x1 << 17;
+ private static final int IAMF_PROFILE_BASE_ENHANCED = 0x1 << 18;
+ private static final int IAMF_v1 = 0x1 << 24;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-simple">simple profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in OPUS.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileSimpleOpus =
+ IAMF_v1 + IAMF_PROFILE_SIMPLE + IAMF_CODEC_OPUS;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-simple">simple profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in AAC.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileSimpleAac =
+ IAMF_v1 + IAMF_PROFILE_SIMPLE + IAMF_CODEC_AAC;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-simple">simple profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in FLAC.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileSimpleFlac =
+ IAMF_v1 + IAMF_PROFILE_SIMPLE + IAMF_CODEC_FLAC;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-simple">simple profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in PCM.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileSimplePcm =
+ IAMF_v1 + IAMF_PROFILE_SIMPLE + IAMF_CODEC_PCM;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base">base profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in OPUS.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBaseOpus =
+ IAMF_v1 + IAMF_PROFILE_BASE + IAMF_CODEC_OPUS;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base">base profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in AAC.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBaseAac =
+ IAMF_v1 + IAMF_PROFILE_BASE + IAMF_CODEC_AAC;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base">base profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in FLAC.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBaseFlac =
+ IAMF_v1 + IAMF_PROFILE_BASE + IAMF_CODEC_FLAC;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base">base profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in PCM.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBasePcm =
+ IAMF_v1 + IAMF_PROFILE_BASE + IAMF_CODEC_PCM;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base-enhanced">base-enhanced profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in OPUS.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBaseEnhancedOpus =
+ IAMF_v1 + IAMF_PROFILE_BASE_ENHANCED + IAMF_CODEC_OPUS;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base-enhanced">base-enhanced profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in AAC.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBaseEnhancedAac =
+ IAMF_v1 + IAMF_PROFILE_BASE_ENHANCED + IAMF_CODEC_AAC;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base-enhanced">base-enhanced profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in FLAC.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBaseEnhancedFlac =
+ IAMF_v1 + IAMF_PROFILE_BASE_ENHANCED + IAMF_CODEC_FLAC;
+ /**
+ * IAMF profile using the
+ * <a href="https://aomediacodec.github.io/iamf/#profiles-base-enhanced">base-enhanced profile</a>
+ * with audio streams <a href="https://aomediacodec.github.io/iamf/#codec_id">encoded</a>
+ * in PCM.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final int IAMFProfileBaseEnhancedPcm =
+ IAMF_v1 + IAMF_PROFILE_BASE_ENHANCED + IAMF_CODEC_PCM;
+
/**
* The profile of the media content. Depending on the type of media this can be
* one of the profile values defined in this class.
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index bd65b2ecb76a..50387548b4ab 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -16,10 +16,12 @@
package android.media;
+import static android.media.audio.Flags.FLAG_IAMF_DEFINITIONS_API;
+import static android.media.codec.Flags.FLAG_APV_SUPPORT;
import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
import static android.media.codec.Flags.FLAG_NUM_INPUT_SLOTS;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
-import static android.media.codec.Flags.FLAG_APV_SUPPORT;
+import static android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES;
import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE;
import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -262,6 +264,11 @@ public final class MediaFormat {
* MIME type for the IEC61937 audio stream encapsulation. This type isn't defined by IANA.
*/
public static final String MIMETYPE_AUDIO_IEC61937 = "audio/x-iec61937";
+ /**
+ * MIME type for IAMF audio stream
+ */
+ @FlaggedApi(FLAG_IAMF_DEFINITIONS_API)
+ public static final String MIMETYPE_AUDIO_IAMF = "audio/iamf";
/**
* MIME type for HEIF still image data encoded in HEVC.
@@ -1748,6 +1755,7 @@ public final class MediaFormat {
(1 << MediaCodecInfo.SECURITY_MODEL_MEMORY_SAFE);
/**
* Flag for {@link MediaCodecInfo#SECURITY_MODEL_TRUSTED_CONTENT_ONLY}.
+ * @hide
*/
@FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY =
@@ -1759,8 +1767,7 @@ public final class MediaFormat {
* The associated value is a flag of the following values:
* {@link FLAG_SECURITY_MODEL_SANDBOXED},
* {@link FLAG_SECURITY_MODEL_MEMORY_SAFE},
- * {@link FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY}. The default value is
- * {@link FLAG_SECURITY_MODEL_SANDBOXED}.
+ * The default value is {@link FLAG_SECURITY_MODEL_SANDBOXED}.
* <p>
* When passed to {@link MediaCodecList#findDecoderForFormat} or
* {@link MediaCodecList#findEncoderForFormat}, MediaCodecList filters
@@ -1789,6 +1796,27 @@ public final class MediaFormat {
public static final String KEY_NUM_SLOTS = "num-slots";
/**
+ * A key describing the picture profile ID to be applied to {@link MediaCodec}.
+ * <p>
+ * The associated value is a string.
+ * <p>
+ * @see {@link android.media.quality.PictureProfile}
+ * @see {@link android.media.quality.PictureProfile#getProfileId}
+ */
+ @FlaggedApi(FLAG_APPLY_PICTURE_PROFILES)
+ public static final String KEY_PICTURE_PROFILE_ID = "picture-profile-id";
+
+ /**
+ * A key describing the picture profile instance to be applied to {@link MediaCodec}.
+ * <p>
+ * The associated value is an instance of {@link android.media.quality.PictureProfile}.
+ * <p>
+ * @see {@link android.media.quality.PictureProfile}
+ */
+ @FlaggedApi(FLAG_APPLY_PICTURE_PROFILES)
+ public static final String KEY_PICTURE_PROFILE_INSTANCE = "picture-profile-instance";
+
+ /**
* QpOffsetRect constitutes the metadata required for encoding a region of interest in an
* image or a video frame. The region of interest is represented by a rectangle. The four
* integer coordinates of the rectangle are stored in fields left, top, right, bottom.
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index a0f8ae5defeb..f1c2a7aec903 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -18,7 +18,9 @@ package android.media;
import static android.Manifest.permission.BIND_IMS_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -84,6 +86,7 @@ import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.ByteOrder;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
@@ -1412,7 +1415,7 @@ public class MediaPlayer extends PlayerBase
}
private void startImpl() {
- baseStart(0); // unknown device at this point
+ baseStart(new int[0]); // unknown device at this point
stayAwake(true);
tryToEnableNativeRoutingCallback();
_start();
@@ -1538,20 +1541,54 @@ public class MediaPlayer extends PlayerBase
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_OUTPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer
* Note: The query is only valid if the MediaPlayer is currently playing.
* If the player is not playing, the returned device can be null or correspond to previously
* selected device when the player was last active.
+ * Audio may play on multiple devices simultaneously (e.g. an alarm playing on headphones and
+ * speaker on a phone), so prefer using {@link #getRoutedDevices}.
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+ return audioDeviceInfos.get(0);
}
+ /**
+ * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+ * MediaPlayer.
+ * Note: The query is only valid if the MediaPlayer is currently playing.
+ * If the player is not playing, the returned devices can be empty or correspond to previously
+ * selected devices when the player was last active.
+ */
+ @Override
+ @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+ public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+ return getRoutedDevicesInternal();
+ }
/**
* Sends device list change notification to all listeners.
@@ -1562,7 +1599,7 @@ public class MediaPlayer extends PlayerBase
// Prevent the case where an event is triggered by registering a routing change
// listener via the media player.
if (mEnableSelfRoutingMonitor) {
- baseUpdateDeviceId(getRoutedDevice());
+ baseUpdateDeviceIds(getRoutedDevicesInternal());
}
for (NativeRoutingEventHandlerDelegate delegate
: mRoutingChangeListeners.values()) {
@@ -1672,7 +1709,7 @@ public class MediaPlayer extends PlayerBase
}
private native final boolean native_setOutputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback(boolean enabled);
/**
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 2d17bf500f12..7af78b81cda5 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,7 +16,10 @@
package android.media;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
+
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -1681,6 +1684,26 @@ public class MediaRecorder implements AudioRouting,
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_INPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaRecorder
* Note: The query is only valid if the MediaRecorder is currently recording.
* If the recorder is not recording, the returned device can be null or correspond to previously
@@ -1688,11 +1711,24 @@ public class MediaRecorder implements AudioRouting,
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
+ return audioDeviceInfos.get(0);
+ }
+
+ /**
+ * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+ * MediaRecorder.
+ * Note: The query is only valid if the MediaRecorder is currently recording.
+ * If the recorder is not recording, the returned devices can be empty or correspond to
+ * previously selected devices when the recorder was last active.
+ */
+ @Override
+ @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+ public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+ return getRoutedDevicesInternal();
}
/*
@@ -1752,7 +1788,7 @@ public class MediaRecorder implements AudioRouting,
}
private native final boolean native_setInputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback(boolean enabled);
//--------------------------------------------------------------------------
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 3f44b09124e4..dbf8338ac99f 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -39,6 +39,8 @@ import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -91,7 +93,7 @@ public abstract class PlayerBase {
@GuardedBy("mLock")
private float mVolMultiplier = 1.0f;
@GuardedBy("mLock")
- private int mDeviceId;
+ private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
/**
* Constructor. Must be given audio attributes, as they are required for AppOps.
@@ -158,35 +160,36 @@ public abstract class PlayerBase {
}
}
- void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) {
- int deviceId = 0;
- if (deviceInfo != null) {
- deviceId = deviceInfo.getId();
+ void baseUpdateDeviceIds(@NonNull List<AudioDeviceInfo> deviceInfos) {
+ int[] deviceIds = new int[deviceInfos.size()];
+ for (int i = 0; i < deviceInfos.size(); i++) {
+ deviceIds[i] = deviceInfos.get(i).getId();
}
+
int piid;
synchronized (mLock) {
piid = mPlayerIId;
- mDeviceId = deviceId;
+ mDeviceIds = deviceIds;
}
try {
getService().playerEvent(piid,
- AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceId);
+ AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceIds);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
- + deviceId
+ + Arrays.toString(deviceIds)
+ " device id will not be tracked for piid=" + piid, e);
}
}
- private void updateState(int state, int deviceId) {
+ private void updateState(int state, @NonNull int[] deviceIds) {
final int piid;
synchronized (mLock) {
mState = state;
piid = mPlayerIId;
- mDeviceId = deviceId;
+ mDeviceIds = deviceIds;
}
try {
- getService().playerEvent(piid, state, deviceId);
+ getService().playerEvent(piid, state, deviceIds);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
+ AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
@@ -194,11 +197,12 @@ public abstract class PlayerBase {
}
}
- void baseStart(int deviceId) {
+ void baseStart(@NonNull int[] deviceIds) {
if (DEBUG) {
- Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId);
+ Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId="
+ + Arrays.toString(deviceIds));
}
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceIds);
}
void baseSetStartDelayMs(int delayMs) {
@@ -215,12 +219,12 @@ public abstract class PlayerBase {
void basePause() {
if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, 0);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, new int[0]);
}
void baseStop() {
if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, 0);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, new int[0]);
}
void baseSetPan(float pan) {
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 7b9ff23596d9..f22cc9c08b4c 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -317,7 +317,7 @@ public class SoundPool extends PlayerBase {
// FIXME: b/174876164 implement device id for soundpool
try {
Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "SoundPool.play");
- baseStart(0);
+ baseStart(new int[0]);
return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId());
} finally {
Trace.traceEnd(Trace.TRACE_TAG_AUDIO);
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index 99fcaf29688c..95c4ad3c3a7f 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -16,7 +16,10 @@
package android.media;
+import static android.media.audio.Flags.FLAG_SPATIALIZER_CAPABILITIES;
+
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -35,6 +38,7 @@ import com.android.internal.annotations.GuardedBy;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -527,6 +531,28 @@ public class Spatializer {
}
/**
+ * Returns a list of channel masks that represent the widest channel masks the spatializer
+ * is capable of rendering with individual channel positions.
+ * For instance a spatializer may only support virtual speaker positions for 5.1, it would
+ * therefore return {@link AudioFormat#CHANNEL_OUT_5POINT1}. But it would still return
+ * <code>true</code> when querying {@link #canBeSpatialized(AudioAttributes, AudioFormat)} it
+ * with a channel mask of {@link AudioFormat#CHANNEL_OUT_7POINT1POINT2}: the sound present
+ * in each channel would still be heard, but the sounds from the rear, side and top pairs would
+ * be mixed together, and be spatialized at the same location.
+ * @return a list of channel masks following the <code>CHANNEL_OUT_*</code> output channel
+ * definitions found in {@link AudioFormat}.
+ */
+ @FlaggedApi(FLAG_SPATIALIZER_CAPABILITIES)
+ public @NonNull List<Integer> getSpatializedChannelMasks() {
+ try {
+ return mAm.getService().getSpatializedChannelMasks();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error querying getSpatializedChannelMasks", e);
+ return Collections.emptyList();
+ }
+ }
+
+ /**
* Adds a listener to be notified of changes to the enabled state of the
* {@code Spatializer}.
* @param executor the {@code Executor} handling the callback
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 7895eb27b372..d8a8c8b0ee2a 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -1,13 +1,7 @@
package: "com.android.media.flags"
container: "system"
-flag {
- name: "enable_rlp_callbacks_in_media_router2"
- is_exported: true
- namespace: "media_solutions"
- description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
- bug: "281067101"
-}
+# Flags are ordered alphabetically by name.
flag {
name: "adjust_volume_for_foreground_app_playing_audio_without_media_session"
@@ -17,6 +11,13 @@ flag {
}
flag {
+ name: "enable_audio_input_device_routing_and_volume_control"
+ namespace: "media_better_together"
+ description: "Allows audio input devices routing and volume control via system settings."
+ bug: "355684672"
+}
+
+flag {
name: "enable_audio_policies_device_and_bluetooth_controller"
is_exported: true
namespace: "media_solutions"
@@ -25,71 +26,70 @@ flag {
}
flag {
- name: "fallback_to_default_handling_when_media_session_has_fixed_volume_handling"
- namespace: "media_solutions"
- description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller."
- bug: "293743975"
-}
-
-flag {
- name: "enable_waiting_state_for_system_session_creation_request"
- namespace: "media_solutions"
- description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id."
- bug: "307723189"
+ name: "enable_built_in_speaker_route_suitability_statuses"
+ is_exported: true
+ namespace: "media_solutions"
+ description: "Make MediaRoute2Info provide information about routes suitability for transfer."
+ bug: "279555229"
}
flag {
- name: "enable_new_media_route_2_info_types"
+ name: "enable_cross_user_routing_in_media_router2"
is_exported: true
namespace: "media_solutions"
- description: "Enables the following type constants in MediaRoute2Info: CAR, COMPUTER, GAME_CONSOLE, SMARTPHONE, SMARTWATCH, TABLET, TABLET_DOCKED. Note that this doesn't gate any behavior. It only guards some API int symbols."
- bug: "301713440"
+ description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users."
+ bug: "288580225"
}
flag {
- name: "enable_new_wired_media_route_2_info_types"
- is_exported: true
- namespace: "media_tv"
- description: "Enables the following type constant in MediaRoute2Info: LINE_ANALOG, LINE_DIGITAL, AUX_LINE"
- bug: "375691732"
+ name: "enable_full_scan_with_media_content_control"
+ namespace: "media_better_together"
+ description: "Allows holders of the MEDIA_CONTENT_CONTROL permission to scan for routes while not in the foreground."
+ bug: "352401364"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
- name: "enable_privileged_routing_for_media_routing_control"
+ name: "enable_get_transferable_routes"
is_exported: true
namespace: "media_solutions"
- description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders."
- bug: "305919655"
+ description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API."
+ bug: "323154573"
}
flag {
- name: "enable_cross_user_routing_in_media_router2"
- is_exported: true
- namespace: "media_solutions"
- description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users."
- bug: "288580225"
+ name: "enable_mirroring_in_media_router_2"
+ namespace: "media_better_together"
+ description: "Enables support for mirroring routes in the MediaRouter2 framework, allowing Output Switcher to offer mirroring routes."
+ bug: "362507305"
}
flag {
- name: "enable_use_of_bluetooth_device_get_alias_for_mr2info_get_name"
+ name: "enable_mr2_service_non_main_bg_thread"
namespace: "media_solutions"
- description: "Use BluetoothDevice.getAlias to populate the name of Bluetooth MediaRoute2Infos."
- bug: "314324170"
+ description: "Enables the use of a background thread in the media routing framework, instead of using the main thread."
+ bug: "310145678"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
- name: "update_client_profile_priority"
+ name: "enable_new_media_route_2_info_types"
+ is_exported: true
namespace: "media_solutions"
- description : "Feature flag to add updateResourcePriority api to MediaCas"
- bug: "300565729"
+ description: "Enables the following type constants in MediaRoute2Info: CAR, COMPUTER, GAME_CONSOLE, SMARTPHONE, SMARTWATCH, TABLET, TABLET_DOCKED. Note that this doesn't gate any behavior. It only guards some API int symbols."
+ bug: "301713440"
}
flag {
- name: "enable_built_in_speaker_route_suitability_statuses"
- is_exported: true
- namespace: "media_solutions"
- description: "Make MediaRoute2Info provide information about routes suitability for transfer."
- bug: "279555229"
+ name: "enable_new_wired_media_route_2_info_types"
+ is_exported: true
+ namespace: "media_tv"
+ description: "Enables the following type constant in MediaRoute2Info: LINE_ANALOG, LINE_DIGITAL, AUX_LINE"
+ bug: "375691732"
}
flag {
@@ -101,11 +101,10 @@ flag {
}
flag {
- name: "enable_get_transferable_routes"
- is_exported: true
+ name: "enable_null_session_in_media_browser_service"
namespace: "media_solutions"
- description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API."
- bug: "323154573"
+ description: "Enables apps owning a MediaBrowserService to disconnect all connected browsers."
+ bug: "185136506"
}
flag {
@@ -116,60 +115,56 @@ flag {
}
flag {
- name: "enable_mr2_service_non_main_bg_thread"
+ name: "enable_prevention_of_manager_scans_when_no_apps_scan"
namespace: "media_solutions"
- description: "Enables the use of a background thread in the media routing framework, instead of using the main thread."
- bug: "310145678"
+ description: "Prevents waking up route providers when no apps are scanning, even if SysUI or Settings are scanning."
+ bug: "319604673"
metadata {
purpose: PURPOSE_BUGFIX
}
}
flag {
- name: "enable_screen_off_scanning"
+ name: "enable_privileged_routing_for_media_routing_control"
is_exported: true
namespace: "media_solutions"
- description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off."
- bug: "281072508"
+ description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders."
+ bug: "305919655"
}
flag {
- name: "enable_null_session_in_media_browser_service"
+ name: "enable_rlp_callbacks_in_media_router2"
+ is_exported: true
namespace: "media_solutions"
- description: "Enables apps owning a MediaBrowserService to disconnect all connected browsers."
- bug: "185136506"
+ description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
+ bug: "281067101"
}
flag {
- name: "enable_prevention_of_manager_scans_when_no_apps_scan"
+ name: "enable_screen_off_scanning"
+ is_exported: true
namespace: "media_solutions"
- description: "Prevents waking up route providers when no apps are scanning, even if SysUI or Settings are scanning."
- bug: "319604673"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
+ description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off."
+ bug: "281072508"
}
flag {
- name: "enable_full_scan_with_media_content_control"
- namespace: "media_better_together"
- description: "Allows holders of the MEDIA_CONTENT_CONTROL permission to scan for routes while not in the foreground."
- bug: "352401364"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
+ name: "enable_use_of_bluetooth_device_get_alias_for_mr2info_get_name"
+ namespace: "media_solutions"
+ description: "Use BluetoothDevice.getAlias to populate the name of Bluetooth MediaRoute2Infos."
+ bug: "314324170"
}
flag {
- name: "enable_audio_input_device_routing_and_volume_control"
- namespace: "media_better_together"
- description: "Allows audio input devices routing and volume control via system settings."
- bug: "355684672"
+ name: "enable_waiting_state_for_system_session_creation_request"
+ namespace: "media_solutions"
+ description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id."
+ bug: "307723189"
}
flag {
- name: "enable_mirroring_in_media_router_2"
- namespace: "media_better_together"
- description: "Enables support for mirroring routes in the MediaRouter2 framework, allowing Output Switcher to offer mirroring routes."
- bug: "362507305"
+ name: "fallback_to_default_handling_when_media_session_has_fixed_volume_handling"
+ namespace: "media_solutions"
+ description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller."
+ bug: "293743975"
}
diff --git a/media/java/android/media/flags/projection.aconfig b/media/java/android/media/flags/projection.aconfig
index 17d1ff6a86a7..b4dee0cab24e 100644
--- a/media/java/android/media/flags/projection.aconfig
+++ b/media/java/android/media/flags/projection.aconfig
@@ -4,17 +4,16 @@ container: "system"
# Project link: https://gantry.corp.google.com/projects/android_platform_window_surfaces/changes
flag {
- name: "limit_manage_media_projection"
- namespace: "lse_desktop_experience"
- description: "Limit signature permission manage_media_projection to the SystemUI role"
- bug: "323008518"
- is_fixed_read_only: true
-}
-
-flag {
name: "media_projection_connected_display"
namespace: "virtual_devices"
description: "Enable recording connected display"
bug: "362720120"
is_exported: true
}
+
+flag {
+ namespace: "media_projection"
+ name: "stop_media_projection_on_call_end"
+ description: "Stops MediaProjection sessions when a call ends"
+ bug: "368336349"
+} \ No newline at end of file
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 8ee966ddc377..dacd1bd06cc0 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,13 +17,14 @@
package android.media.projection;
import android.media.projection.IMediaProjectionCallback;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.app.ActivityOptions.LaunchCookie;
/** {@hide} */
interface IMediaProjection {
void start(IMediaProjectionCallback callback);
- void stop();
+ void stop(StopReason stopReason);
boolean canProjectAudio();
boolean canProjectVideo();
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index b104972572b9..1d92eabb726d 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -16,11 +16,13 @@
package android.media.projection;
+import android.graphics.Rect;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.view.ContentRecordingSession;
@@ -107,12 +109,7 @@ interface IMediaProjectionManager {
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- void stopActiveProjection();
-
- @EnforcePermission("MANAGE_MEDIA_PROJECTION")
- @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
- + ".permission.MANAGE_MEDIA_PROJECTION)")
- void notifyActiveProjectionCapturedContentResized(int width, int height);
+ void stopActiveProjection(in StopReason stopReason);
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
@@ -227,5 +224,11 @@ interface IMediaProjectionManager {
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode);
+ oneway void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode);
+
+ @EnforcePermission("MANAGE_MEDIA_PROJECTION")
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.MANAGE_MEDIA_PROJECTION)")
+ oneway void notifyCaptureBoundsChanged(int contentToRecord, int targetProcessUid,
+ in Rect captureBounds);
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4114f5359ace..f7f10df5786a 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -317,7 +317,7 @@ public final class MediaProjection {
public void stop() {
try {
Log.d(TAG, "Content Recording: stopping projection");
- mImpl.stop();
+ mImpl.stop(StopReason.STOP_HOST_APP);
} catch (RemoteException e) {
Log.e(TAG, "Unable to stop projection", e);
}
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index dc55e41fb74c..9cc2cca441a4 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -297,10 +297,10 @@ public final class MediaProjectionManager {
* Stop the current projection if there is one.
* @hide
*/
- public void stopActiveProjection() {
+ public void stopActiveProjection(@StopReason int stopReason) {
try {
Log.d(TAG, "Content Recording: stopping active projection");
- mService.stopActiveProjection();
+ mService.stopActiveProjection(stopReason);
} catch (RemoteException e) {
Log.e(TAG, "Unable to stop the currently active media projection", e);
}
diff --git a/media/java/android/media/projection/StopReason.aidl b/media/java/android/media/projection/StopReason.aidl
new file mode 100644
index 000000000000..8611def3d2b9
--- /dev/null
+++ b/media/java/android/media/projection/StopReason.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.projection;
+
+/**
+ * Identifies the reason for a MediaProjection being stopped (for metric logging purposes)
+ * @hide
+ */
+@Backing(type="int")
+enum StopReason {
+ STOP_UNKNOWN = 0,
+ STOP_HOST_APP = 1,
+ STOP_TARGET_REMOVED = 2,
+ STOP_DEVICE_LOCKED = 3,
+ STOP_PRIVACY_CHIP = 4,
+ STOP_QS_TILE = 5,
+ STOP_USER_SWITCH = 6,
+ STOP_FOREGROUND_SERVICE_CHANGE = 7,
+ STOP_NEW_PROJECTION = 8,
+ STOP_NEW_MEDIA_ROUTE = 9,
+ STOP_ERROR = 10,
+}
diff --git a/media/java/android/media/quality/AmbientBacklightEvent.java b/media/java/android/media/quality/AmbientBacklightEvent.java
index 3bc6b86c0615..b1483c685fdb 100644
--- a/media/java/android/media/quality/AmbientBacklightEvent.java
+++ b/media/java/android/media/quality/AmbientBacklightEvent.java
@@ -16,9 +16,11 @@
package android.media.quality;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.media.tv.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,8 +29,9 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
- * @hide
+ * Ambient backlight event
*/
+@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
public final class AmbientBacklightEvent implements Parcelable {
/** @hide */
@@ -36,7 +39,7 @@ public final class AmbientBacklightEvent implements Parcelable {
@IntDef({AMBIENT_BACKLIGHT_EVENT_ENABLED, AMBIENT_BACKLIGHT_EVENT_DISABLED,
AMBIENT_BACKLIGHT_EVENT_METADATA,
AMBIENT_BACKLIGHT_EVENT_INTERRUPTED})
- public @interface AmbientBacklightEventTypes {}
+ public @interface Type {}
/**
* Event type for ambient backlight events. The ambient backlight is enabled.
@@ -64,7 +67,10 @@ public final class AmbientBacklightEvent implements Parcelable {
@Nullable
private final AmbientBacklightMetadata mMetadata;
- public AmbientBacklightEvent(int eventType,
+ /**
+ * Constructs AmbientBacklightEvent.
+ */
+ public AmbientBacklightEvent(@Type int eventType,
@Nullable AmbientBacklightMetadata metadata) {
mEventType = eventType;
mMetadata = metadata;
@@ -75,10 +81,20 @@ public final class AmbientBacklightEvent implements Parcelable {
mMetadata = in.readParcelable(AmbientBacklightMetadata.class.getClassLoader());
}
+ /**
+ * Gets event type.
+ */
+ @Type
public int getEventType() {
return mEventType;
}
+ /**
+ * Gets ambient backlight metadata.
+ *
+ * @return the metadata of the event. It's non-null only for
+ * {@link #AMBIENT_BACKLIGHT_EVENT_METADATA}.
+ */
@Nullable
public AmbientBacklightMetadata getMetadata() {
return mMetadata;
@@ -95,7 +111,8 @@ public final class AmbientBacklightEvent implements Parcelable {
return 0;
}
- public static final @NonNull Parcelable.Creator<AmbientBacklightEvent> CREATOR =
+ @NonNull
+ public static final Parcelable.Creator<AmbientBacklightEvent> CREATOR =
new Parcelable.Creator<AmbientBacklightEvent>() {
public AmbientBacklightEvent createFromParcel(Parcel in) {
return new AmbientBacklightEvent(in);
diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.java b/media/java/android/media/quality/AmbientBacklightMetadata.java
index fc779348de11..ad19d0456ab0 100644
--- a/media/java/android/media/quality/AmbientBacklightMetadata.java
+++ b/media/java/android/media/quality/AmbientBacklightMetadata.java
@@ -16,6 +16,10 @@
package android.media.quality;
+import android.annotation.FlaggedApi;
+import android.annotation.IntRange;
+import android.graphics.PixelFormat;
+import android.media.tv.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,9 +28,13 @@ import androidx.annotation.NonNull;
import java.util.Arrays;
/**
- * @hide
+ * Metadata of ambient backlight.
+ *
+ * <p>A metadata instance is sent from ambient backlight hardware in a {@link AmbientBacklightEvent}
+ * with {@link AmbientBacklightEvent#AMBIENT_BACKLIGHT_EVENT_METADATA}.
*/
-public class AmbientBacklightMetadata implements Parcelable {
+@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
+public final class AmbientBacklightMetadata implements Parcelable {
@NonNull
private final String mPackageName;
private final int mCompressAlgorithm;
@@ -37,8 +45,16 @@ public class AmbientBacklightMetadata implements Parcelable {
@NonNull
private final int[] mZonesColors;
- public AmbientBacklightMetadata(@NonNull String packageName, int compressAlgorithm,
- int source, int colorFormat, int horizontalZonesNumber, int verticalZonesNumber,
+ /**
+ * Constructs AmbientBacklightMetadata.
+ */
+ public AmbientBacklightMetadata(
+ @NonNull String packageName,
+ @AmbientBacklightSettings.CompressAlgorithm int compressAlgorithm,
+ @AmbientBacklightSettings.Source int source,
+ @PixelFormat.Format int colorFormat,
+ int horizontalZonesNumber,
+ int verticalZonesNumber,
@NonNull int[] zonesColors) {
mPackageName = packageName;
mCompressAlgorithm = compressAlgorithm;
@@ -59,31 +75,69 @@ public class AmbientBacklightMetadata implements Parcelable {
mZonesColors = in.createIntArray();
}
+ /**
+ * Gets package name of the metadata.
+ */
@NonNull
public String getPackageName() {
return mPackageName;
}
+ /**
+ * Gets compress algorithm.
+ */
+ @AmbientBacklightSettings.CompressAlgorithm
public int getCompressAlgorithm() {
return mCompressAlgorithm;
}
+ /**
+ * Gets source of ambient backlight detection.
+ */
+ @AmbientBacklightSettings.Source
public int getSource() {
return mSource;
}
+ /**
+ * Gets color format.
+ */
+ @PixelFormat.Format
public int getColorFormat() {
return mColorFormat;
}
+ /**
+ * Gets the number of horizontal color zones.
+ *
+ * <p>A color zone is a group of lights that always display the same color.
+ */
+ @IntRange(from = 0)
public int getHorizontalZonesNumber() {
return mHorizontalZonesNumber;
}
+ /**
+ * Gets the number of vertical color zones.
+ *
+ * <p>A color zone is a group of lights that always display the same color.
+ */
+ @IntRange(from = 0)
public int getVerticalZonesNumber() {
return mVerticalZonesNumber;
}
+ /**
+ * Gets color data of all available color zones.
+ *
+ * <p>The format of the color data can be found at {@link #getColorFormat()}.
+ *
+ * @return an array of color data, in row by row (left-to-right then top-to-bottom) order of the
+ * color zones.
+ *
+ * @see #getHorizontalZonesNumber()
+ * @see #getVerticalZonesNumber()
+ */
@NonNull
public int[] getZonesColors() {
return mZonesColors;
diff --git a/media/java/android/media/quality/AmbientBacklightSettings.java b/media/java/android/media/quality/AmbientBacklightSettings.java
index bb782bf1aee4..aa06341977fe 100644
--- a/media/java/android/media/quality/AmbientBacklightSettings.java
+++ b/media/java/android/media/quality/AmbientBacklightSettings.java
@@ -16,7 +16,11 @@
package android.media.quality;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.graphics.PixelFormat;
+import android.media.tv.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -26,10 +30,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Settings for ambient backlight.
- * @hide
+ * Settings to configure ambient backlight hardware.
*/
-public class AmbientBacklightSettings implements Parcelable {
+@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
+public final class AmbientBacklightSettings implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({SOURCE_NONE, SOURCE_AUDIO, SOURCE_VIDEO, SOURCE_AUDIO_VIDEO})
@@ -55,15 +59,6 @@ public class AmbientBacklightSettings implements Parcelable {
*/
public static final int SOURCE_AUDIO_VIDEO = 3;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({COLOR_FORMAT_RGB888})
- public @interface ColorFormat {}
-
- /**
- * The color format is RGB888.
- */
- public static final int COLOR_FORMAT_RGB888 = 1;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -76,7 +71,7 @@ public class AmbientBacklightSettings implements Parcelable {
public static final int ALGORITHM_NONE = 0;
/**
- * The compress algorithm is RLE.
+ * The compress algorithm is run length encoding (RLE).
*/
public static final int ALGORITHM_RLE = 1;
@@ -115,8 +110,16 @@ public class AmbientBacklightSettings implements Parcelable {
*/
private final int mThreshold;
- public AmbientBacklightSettings(int source, int maxFps, int colorFormat,
- int horizontalZonesNumber, int verticalZonesNumber, boolean isLetterboxOmitted,
+ /**
+ * Constructs AmbientBacklightSettings.
+ */
+ public AmbientBacklightSettings(
+ @Source int source,
+ int maxFps,
+ @PixelFormat.Format int colorFormat,
+ int horizontalZonesNumber,
+ int verticalZonesNumber,
+ boolean isLetterboxOmitted,
int threshold) {
mSource = source;
mMaxFps = maxFps;
@@ -137,32 +140,67 @@ public class AmbientBacklightSettings implements Parcelable {
mThreshold = in.readInt();
}
+ /**
+ * Gets source of ambient backlight detection.
+ */
@Source
public int getSource() {
return mSource;
}
+ /**
+ * Gets max frames per second.
+ */
+ @IntRange(from = 1)
public int getMaxFps() {
return mMaxFps;
}
- @ColorFormat
+ /**
+ * Gets color format.
+ */
+ @PixelFormat.Format
public int getColorFormat() {
return mColorFormat;
}
+ /**
+ * Gets the number of horizontal color zones.
+ *
+ * <p>A color zone is a group of lights that always display the same color.
+ */
+ @IntRange(from = 0)
public int getHorizontalZonesNumber() {
return mHorizontalZonesNumber;
}
+ /**
+ * Gets the number of vertical color zones.
+ *
+ * <p>A color zone is a group of lights that always display the same color.
+ */
+ @IntRange(from = 0)
public int getVerticalZonesNumber() {
return mVerticalZonesNumber;
}
+ /**
+ * Returns {@code true} if the black portion of the screen in letter box mode is omitted;
+ * {@code false} otherwise.
+ *
+ * <p>Letter-box is a technique to keep the original aspect ratio when displayed on a screen
+ * with different aspect ratio. Black bars are added to the top and bottom.
+ */
public boolean isLetterboxOmitted() {
return mIsLetterboxOmitted;
}
+ /**
+ * Gets the detection threshold of the ambient light.
+ *
+ * <p>If the color of a color zone is changed but the difference is smaller than the threshold,
+ * the change is ignored.
+ */
public int getThreshold() {
return mThreshold;
}
diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl
index 250d59b7c2d7..b7e75b7e6649 100644
--- a/media/java/android/media/quality/IMediaQualityManager.aidl
+++ b/media/java/android/media/quality/IMediaQualityManager.aidl
@@ -21,6 +21,7 @@ import android.media.quality.IAmbientBacklightCallback;
import android.media.quality.IPictureProfileCallback;
import android.media.quality.ISoundProfileCallback;
import android.media.quality.ParamCapability;
+import android.media.quality.PictureProfileHandle;
import android.media.quality.PictureProfile;
import android.media.quality.SoundProfile;
@@ -38,14 +39,17 @@ interface IMediaQualityManager {
List<String> getPictureProfilePackageNames();
List<String> getPictureProfileAllowList();
void setPictureProfileAllowList(in List<String> packages);
+ PictureProfileHandle getPictureProfileHandle(in String id);
SoundProfile createSoundProfile(in SoundProfile pp);
void updateSoundProfile(in String id, in SoundProfile pp);
void removeSoundProfile(in String id);
- SoundProfile getSoundProfileById(in String id);
+ SoundProfile getSoundProfile(in int type, in String name);
List<SoundProfile> getSoundProfilesByPackage(in String packageName);
List<SoundProfile> getAvailableSoundProfiles();
List<String> getSoundProfilePackageNames();
+ List<String> getSoundProfileAllowList();
+ void setSoundProfileAllowList(in List<String> packages);
void registerPictureProfileCallback(in IPictureProfileCallback cb);
void registerSoundProfileCallback(in ISoundProfileCallback cb);
@@ -63,4 +67,5 @@ interface IMediaQualityManager {
void setAmbientBacklightSettings(in AmbientBacklightSettings settings);
void setAmbientBacklightEnabled(in boolean enabled);
+ boolean isAmbientBacklightEnabled();
}
diff --git a/media/java/android/media/quality/ISoundProfileCallback.aidl b/media/java/android/media/quality/ISoundProfileCallback.aidl
index 72d1524198fd..9043757316bc 100644
--- a/media/java/android/media/quality/ISoundProfileCallback.aidl
+++ b/media/java/android/media/quality/ISoundProfileCallback.aidl
@@ -17,6 +17,7 @@
package android.media.quality;
+import android.media.quality.ParamCapability;
import android.media.quality.SoundProfile;
/**
@@ -24,7 +25,9 @@ import android.media.quality.SoundProfile;
* @hide
*/
oneway interface ISoundProfileCallback {
- void onSoundProfileAdded(in long id, in SoundProfile p);
- void onSoundProfileUpdated(in long id, in SoundProfile p);
- void onSoundProfileRemoved(in long id, in SoundProfile p);
+ void onSoundProfileAdded(in String id, in SoundProfile p);
+ void onSoundProfileUpdated(in String id, in SoundProfile p);
+ void onSoundProfileRemoved(in String id, in SoundProfile p);
+ void onParamCapabilitiesChanged(in String id, in List<ParamCapability> caps);
+ void onError(in int err);
}
diff --git a/media/java/android/media/quality/MediaQualityContract.java b/media/java/android/media/quality/MediaQualityContract.java
index 472d7985b304..3fac74b2a37d 100644
--- a/media/java/android/media/quality/MediaQualityContract.java
+++ b/media/java/android/media/quality/MediaQualityContract.java
@@ -23,7 +23,6 @@ import android.media.tv.flags.Flags;
/**
* The contract between the media quality service and applications. Contains definitions for the
* commonly used parameter names.
- * @hide
*/
@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
public class MediaQualityContract {
@@ -33,6 +32,7 @@ public class MediaQualityContract {
*/
public interface BaseParameters {
String PARAMETER_ID = "_id";
+ String PARAMETER_TYPE = "_type";
String PARAMETER_NAME = "_name";
String PARAMETER_PACKAGE = "_package";
String PARAMETER_INPUT_ID = "_input_id";
@@ -41,7 +41,6 @@ public class MediaQualityContract {
/**
* Parameters picture quality.
- * @hide
*/
public static final class PictureQuality {
/**
@@ -80,12 +79,34 @@ public class MediaQualityContract {
}
/**
- * @hide
+ * Parameters for sound quality.
*/
- public static final class SoundQuality implements BaseParameters {
+ public static final class SoundQuality {
+ /**
+ * The audio volume balance.
+ *
+ * <p>Type: INTEGER
+ */
public static final String PARAMETER_BALANCE = "balance";
+
+ /**
+ * The bass.
+ *
+ * <p>Bass setting adjust the low sound frequencies.
+ * <p>Type: INTEGER
+ */
public static final String PARAMETER_BASS = "bass";
+
+ /**
+ * The treble.
+ *
+ * <p>Treble setting adjust the high sound frequencies.
+ * <p>Type: INTEGER
+ */
public static final String PARAMETER_TREBLE = "treble";
+
+ private SoundQuality() {
+ }
}
private MediaQualityContract() {
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 26d83aca3e7b..50055971d66d 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -20,6 +20,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.media.tv.flags.Flags;
@@ -37,7 +38,6 @@ import java.util.concurrent.Executor;
/**
* Central system API to the overall media quality, which arbitrates interaction between
* applications and media quality service.
- * @hide
*/
@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
@SystemService(Context.MEDIA_QUALITY_SERVICE)
@@ -111,7 +111,7 @@ public final class MediaQualityManager {
};
ISoundProfileCallback spCallback = new ISoundProfileCallback.Stub() {
@Override
- public void onSoundProfileAdded(long profileId, SoundProfile profile) {
+ public void onSoundProfileAdded(String profileId, SoundProfile profile) {
synchronized (mLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
@@ -120,7 +120,7 @@ public final class MediaQualityManager {
}
}
@Override
- public void onSoundProfileUpdated(long profileId, SoundProfile profile) {
+ public void onSoundProfileUpdated(String profileId, SoundProfile profile) {
synchronized (mLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
@@ -129,7 +129,7 @@ public final class MediaQualityManager {
}
}
@Override
- public void onSoundProfileRemoved(long profileId, SoundProfile profile) {
+ public void onSoundProfileRemoved(String profileId, SoundProfile profile) {
synchronized (mLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
@@ -137,6 +137,24 @@ public final class MediaQualityManager {
}
}
}
+ @Override
+ public void onParamCapabilitiesChanged(String profileId, List<ParamCapability> caps) {
+ synchronized (mLock) {
+ for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
+ // TODO: filter callback record
+ record.postParamCapabilitiesChanged(profileId, caps);
+ }
+ }
+ }
+ @Override
+ public void onError(int err) {
+ synchronized (mLock) {
+ for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
+ // TODO: filter callback record
+ record.postError(err);
+ }
+ }
+ }
};
IAmbientBacklightCallback abCallback = new IAmbientBacklightCallback.Stub() {
@Override
@@ -162,7 +180,6 @@ public final class MediaQualityManager {
/**
* Registers a {@link PictureProfileCallback}.
- * @hide
*/
public void registerPictureProfileCallback(
@NonNull @CallbackExecutor Executor executor,
@@ -176,7 +193,6 @@ public final class MediaQualityManager {
/**
* Unregisters the existing {@link PictureProfileCallback}.
- * @hide
*/
public void unregisterPictureProfileCallback(@NonNull final PictureProfileCallback callback) {
Preconditions.checkNotNull(callback);
@@ -198,7 +214,6 @@ public final class MediaQualityManager {
*
* @return the corresponding picture profile if available; {@code null} if the name doesn't
* exist.
- * @hide
*/
@Nullable
public PictureProfile getPictureProfile(
@@ -214,8 +229,9 @@ public final class MediaQualityManager {
/**
* Gets profiles that available to the given package.
*
- * @hide @SystemApi
+ * @hide
*/
+ @SystemApi
@NonNull
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
public List<PictureProfile> getPictureProfilesByPackage(@NonNull String packageName) {
@@ -242,8 +258,9 @@ public final class MediaQualityManager {
* Gets all package names whose picture profiles are available.
*
* @see #getPictureProfilesByPackage(String)
- * @hide @SystemApi
+ * @hide
*/
+ @SystemApi
@NonNull
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
public List<String> getPictureProfilePackageNames() {
@@ -254,18 +271,27 @@ public final class MediaQualityManager {
}
}
+ /**
+ * Gets picture profile handle by profile ID.
+ * @hide
+ */
+ public PictureProfileHandle getPictureProfileHandle(String id) {
+ try {
+ return mService.getPictureProfileHandle(id);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* Creates a picture profile and store it in the system.
*
- * @return the stored profile with an assigned profile ID. {@code null} if it's not created
- * successfully.
- * @hide
+ * <p>If the profile is created successfully,
+ * {@link PictureProfileCallback#onPictureProfileAdded(String, PictureProfile)} is invoked.
*/
- @Nullable
- public PictureProfile createPictureProfile(@NonNull PictureProfile pp) {
+ public void createPictureProfile(@NonNull PictureProfile pp) {
try {
- return mService.createPictureProfile(pp);
+ mService.createPictureProfile(pp);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -274,7 +300,6 @@ public final class MediaQualityManager {
/**
* Updates an existing picture profile and store it in the system.
- * @hide
*/
public void updatePictureProfile(@NonNull String profileId, @NonNull PictureProfile pp) {
try {
@@ -287,7 +312,6 @@ public final class MediaQualityManager {
/**
* Removes a picture profile from the system.
- * @hide
*/
public void removePictureProfile(@NonNull String profileId) {
try {
@@ -299,7 +323,6 @@ public final class MediaQualityManager {
/**
* Registers a {@link SoundProfileCallback}.
- * @hide
*/
public void registerSoundProfileCallback(
@NonNull @CallbackExecutor Executor executor,
@@ -313,7 +336,6 @@ public final class MediaQualityManager {
/**
* Unregisters the existing {@link SoundProfileCallback}.
- * @hide
*/
public void unregisterSoundProfileCallback(@NonNull final SoundProfileCallback callback) {
Preconditions.checkNotNull(callback);
@@ -331,14 +353,16 @@ public final class MediaQualityManager {
/**
- * Gets sound profile by given profile ID.
- * @return the corresponding sound profile if available; {@code null} if the ID doesn't
- * exist or the profile is not accessible to the caller.
- * @hide
+ * Gets sound profile by given profile type and name.
+ *
+ * @return the corresponding sound profile if available; {@code null} if the name doesn't
+ * exist.
*/
- public SoundProfile getSoundProfileById(String profileId) {
+ @Nullable
+ public SoundProfile getSoundProfile(
+ @SoundProfile.ProfileType int type, @NonNull String name) {
try {
- return mService.getSoundProfileById(profileId);
+ return mService.getSoundProfile(type, name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -346,11 +370,14 @@ public final class MediaQualityManager {
/**
- * @SystemApi gets profiles that available to the given package
+ * Gets profiles that available to the given package.
+ *
* @hide
*/
+ @SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
- public List<SoundProfile> getSoundProfilesByPackage(String packageName) {
+ public List<SoundProfile> getSoundProfilesByPackage(@NonNull String packageName) {
try {
return mService.getSoundProfilesByPackage(packageName);
} catch (RemoteException e) {
@@ -359,9 +386,9 @@ public final class MediaQualityManager {
}
/**
- * Gets profiles that available to the caller package
- * @hide
+ * Gets profiles that available to the caller package.
*/
+ @NonNull
public List<SoundProfile> getAvailableSoundProfiles() {
try {
return mService.getAvailableSoundProfiles();
@@ -371,9 +398,14 @@ public final class MediaQualityManager {
}
/**
- * @SystemApi all stored sound profiles of all packages
+ * Gets all package names whose sound profiles are available.
+ *
+ * @see #getSoundProfilesByPackage(String)
+ *
* @hide
*/
+ @SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
public List<String> getSoundProfilePackageNames() {
try {
@@ -387,12 +419,12 @@ public final class MediaQualityManager {
/**
* Creates a sound profile and store it in the system.
*
- * @return the stored profile with an assigned profile ID.
- * @hide
+ * <p>If the profile is created successfully,
+ * {@link SoundProfileCallback#onSoundProfileAdded(String, SoundProfile)} is invoked.
*/
- public SoundProfile createSoundProfile(SoundProfile sp) {
+ public void createSoundProfile(@NonNull SoundProfile sp) {
try {
- return mService.createSoundProfile(sp);
+ mService.createSoundProfile(sp);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -401,9 +433,8 @@ public final class MediaQualityManager {
/**
* Updates an existing sound profile and store it in the system.
- * @hide
*/
- public void updateSoundProfile(String profileId, SoundProfile sp) {
+ public void updateSoundProfile(@NonNull String profileId, @NonNull SoundProfile sp) {
try {
mService.updateSoundProfile(profileId, sp);
} catch (RemoteException e) {
@@ -414,9 +445,8 @@ public final class MediaQualityManager {
/**
* Removes a sound profile from the system.
- * @hide
*/
- public void removeSoundProfile(String profileId) {
+ public void removeSoundProfile(@NonNull String profileId) {
try {
mService.removeSoundProfile(profileId);
} catch (RemoteException e) {
@@ -426,7 +456,6 @@ public final class MediaQualityManager {
/**
* Gets capability information of the given parameters.
- * @hide
*/
@NonNull
public List<ParamCapability> getParamCapabilities(@NonNull List<String> names) {
@@ -444,6 +473,7 @@ public final class MediaQualityManager {
* @see #removePictureProfile(String)
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
@NonNull
public List<String> getPictureProfileAllowList() {
@@ -458,6 +488,7 @@ public final class MediaQualityManager {
* Sets the allowlist of packages that can create and removed picture profiles
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
public void setPictureProfileAllowList(@NonNull List<String> packageNames) {
try {
@@ -468,6 +499,38 @@ public final class MediaQualityManager {
}
/**
+ * Gets the allowlist of packages that can create and removed sound profiles
+ *
+ * @see #createSoundProfile(SoundProfile)
+ * @see #removeSoundProfile(String)
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
+ @NonNull
+ public List<String> getSoundProfileAllowList() {
+ try {
+ return mService.getSoundProfileAllowList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the allowlist of packages that can create and removed sound profiles
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
+ public void setSoundProfileAllowList(@NonNull List<String> packageNames) {
+ try {
+ mService.setSoundProfileAllowList(packageNames);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns {@code true} if media quality HAL is implemented; {@code false} otherwise.
* @hide
*/
@@ -487,6 +550,7 @@ public final class MediaQualityManager {
* @param enabled {@code true} to enable, {@code false} to disable.
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
public void setAutoPictureQualityEnabled(boolean enabled) {
try {
@@ -498,7 +562,6 @@ public final class MediaQualityManager {
/**
* Returns {@code true} if auto picture quality is enabled; {@code false} otherwise.
- * @hide
*/
public boolean isAutoPictureQualityEnabled() {
try {
@@ -515,6 +578,7 @@ public final class MediaQualityManager {
* @param enabled {@code true} to enable, {@code false} to disable.
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
public void setSuperResolutionEnabled(boolean enabled) {
try {
@@ -526,7 +590,6 @@ public final class MediaQualityManager {
/**
* Returns {@code true} if super resolution is enabled; {@code false} otherwise.
- * @hide
*/
public boolean isSuperResolutionEnabled() {
try {
@@ -544,6 +607,7 @@ public final class MediaQualityManager {
* @param enabled {@code true} to enable, {@code false} to disable.
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
public void setAutoSoundQualityEnabled(boolean enabled) {
try {
@@ -555,7 +619,6 @@ public final class MediaQualityManager {
/**
* Returns {@code true} if auto sound quality is enabled; {@code false} otherwise.
- * @hide
*/
public boolean isAutoSoundQualityEnabled() {
try {
@@ -567,7 +630,6 @@ public final class MediaQualityManager {
/**
* Registers a {@link AmbientBacklightCallback}.
- * @hide
*/
public void registerAmbientBacklightCallback(
@NonNull @CallbackExecutor Executor executor,
@@ -581,7 +643,6 @@ public final class MediaQualityManager {
/**
* Unregisters the existing {@link AmbientBacklightCallback}.
- * @hide
*/
public void unregisterAmbientBacklightCallback(
@NonNull final AmbientBacklightCallback callback) {
@@ -602,7 +663,6 @@ public final class MediaQualityManager {
* Set the ambient backlight settings.
*
* @param settings The settings to use for the backlight detector.
- * @hide
*/
public void setAmbientBacklightSettings(
@NonNull AmbientBacklightSettings settings) {
@@ -615,10 +675,20 @@ public final class MediaQualityManager {
}
/**
+ * Returns {@code true} if ambient backlight is enabled; {@code false} otherwise.
+ */
+ public boolean isAmbientBacklightEnabled() {
+ try {
+ return mService.isAmbientBacklightEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Enables or disables the ambient backlight detection.
*
* @param enabled {@code true} to enable, {@code false} to disable.
- * @hide
*/
public void setAmbientBacklightEnabled(boolean enabled) {
try {
@@ -702,7 +772,7 @@ public final class MediaQualityManager {
return mCallback;
}
- public void postSoundProfileAdded(final long id, SoundProfile profile) {
+ public void postSoundProfileAdded(final String id, SoundProfile profile) {
mExecutor.execute(new Runnable() {
@Override
@@ -712,7 +782,7 @@ public final class MediaQualityManager {
});
}
- public void postSoundProfileUpdated(final long id, SoundProfile profile) {
+ public void postSoundProfileUpdated(final String id, SoundProfile profile) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
@@ -721,7 +791,7 @@ public final class MediaQualityManager {
});
}
- public void postSoundProfileRemoved(final long id, SoundProfile profile) {
+ public void postSoundProfileRemoved(final String id, SoundProfile profile) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
@@ -729,6 +799,24 @@ public final class MediaQualityManager {
}
});
}
+
+ public void postParamCapabilitiesChanged(final String id, List<ParamCapability> caps) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onParamCapabilitiesChanged(id, caps);
+ }
+ });
+ }
+
+ public void postError(int error) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onError(error);
+ }
+ });
+ }
}
private static final class AmbientBacklightCallbackRecord {
@@ -755,8 +843,7 @@ public final class MediaQualityManager {
}
/**
- * Callback used to monitor status of picture profiles.
- * @hide
+ * Callback used to monitor status of picture profiles
*/
public abstract static class PictureProfileCallback {
/**
@@ -764,7 +851,6 @@ public final class MediaQualityManager {
*
* @param profileId the ID of the profile.
* @param profile the newly added profile.
- * @hide
*/
public void onPictureProfileAdded(
@NonNull String profileId, @NonNull PictureProfile profile) {
@@ -775,7 +861,6 @@ public final class MediaQualityManager {
*
* @param profileId the ID of the profile.
* @param profile the profile with updated info.
- * @hide
*/
public void onPictureProfileUpdated(
@NonNull String profileId, @NonNull PictureProfile profile) {
@@ -786,7 +871,6 @@ public final class MediaQualityManager {
*
* @param profileId the ID of the profile.
* @param profile the removed profile.
- * @hide
*/
public void onPictureProfileRemoved(
@NonNull String profileId, @NonNull PictureProfile profile) {
@@ -796,7 +880,6 @@ public final class MediaQualityManager {
* This is invoked when an issue has occurred.
*
* @param errorCode the error code
- * @hide
*/
public void onError(@PictureProfile.ErrorCode int errorCode) {
}
@@ -805,52 +888,78 @@ public final class MediaQualityManager {
* This is invoked when parameter capabilities has been changed due to status changes of the
* content.
*
- * @param profileId the ID of the profile used by the media content.
+ * @param profileId the ID of the profile used by the media content. {@code null} if there
+ * is no associated profile
* @param updatedCaps the updated capabilities.
- * @hide
*/
public void onParamCapabilitiesChanged(
- @NonNull String profileId, @NonNull List<ParamCapability> updatedCaps) {
+ @Nullable String profileId, @NonNull List<ParamCapability> updatedCaps) {
}
}
/**
* Callback used to monitor status of sound profiles.
- * @hide
*/
public abstract static class SoundProfileCallback {
/**
- * @hide
+ * This is invoked when a sound profile has been added.
+ *
+ * @param profileId the ID of the profile.
+ * @param profile the newly added profile.
*/
- public void onSoundProfileAdded(long id, SoundProfile profile) {
+ public void onSoundProfileAdded(
+ @NonNull String profileId, @NonNull SoundProfile profile) {
}
+
/**
- * @hide
+ * This is invoked when a sound profile has been updated.
+ *
+ * @param profileId the ID of the profile.
+ * @param profile the profile with updated info.
*/
- public void onSoundProfileUpdated(long id, SoundProfile profile) {
+ public void onSoundProfileUpdated(
+ @NonNull String profileId, @NonNull SoundProfile profile) {
}
+
/**
- * @hide
+ * This is invoked when a sound profile has been removed.
+ *
+ * @param profileId the ID of the profile.
+ * @param profile the removed profile.
+ */
+ public void onSoundProfileRemoved(
+ @NonNull String profileId, @NonNull SoundProfile profile) {
+ }
+
+ /**
+ * This is invoked when an issue has occurred.
+ *
+ * @param errorCode the error code
*/
- public void onSoundProfileRemoved(long id, SoundProfile profile) {
+ public void onError(@SoundProfile.ErrorCode int errorCode) {
}
+
/**
- * @hide
+ * This is invoked when parameter capabilities has been changed due to status changes of the
+ * content.
+ *
+ * @param profileId the ID of the profile used by the media content. {@code null} if there
+ * is no associated profile
+ * @param updatedCaps the updated capabilities.
*/
- public void onError(int errorCode) {
+ public void onParamCapabilitiesChanged(
+ @Nullable String profileId, @NonNull List<ParamCapability> updatedCaps) {
}
}
/**
* Callback used to monitor status of ambient backlight.
- * @hide
*/
public abstract static class AmbientBacklightCallback {
/**
* Called when new ambient backlight event is emitted.
- * @hide
*/
- public void onAmbientBacklightEvent(AmbientBacklightEvent event) {
+ public void onAmbientBacklightEvent(@NonNull AmbientBacklightEvent event) {
}
}
}
diff --git a/media/java/android/media/quality/ParamCapability.java b/media/java/android/media/quality/ParamCapability.java
index 0b698a9c1ad2..ed11abd28379 100644
--- a/media/java/android/media/quality/ParamCapability.java
+++ b/media/java/android/media/quality/ParamCapability.java
@@ -31,7 +31,6 @@ import java.lang.annotation.RetentionPolicy;
/**
* Capability info of media quality parameters
- * @hide
*/
@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
public final class ParamCapability implements Parcelable {
diff --git a/media/java/android/media/quality/PictureProfile.java b/media/java/android/media/quality/PictureProfile.java
index 2be47dd87ef2..dcb4222c3eaf 100644
--- a/media/java/android/media/quality/PictureProfile.java
+++ b/media/java/android/media/quality/PictureProfile.java
@@ -18,11 +18,12 @@ package android.media.quality;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.media.tv.TvInputInfo;
import android.media.tv.flags.Flags;
-import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -33,7 +34,6 @@ import java.lang.annotation.RetentionPolicy;
/**
* Profile for picture quality.
- * @hide
*/
@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
public final class PictureProfile implements Parcelable {
@@ -47,7 +47,7 @@ public final class PictureProfile implements Parcelable {
@NonNull
private final String mPackageName;
@NonNull
- private final Bundle mParams;
+ private final PersistableBundle mParams;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -59,14 +59,14 @@ public final class PictureProfile implements Parcelable {
/**
* System profile type.
*
- * <p>A profile of system type is managed by the system, and readable to the package define in
+ * <p>A profile of system type is managed by the system, and readable to the package returned by
* {@link #getPackageName()}.
*/
public static final int TYPE_SYSTEM = 1;
/**
* Application profile type.
*
- * <p>A profile of application type is managed by the package define in
+ * <p>A profile of application type is managed by the package returned by
* {@link #getPackageName()}.
*/
public static final int TYPE_APPLICATION = 2;
@@ -84,13 +84,11 @@ public final class PictureProfile implements Parcelable {
/**
* Error code for unknown errors.
- * @hide
*/
public static final int ERROR_UNKNOWN = 0;
/**
* Error code for missing necessary permission to handle the profiles.
- * @hide
*/
public static final int ERROR_NO_PERMISSION = 1;
@@ -99,13 +97,11 @@ public final class PictureProfile implements Parcelable {
*
* @see #getProfileType()
* @see #getName()
- * @hide
*/
public static final int ERROR_DUPLICATE = 2;
/**
* Error code for invalid argument.
- * @hide
*/
public static final int ERROR_INVALID_ARGUMENT = 3;
@@ -114,7 +110,6 @@ public final class PictureProfile implements Parcelable {
* list.
*
* @see MediaQualityManager#getPictureProfileAllowList()
- * @hide
*/
public static final int ERROR_NOT_ALLOWLISTED = 4;
@@ -125,7 +120,7 @@ public final class PictureProfile implements Parcelable {
mName = in.readString();
mInputId = in.readString();
mPackageName = in.readString();
- mParams = in.readBundle();
+ mParams = in.readPersistableBundle();
}
@Override
@@ -135,7 +130,7 @@ public final class PictureProfile implements Parcelable {
dest.writeString(mName);
dest.writeString(mInputId);
dest.writeString(mPackageName);
- dest.writeBundle(mParams);
+ dest.writePersistableBundle(mParams);
}
@Override
@@ -168,7 +163,7 @@ public final class PictureProfile implements Parcelable {
@NonNull String name,
@Nullable String inputId,
@NonNull String packageName,
- @NonNull Bundle params) {
+ @NonNull PersistableBundle params) {
this.mId = id;
this.mType = type;
this.mName = name;
@@ -251,13 +246,12 @@ public final class PictureProfile implements Parcelable {
* {@link MediaQualityContract.PictureQuality}.
*/
@NonNull
- public Bundle getParameters() {
- return new Bundle(mParams);
+ public PersistableBundle getParameters() {
+ return new PersistableBundle(mParams);
}
/**
* A builder for {@link PictureProfile}.
- * @hide
*/
public static final class Builder {
@Nullable
@@ -270,7 +264,7 @@ public final class PictureProfile implements Parcelable {
@NonNull
private String mPackageName;
@NonNull
- private Bundle mParams;
+ private PersistableBundle mParams;
/**
* Creates a new Builder.
@@ -291,8 +285,6 @@ public final class PictureProfile implements Parcelable {
mParams = p.getParameters();
}
- /* @hide using by MediaQualityService */
-
/**
* Only used by system to assign the ID.
* @hide
@@ -306,8 +298,9 @@ public final class PictureProfile implements Parcelable {
/**
* Sets profile type.
*
- * @hide @SystemApi
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
@NonNull
public Builder setProfileType(@ProfileType int value) {
@@ -320,8 +313,9 @@ public final class PictureProfile implements Parcelable {
*
* @see PictureProfile#getInputId()
*
- * @hide @SystemApi
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
@NonNull
public Builder setInputId(@NonNull String value) {
@@ -334,8 +328,9 @@ public final class PictureProfile implements Parcelable {
*
* @see PictureProfile#getPackageName()
*
- * @hide @SystemApi
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
@NonNull
public Builder setPackageName(@NonNull String value) {
@@ -349,8 +344,8 @@ public final class PictureProfile implements Parcelable {
* @see PictureProfile#getParameters()
*/
@NonNull
- public Builder setParameters(@NonNull Bundle params) {
- mParams = new Bundle(params);
+ public Builder setParameters(@NonNull PersistableBundle params) {
+ mParams = new PersistableBundle(params);
return this;
}
diff --git a/media/java/android/media/quality/PictureProfileHandle.java b/media/java/android/media/quality/PictureProfileHandle.java
index 2b1cda4eb742..714fd36d664a 100644
--- a/media/java/android/media/quality/PictureProfileHandle.java
+++ b/media/java/android/media/quality/PictureProfileHandle.java
@@ -17,46 +17,58 @@
package android.media.quality;
import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import androidx.annotation.NonNull;
-
-// TODO(b/337330263): Expose as public API after API review
/**
- * A type-safe handle to a picture profile, which represents a collection of parameters used to
- * configure picture processing hardware to enhance the quality of graphic buffers.
+ * A type-safe handle to a picture profile used to apply picture processing to a SurfaceControl.
+ *
+ * A picture profile represents a collection of parameters used to configure picture processing
+ * to enhance the quality of graphic buffers.
+ *
* @hide
*/
-@FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW)
+@SystemApi
+@FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
public final class PictureProfileHandle implements Parcelable {
+ public static final @NonNull PictureProfileHandle NONE = new PictureProfileHandle(0);
+
private final long mId;
- @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW)
+ /** @hide */
public PictureProfileHandle(long id) {
mId = id;
}
- @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW)
+ /** @hide */
+ @SystemApi
+ @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
public long getId() {
return mId;
}
- @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW)
+ /** @hide */
+ @SystemApi
@Override
+ @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(mId);
}
- @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW)
+ /** @hide */
+ @SystemApi
@Override
+ @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
public int describeContents() {
return 0;
}
- @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW)
- @NonNull
- public static final Creator<PictureProfileHandle> CREATOR =
+ /** @hide */
+ @SystemApi
+ @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
+ public static final @NonNull Creator<PictureProfileHandle> CREATOR =
new Creator<PictureProfileHandle>() {
@Override
public PictureProfileHandle createFromParcel(Parcel in) {
diff --git a/media/java/android/media/quality/SoundProfile.java b/media/java/android/media/quality/SoundProfile.java
index 20d117bf15cf..c7fb4dd8486f 100644
--- a/media/java/android/media/quality/SoundProfile.java
+++ b/media/java/android/media/quality/SoundProfile.java
@@ -17,54 +17,119 @@
package android.media.quality;
import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.media.tv.TvInputInfo;
import android.media.tv.flags.Flags;
-import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresPermission;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
- * @hide
+ * Profile for sound quality.
*/
@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
-public class SoundProfile implements Parcelable {
+public final class SoundProfile implements Parcelable {
@Nullable
- private Long mId;
+ private String mId;
+ private final int mType;
@NonNull
private final String mName;
@Nullable
private final String mInputId;
- @Nullable
+ @NonNull
private final String mPackageName;
@NonNull
- private final Bundle mParams;
+ private final PersistableBundle mParams;
- protected SoundProfile(Parcel in) {
- if (in.readByte() == 0) {
- mId = null;
- } else {
- mId = in.readLong();
- }
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, prefix = "TYPE_", value = {
+ TYPE_SYSTEM,
+ TYPE_APPLICATION})
+ public @interface ProfileType {}
+
+ /**
+ * System profile type.
+ *
+ * <p>A profile of system type is managed by the system, and readable to the package returned by
+ * {@link #getPackageName()}.
+ */
+ public static final int TYPE_SYSTEM = 1;
+ /**
+ * Application profile type.
+ *
+ * <p>A profile of application type is managed by the package returned by
+ * {@link #getPackageName()}.
+ */
+ public static final int TYPE_APPLICATION = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, prefix = "ERROR_", value = {
+ ERROR_UNKNOWN,
+ ERROR_NO_PERMISSION,
+ ERROR_DUPLICATE,
+ ERROR_INVALID_ARGUMENT,
+ ERROR_NOT_ALLOWLISTED
+ })
+ public @interface ErrorCode {}
+
+ /**
+ * Error code for unknown errors.
+ */
+ public static final int ERROR_UNKNOWN = 0;
+
+ /**
+ * Error code for missing necessary permission to handle the profiles.
+ */
+ public static final int ERROR_NO_PERMISSION = 1;
+
+ /**
+ * Error code for creating a profile with existing profile type and name.
+ *
+ * @see #getProfileType()
+ * @see #getName()
+ */
+ public static final int ERROR_DUPLICATE = 2;
+
+ /**
+ * Error code for invalid argument.
+ */
+ public static final int ERROR_INVALID_ARGUMENT = 3;
+
+ /**
+ * Error code for the case when an operation requires an allowlist but the caller is not in the
+ * list.
+ *
+ * @see MediaQualityManager#getSoundProfileAllowList()
+ */
+ public static final int ERROR_NOT_ALLOWLISTED = 4;
+
+ private SoundProfile(@NonNull Parcel in) {
+ mId = in.readString();
+ mType = in.readInt();
mName = in.readString();
mInputId = in.readString();
mPackageName = in.readString();
- mParams = in.readBundle();
+ mParams = in.readPersistableBundle();
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- if (mId == null) {
- dest.writeByte((byte) 0);
- } else {
- dest.writeByte((byte) 1);
- dest.writeLong(mId);
- }
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mId);
+ dest.writeInt(mType);
dest.writeString(mName);
dest.writeString(mInputId);
dest.writeString(mPackageName);
- dest.writeBundle(mParams);
+ dest.writePersistableBundle(mParams);
}
@Override
@@ -72,6 +137,7 @@ public class SoundProfile implements Parcelable {
return 0;
}
+ @NonNull
public static final Creator<SoundProfile> CREATOR = new Creator<SoundProfile>() {
@Override
public SoundProfile createFromParcel(Parcel in) {
@@ -91,93 +157,165 @@ public class SoundProfile implements Parcelable {
* @hide
*/
public SoundProfile(
- @Nullable Long id,
+ @Nullable String id,
+ int type,
@NonNull String name,
@Nullable String inputId,
- @Nullable String packageName,
- @NonNull Bundle params) {
+ @NonNull String packageName,
+ @NonNull PersistableBundle params) {
this.mId = id;
+ this.mType = type;
this.mName = name;
- com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, name);
this.mInputId = inputId;
this.mPackageName = packageName;
this.mParams = params;
}
+ /**
+ * Gets profile ID.
+ *
+ * <p>A profile ID is a globally unique ID generated and assigned by the system. For profile
+ * objects retrieved from system (e.g {@link MediaQualityManager#getAvailableSoundProfiles()})
+ * this profile ID is non-null; For profiles built locally with {@link Builder}, it's
+ * {@code null}.
+ *
+ * @return the unique profile ID; {@code null} if the profile is built locally with
+ * {@link Builder}.
+ */
@Nullable
- public Long getProfileId() {
+ public String getProfileId() {
return mId;
}
+ /**
+ * Only used by system to assign the ID.
+ * @hide
+ */
+ public void setProfileId(String id) {
+ mId = id;
+ }
+
+ /**
+ * Gets profile type.
+ */
+ @ProfileType
+ public int getProfileType() {
+ return mType;
+ }
+
+ /**
+ * Gets the profile name.
+ */
@NonNull
public String getName() {
return mName;
}
+ /**
+ * Gets the input ID if the profile is for a TV input.
+ *
+ * @return the corresponding TV input ID; {@code null} if the profile is not associated with a
+ * TV input.
+ *
+ * @see TvInputInfo#getId()
+ */
@Nullable
public String getInputId() {
return mInputId;
}
+ /**
+ * Gets the package name of this profile.
+ *
+ * <p>The package name defines the user of a profile. Only this specific package and system app
+ * can access to this profile.
+ *
+ * @return the package name; {@code null} if the profile is built locally using
+ * {@link Builder} and the package is not set.
+ */
@Nullable
public String getPackageName() {
return mPackageName;
}
+
+ /**
+ * Gets the parameters of this profile.
+ *
+ * <p>The keys of commonly used parameters can be found in
+ * {@link MediaQualityContract.SoundQuality}.
+ */
@NonNull
- public Bundle getParameters() {
- return new Bundle(mParams);
+ public PersistableBundle getParameters() {
+ return new PersistableBundle(mParams);
}
/**
* A builder for {@link SoundProfile}
*/
- public static class Builder {
+ public static final class Builder {
@Nullable
- private Long mId;
+ private String mId;
+ private int mType = TYPE_APPLICATION;
@NonNull
private String mName;
@Nullable
private String mInputId;
- @Nullable
+ @NonNull
private String mPackageName;
@NonNull
- private Bundle mParams;
+ private PersistableBundle mParams;
/**
* Creates a new Builder.
- *
- * @hide
*/
public Builder(@NonNull String name) {
mName = name;
- com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, name);
}
/**
- * Copy constructor.
- *
- * @hide
+ * Copy constructor of builder.
*/
public Builder(@NonNull SoundProfile p) {
mId = null; // ID needs to be reset
+ mType = p.getProfileType();
mName = p.getName();
mPackageName = p.getPackageName();
mInputId = p.getInputId();
+ mParams = p.getParameters();
}
/**
- * Sets profile ID.
- * @hide using by MediaQualityService
+ * Only used by system to assign the ID.
+ * @hide
*/
@NonNull
- public Builder setProfileId(@Nullable Long id) {
+ public Builder setProfileId(@Nullable String id) {
mId = id;
return this;
}
/**
+ * Sets profile type.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
+ @NonNull
+ public Builder setProfileType(@ProfileType int value) {
+ mType = value;
+ return this;
+ }
+
+ /**
* Sets input ID.
+ *
+ * @see SoundProfile#getInputId()
+ *
+ * @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
@NonNull
public Builder setInputId(@NonNull String value) {
mInputId = value;
@@ -186,7 +324,13 @@ public class SoundProfile implements Parcelable {
/**
* Sets package name of the profile.
+ *
+ * @see SoundProfile#getPackageName()
+ *
+ * @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
@NonNull
public Builder setPackageName(@NonNull String value) {
mPackageName = value;
@@ -195,12 +339,15 @@ public class SoundProfile implements Parcelable {
/**
* Sets profile parameters.
+ *
+ * @see SoundProfile#getParameters()
*/
@NonNull
- public Builder setParameters(@NonNull Bundle params) {
- mParams = new Bundle(params);
+ public Builder setParameters(@NonNull PersistableBundle params) {
+ mParams = new PersistableBundle(params);
return this;
}
+
/**
* Builds the instance.
*/
@@ -209,6 +356,7 @@ public class SoundProfile implements Parcelable {
SoundProfile o = new SoundProfile(
mId,
+ mType,
mName,
mInputId,
mPackageName,
diff --git a/media/java/android/media/tv/TvInputServiceExtensionManager.java b/media/java/android/media/tv/TvInputServiceExtensionManager.java
index c514f6ed04ef..b876bcf8cd7e 100644
--- a/media/java/android/media/tv/TvInputServiceExtensionManager.java
+++ b/media/java/android/media/tv/TvInputServiceExtensionManager.java
@@ -20,7 +20,9 @@ import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.StringDef;
+import android.annotation.SystemApi;
import android.media.tv.flags.Flags;
import android.os.IBinder;
import android.os.RemoteException;
@@ -43,6 +45,7 @@ import java.util.Set;
*
* @hide
*/
+@SystemApi
@FlaggedApi(Flags.FLAG_TIF_EXTENSION_STANDARDIZATION)
public final class TvInputServiceExtensionManager {
private static final String TAG = "TvInputServiceExtensionManager";
@@ -186,484 +189,397 @@ public final class TvInputServiceExtensionManager {
@Retention(RetentionPolicy.SOURCE)
public @interface StandardizedExtensionName {}
/**
- * Interface responsible for creating scan session and obtain parameters.
- * @hide
+ * Interface responsible for creating scan session and obtaining related parameters.
*/
public static final String ISCAN_INTERFACE = SCAN_PACKAGE + "IScanInterface";
/**
* Interface that handles scan session and get/store related information.
- * @hide
*/
public static final String ISCAN_SESSION = SCAN_PACKAGE + "IScanSession";
/**
- * Interface that notifies changes related to scan session.
- * @hide
+ * Interface that notifies changes related to a scan session.
*/
public static final String ISCAN_LISTENER = SCAN_PACKAGE + "IScanListener";
/**
* Interface for setting HDPlus information.
- * @hide
*/
public static final String IHDPLUS_INFO = SCAN_PACKAGE + "IHDPlusInfo";
/**
* Interface for handling operator detection for scanning.
- * @hide
*/
public static final String IOPERATOR_DETECTION = SCAN_PACKAGE + "IOperatorDetection";
/**
- * Interface for changes related to operator detection searches.
- * @hide
+ * Interface for notifying changes related to operator detection searches.
*/
public static final String IOPERATOR_DETECTION_LISTENER = SCAN_PACKAGE
+ "IOperatorDetectionListener";
/**
* Interface for handling region channel list for scanning.
- * @hide
*/
public static final String IREGION_CHANNEL_LIST = SCAN_PACKAGE + "IRegionChannelList";
/**
- * Interface for changes related to changes in region channel list search.
- * @hide
+ * Interface for notifying changes related to changes in region channel list search.
*/
public static final String IREGION_CHANNEL_LIST_LISTENER = SCAN_PACKAGE
+ "IRegionChannelListListener";
/**
* Interface for handling target region information.
- * @hide
*/
public static final String ITARGET_REGION = SCAN_PACKAGE + "ITargetRegion";
/**
- * Interface for changes related to target regions during scanning.
- * @hide
+ * Interface for detecting changes related to target regions.
*/
public static final String ITARGET_REGION_LISTENER = SCAN_PACKAGE + "ITargetRegionListener";
/**
- * Interface for handling LCN conflict groups.
- * @hide
+ * Interface for handling logical channel number conflict groups.
*/
public static final String ILCN_CONFLICT = SCAN_PACKAGE + "ILcnConflict";
/**
- * Interface for detecting LCN conflicts during scanning.
- * @hide
+ * Interface for notifying changes in handling logical channel number conflicts.
*/
public static final String ILCN_CONFLICT_LISTENER = SCAN_PACKAGE + "ILcnConflictListener";
/**
- * Interface for handling LCN V2 channel list information.
- * @hide
+ * Interface for handling the updated standard for assigning logical channel numbers.
*/
public static final String ILCNV2_CHANNEL_LIST = SCAN_PACKAGE + "ILcnV2ChannelList";
/**
- * Interface for detecting LCN V2 channel list during scanning.
- * @hide
+ * Interface for notifying changes in assigning logical channel numbers with updated standard.
*/
public static final String ILCNV2_CHANNEL_LIST_LISTENER = SCAN_PACKAGE
+ "ILcnV2ChannelListListener";
/**
* Interface for handling favorite network related information.
- * @hide
*/
public static final String IFAVORITE_NETWORK = SCAN_PACKAGE + "IFavoriteNetwork";
/**
- * Interface for detecting favorite network during scanning.
- * @hide
+ * Interface for notifying changes favorite network during scanning.
*/
public static final String IFAVORITE_NETWORK_LISTENER = SCAN_PACKAGE
+ "IFavoriteNetworkListener";
/**
- * Interface for handling Turksat channel update system service.
- * @hide
+ * Interface for handling Turksat(TKGS) channel update system service.
*/
public static final String ITKGS_INFO = SCAN_PACKAGE + "ITkgsInfo";
/**
- * Interface for changes related to TKGS information.
- * @hide
+ * Interface for notifying changes related to Turksat(TKGS) information.
*/
public static final String ITKGS_INFO_LISTENER = SCAN_PACKAGE + "ITkgsInfoListener";
/**
* Interface for satellite search related to low noise block downconverter.
- * @hide
*/
public static final String ISCAN_SAT_SEARCH = SCAN_PACKAGE + "IScanSatSearch";
/**
* Interface for Over-the-Air Download.
- * @hide
*/
public static final String IOAD_UPDATE_INTERFACE = OAD_PACKAGE + "IOadUpdateInterface";
/**
* Interface for handling conditional access module app related information.
- * @hide
*/
public static final String ICAM_APP_INFO_SERVICE = CAM_PACKAGE + "ICamAppInfoService";
/**
- * Interface for changes on conditional access module app related information.
- * @hide
+ * Interface for notifying changes on conditional access module app related information.
*/
public static final String ICAM_APP_INFO_LISTENER = CAM_PACKAGE + "ICamAppInfoListener";
/**
* Interface for handling conditional access module related information.
- * @hide
*/
public static final String ICAM_MONITORING_SERVICE = CAM_PACKAGE + "ICamMonitoringService";
/**
- * Interface for changes on conditional access module related information.
- * @hide
+ * Interface for notifying changes on conditional access module related information.
*/
public static final String ICAM_INFO_LISTENER = CAM_PACKAGE + "ICamInfoListener";
/**
- * Interface for handling control of CI+ operations.
- * @hide
+ * Interface for handling control of common interface plus operations.
*/
public static final String ICI_OPERATOR_INTERFACE = CAM_PACKAGE + "ICiOperatorInterface";
/**
- * Interfaces for changes on CI+ operations.
- * @hide
+ * Interfaces for notifying changes on common interface plus operations.
*/
public static final String ICI_OPERATOR_LISTENER = CAM_PACKAGE + "ICiOperatorListener";
/**
* Interface for handling conditional access module profile related information.
- * @hide
*/
public static final String ICAM_PROFILE_INTERFACE = CAM_PACKAGE + "ICamProfileInterface";
/**
- * Interface for handling conditional access module DRM related information.
- * @hide
+ * Interface for handling conditional access module digital rights management (DRM)
+ * related information.
*/
public static final String ICONTENT_CONTROL_SERVICE = CAM_PACKAGE + "IContentControlService";
/**
- * Interface for changes on DRM.
- * @hide
+ * Interface for notifying changes on digital rights management (DRM).
*/
public static final String ICAM_DRM_INFO_LISTENER = CAM_PACKAGE + "ICamDrmInfoListener";
/**
* Interface for handling conditional access module pin related information.
- * @hide
*/
public static final String ICAM_PIN_SERVICE = CAM_PACKAGE + "ICamPinService";
/**
- * Interface for changes on conditional access module pin capability.
- * @hide
+ * Interface for notifying changes on conditional access module pin capability.
*/
public static final String ICAM_PIN_CAPABILITY_LISTENER = CAM_PACKAGE
+ "ICamPinCapabilityListener";
/**
- * Interface for changes on conditional access module pin status.
- * @hide
+ * Interface for notifying changes on conditional access module pin status.
*/
public static final String ICAM_PIN_STATUS_LISTENER = CAM_PACKAGE + "ICamPinStatusListener";
/**
* Interface for handling conditional access module host control service.
- * @hide
*/
public static final String ICAM_HOST_CONTROL_SERVICE = CAM_PACKAGE + "ICamHostControlService";
/**
* Interface for handling conditional access module ask release reply.
- * @hide
*/
public static final String ICAM_HOST_CONTROL_ASK_RELEASE_REPLY_CALLBACK = CAM_PACKAGE
+ "ICamHostControlAskReleaseReplyCallback";
/**
- * Interface for changes on conditional access module host control service.
- * @hide
+ * Interface for notifying changes on conditional access module host control service.
*/
public static final String ICAM_HOST_CONTROL_INFO_LISTENER = CAM_PACKAGE
+ "ICamHostControlInfoListener";
/**
* Interface for handling conditional access module host control service tune_quietly_flag.
- * @hide
*/
public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG = CAM_PACKAGE
+ "ICamHostControlTuneQuietlyFlag";
/**
- * Interface for changes on conditional access module host control service tune_quietly_flag.
- * @hide
+ * Interface for notifying changes on conditional access module host control service
+ * tune_quietly_flag.
*/
public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG_LISTENER = CAM_PACKAGE
+ "ICamHostControlTuneQuietlyFlagListener";
/**
- * Interface for handling conditional access module multi media interface.
- * @hide
+ * Interface for handling conditional access module multi-media interface.
*/
public static final String IMMI_INTERFACE = CAM_PACKAGE + "IMmiInterface";
/**
- * Interface for controlling conditional access module multi media session.
- * @hide
+ * Interface for controlling conditional access module multi-media session.
*/
public static final String IMMI_SESSION = CAM_PACKAGE + "IMmiSession";
/**
- * Interface for changes on conditional access module multi media session status.
- * @hide
+ * Interface for notifying changes on conditional access module multi-media session status.
*/
public static final String IMMI_STATUS_CALLBACK = CAM_PACKAGE + "IMmiStatusCallback";
/**
- * Interface for changes on conditional access app info related to entering menu.
- * @hide
+ * Interface for notifying changes on conditional access app info related to entering menu.
*/
public static final String IENTER_MENU_ERROR_CALLBACK = CAM_PACKAGE + "IEnterMenuErrorCallback";
/**
- * Interface for handling RRT downloadable rating data.
- * @hide
+ * Interface for handling Region Rating Table downloadable rating data.
*/
public static final String IDOWNLOADABLE_RATING_TABLE_MONITOR = RATING_PACKAGE
+ "IDownloadableRatingTableMonitor";
/**
- * Interface for handling RRT rating related information.
- * @hide
+ * Interface for handling Region Rating Table rating system related information.
*/
public static final String IRATING_INTERFACE = RATING_PACKAGE + "IRatingInterface";
/**
- * Interface for handling PMT rating related information.
- * @hide
+ * Interface for handling Program Map Table rating related information.
*/
public static final String IPMT_RATING_INTERFACE = RATING_PACKAGE + "IPmtRatingInterface";
/**
- * Interface for changes on PMT rating related information.
- * @hide
+ * Interface for notifying changes on Program Map Table rating related information.
*/
public static final String IPMT_RATING_LISTENER = RATING_PACKAGE + "IPmtRatingListener";
/**
- * Interface for handling IVBI rating related information.
- * @hide
+ * Interface for handling Vertical Blanking Interval rating related information.
*/
public static final String IVBI_RATING_INTERFACE = RATING_PACKAGE + "IVbiRatingInterface";
/**
- * Interface for changes on IVBI rating related information.
- * @hide
+ * Interface for notifying changes on Vertical Blanking Interval rating related information.
*/
public static final String IVBI_RATING_LISTENER = RATING_PACKAGE + "IVbiRatingListener";
/**
* Interface for handling program rating related information.
- * @hide
*/
public static final String IPROGRAM_INFO = RATING_PACKAGE + "IProgramInfo";
/**
- * Interface for changes on program rating related information.
- * @hide
+ * Interface for notifying changes on program rating related information.
*/
public static final String IPROGRAM_INFO_LISTENER = RATING_PACKAGE + "IProgramInfoListener";
/**
* Interface for getting broadcast time related information.
- * @hide
*/
- public static final String IBROADCAST_TIME = TIME_PACKAGE + "BroadcastTime";
+ public static final String IBROADCAST_TIME = TIME_PACKAGE + "IBroadcastTime";
/**
* Interface for handling data service signal information on teletext.
- * @hide
*/
public static final String IDATA_SERVICE_SIGNAL_INFO = TELETEXT_PACKAGE
+ "IDataServiceSignalInfo";
/**
- * Interface for changes on data service signal information on teletext.
- * @hide
+ * Interface for notifying changes on data service signal information on teletext.
*/
public static final String IDATA_SERVICE_SIGNAL_INFO_LISTENER = TELETEXT_PACKAGE
+ "IDataServiceSignalInfoListener";
/**
* Interface for handling teletext page information.
- * @hide
*/
public static final String ITELETEXT_PAGE_SUB_CODE = TELETEXT_PACKAGE + "ITeletextPageSubCode";
/**
* Interface for handling scan background service update.
- * @hide
*/
public static final String ISCAN_BACKGROUND_SERVICE_UPDATE = SCAN_BSU_PACKAGE
+ "IScanBackgroundServiceUpdate";
/**
- * Interface for changes on background service update
- * @hide
+ * Interface for notifying changes on background service update
*/
public static final String ISCAN_BACKGROUND_SERVICE_UPDATE_LISTENER = SCAN_BSU_PACKAGE
+ "IScanBackgroundServiceUpdateListener";
/**
* Interface for generating client token.
- * @hide
*/
public static final String ICLIENT_TOKEN = CLIENT_TOKEN_PACKAGE + "IClientToken";
/**
* Interfaces for handling screen mode information.
- * @hide
*/
public static final String ISCREEN_MODE_SETTINGS = SCREEN_MODE_PACKAGE + "IScreenModeSettings";
/**
* Interfaces for handling HDMI signal information update.
- * @hide
*/
public static final String IHDMI_SIGNAL_INTERFACE = SIGNAL_PACKAGE + "IHdmiSignalInterface";
/**
- * Interfaces for changes on HDMI signal information update.
- * @hide
+ * Interfaces for notifying changes on HDMI signal information update.
*/
public static final String IHDMI_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
+ "IHdmiSignalInfoListener";
/**
* Interfaces for handling audio signal information update.
- * @hide
*/
public static final String IAUDIO_SIGNAL_INFO = SIGNAL_PACKAGE + "IAudioSignalInfo";
/**
* Interfaces for handling analog audio signal information update.
- * @hide
*/
public static final String IANALOG_AUDIO_INFO = SIGNAL_PACKAGE + "IAnalogAudioInfo";
/**
- * Interfaces for change on audio signal information update.
- * @hide
+ * Interfaces for notifying changes on audio signal information update.
*/
public static final String IAUDIO_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
+ "IAudioSignalInfoListener";
/**
* Interfaces for handling video signal information update.
- * @hide
*/
public static final String IVIDEO_SIGNAL_INFO = SIGNAL_PACKAGE + "IVideoSignalInfo";
/**
- * Interfaces for changes on video signal information update.
- * @hide
+ * Interfaces for notifying changes on video signal information update.
*/
public static final String IVIDEO_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
+ "IVideoSignalInfoListener";
/**
* Interfaces for handling service database updates.
- * @hide
*/
public static final String ISERVICE_LIST_EDIT = SERVICE_DATABASE_PACKAGE + "IServiceListEdit";
/**
- * Interfaces for changes on service database updates.
- * @hide
+ * Interfaces for notifying changes on service database updates.
*/
public static final String ISERVICE_LIST_EDIT_LISTENER = SERVICE_DATABASE_PACKAGE
+ "IServiceListEditListener";
/**
* Interfaces for getting service database related information.
- * @hide
*/
public static final String ISERVICE_LIST = SERVICE_DATABASE_PACKAGE + "IServiceList";
/**
* Interfaces for transferring service database related information.
- * @hide
*/
public static final String ISERVICE_LIST_TRANSFER_INTERFACE = SERVICE_DATABASE_PACKAGE
+ "IServiceListTransferInterface";
/**
* Interfaces for exporting service database session.
- * @hide
*/
public static final String ISERVICE_LIST_EXPORT_SESSION = SERVICE_DATABASE_PACKAGE
+ "IServiceListExportSession";
/**
- * Interfaces for changes on exporting service database session.
- * @hide
+ * Interfaces for notifying changes on exporting service database session.
*/
public static final String ISERVICE_LIST_EXPORT_LISTENER = SERVICE_DATABASE_PACKAGE
+ "IServiceListExportListener";
/**
* Interfaces for importing service database session.
- * @hide
*/
public static final String ISERVICE_LIST_IMPORT_SESSION = SERVICE_DATABASE_PACKAGE
+ "IServiceListImportSession";
/**
- * Interfaces for changes on importing service database session.
- * @hide
+ * Interfaces for notifying changes on importing service database session.
*/
public static final String ISERVICE_LIST_IMPORT_LISTENER = SERVICE_DATABASE_PACKAGE
+ "IServiceListImportListener";
/**
* Interfaces for setting channel list resources.
- * @hide
*/
public static final String ISERVICE_LIST_SET_CHANNEL_LIST_SESSION = SERVICE_DATABASE_PACKAGE
+ "IServiceListSetChannelListSession";
/**
- * Interfaces for changes on setting channel list resources.
- * @hide
+ * Interfaces for notifying changes on setting channel list resources.
*/
public static final String ISERVICE_LIST_SET_CHANNEL_LIST_LISTENER = SERVICE_DATABASE_PACKAGE
+ "IServiceListSetChannelListListener";
/**
* Interfaces for transferring channel list resources.
- * @hide
*/
public static final String ICHANNEL_LIST_TRANSFER = SERVICE_DATABASE_PACKAGE
+ "IChannelListTransfer";
/**
- * Interfaces for record contents updates.
- * @hide
+ * Interface for operations related to recorded contents.
*/
public static final String IRECORDED_CONTENTS = PVR_PACKAGE + "IRecordedContents";
/**
- * Interfaces for changes on deleting record contents.
- * @hide
+ * Interfaces for notifying changes on deleting record contents.
*/
public static final String IDELETE_RECORDED_CONTENTS_CALLBACK = PVR_PACKAGE
+ "IDeleteRecordedContentsCallback";
/**
- * Interfaces for changes on getting record contents.
- * @hide
+ * Interfaces for notifying changes on getting record contents.
*/
public static final String IGET_INFO_RECORDED_CONTENTS_CALLBACK = PVR_PACKAGE
+ "IGetInfoRecordedContentsCallback";
/**
* Interfaces for monitoring present event information.
- * @hide
*/
public static final String IEVENT_MONITOR = EVENT_PACKAGE + "IEventMonitor";
/**
- * Interfaces for changes on present event information.
- * @hide
+ * Interfaces for notifying changes on present event information.
*/
public static final String IEVENT_MONITOR_LISTENER = EVENT_PACKAGE + "IEventMonitorListener";
/**
* Interfaces for handling download event information.
- * @hide
*/
public static final String IEVENT_DOWNLOAD = EVENT_PACKAGE + "IEventDownload";
/**
- * Interfaces for changes on downloading event information.
- * @hide
+ * Interfaces for notifying changes on downloading event information.
*/
public static final String IEVENT_DOWNLOAD_LISTENER = EVENT_PACKAGE + "IEventDownloadListener";
/**
- * Interfaces for handling download event information for DVB and DTMB.
- * @hide
+ * Interfaces for handling download event information for Digital Video Broadcast
+ * and Digital Terrestrial Multimedia Broadcast.
*/
public static final String IEVENT_DOWNLOAD_SESSION = EVENT_PACKAGE + "IEventDownloadSession";
/**
* Interfaces for handling analog color system.
- * @hide
*/
public static final String IANALOG_ATTRIBUTE_INTERFACE = ANALOG_PACKAGE
+ "IAnalogAttributeInterface";
/**
* Interfaces for monitoring channel tuned information.
- * @hide
*/
public static final String ICHANNEL_TUNED_INTERFACE = TUNE_PACKAGE + "IChannelTunedInterface";
/**
- * Interfaces for changes on channel tuned information.
- * @hide
+ * Interfaces for notifying changes on channel tuned information.
*/
public static final String ICHANNEL_TUNED_LISTENER = TUNE_PACKAGE + "IChannelTunedListener";
/**
* Interfaces for handling tuner frontend signal info.
- * @hide
*/
public static final String ITUNER_FRONTEND_SIGNAL_INFO_INTERFACE = SIGNAL_PACKAGE
+ "ITunerFrontendSignalInfoInterface";
/**
- * Interfaces for changes on tuner frontend signal info.
- * @hide
+ * Interfaces for notifying changes on tuner frontend signal info.
*/
public static final String ITUNER_FRONTEND_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
+ "ITunerFrontendSignalInfoListener";
/**
* Interfaces for handling mux tune operations.
- * @hide
*/
public static final String IMUX_TUNE_SESSION = TUNE_PACKAGE + "IMuxTuneSession";
/**
* Interfaces for initing mux tune session.
- * @hide
*/
public static final String IMUX_TUNE = TUNE_PACKAGE + "IMuxTune";
@@ -784,20 +700,22 @@ public final class TvInputServiceExtensionManager {
}
/**
- * This function should be used by OEM to register IBinder objects that implement
- * standardized AIDL interfaces.
+ * Registers IBinder objects that implement standardized AIDL interfaces.
+ * <p>This function should be used by SoCs/OEMs
*
* @param extensionName Extension Interface Name
* @param binder IBinder object to be registered
- * @return REGISTER_SUCCESS on success of registering IBinder object
- * REGISTER_FAIL_NAME_NOT_STANDARDIZED on failure due to registering extension with
- * non-standardized name
- * REGISTER_FAIL_IMPLEMENTATION_NOT_STANDARDIZED on failure due to IBinder not
+ * @return {@link #REGISTER_SUCCESS} on success of registering IBinder object
+ * {@link #REGISTER_FAIL_NAME_NOT_STANDARDIZED} on failure due to registering extension
+ * with non-standardized name
+ * {@link #REGISTER_FAIL_IMPLEMENTATION_NOT_STANDARDIZED} on failure due to IBinder not
* implementing standardized AIDL interface
- * REGISTER_FAIL_REMOTE_EXCEPTION on failure due to remote exception
+ * {@link #REGISTER_FAIL_REMOTE_EXCEPTION} on failure due to remote exception
*
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
@RegisterResult
public int registerExtensionIBinder(@StandardizedExtensionName @NonNull String extensionName,
@NonNull IBinder binder) {
diff --git a/media/java/android/media/tv/ad/TvAdView.java b/media/java/android/media/tv/ad/TvAdView.java
index dd2a534676d8..ff0279fef99e 100644
--- a/media/java/android/media/tv/ad/TvAdView.java
+++ b/media/java/android/media/tv/ad/TvAdView.java
@@ -240,6 +240,38 @@ public class TvAdView extends ViewGroup {
}
}
+ /**
+ * Controls whether the TvAdView's surface is placed on top of other regular surface views in
+ * the window (but still behind the window itself).
+ *
+ * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
+ *
+ * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false}
+ * otherwise.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
+ public void setZOrderMediaOverlay(boolean isMediaOverlay) {
+ if (mSurfaceView != null) {
+ mSurfaceView.setZOrderOnTop(false);
+ mSurfaceView.setZOrderMediaOverlay(isMediaOverlay);
+ }
+ }
+
+ /**
+ * Controls whether the TvAdView's surface is placed on top of its window.
+ *
+ * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
+ *
+ * @param onTop {@code true} to be on top of its window, {@code false} otherwise.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
+ public void setZOrderOnTop(boolean onTop) {
+ if (mSurfaceView != null) {
+ mSurfaceView.setZOrderMediaOverlay(false);
+ mSurfaceView.setZOrderOnTop(onTop);
+ }
+ }
+
private void resetSurfaceView() {
if (mSurfaceView != null) {
mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback);
diff --git a/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl b/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl
new file mode 100644
index 000000000000..550acba8ed65
--- /dev/null
+++ b/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.analog;
+
+/**
+ * @hide
+ */
+interface IAnalogAttributeInterface {
+ int getVersion();
+ void setColorSystemCapability(in String[] list);
+ String[] getColorSystemCapability();
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamAppInfoListener.aidl b/media/java/android/media/tv/extension/cam/ICamAppInfoListener.aidl
new file mode 100644
index 000000000000..73ae209062d6
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamAppInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamAppInfoListener {
+ void onCamAppInfoChanged(int slotId, in Bundle appInfo);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamAppInfoService.aidl b/media/java/android/media/tv/extension/cam/ICamAppInfoService.aidl
new file mode 100644
index 000000000000..d3a03bc80056
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamAppInfoService.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamAppInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamAppInfoService {
+ // Register ICamAppInfoListener to get CICAM Application Information updates.
+ void addCamAppInfoListener(ICamAppInfoListener listener);
+ // Unregister ICamAppInfoListener and stop get Application Information notify.
+ void removeCamAppInfoListener(ICamAppInfoListener listener);
+ // Get the Application Information of the CICAM.
+ int getCamAppInfo(int slotId, out Bundle appInfo);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamDrmInfoListener.aidl b/media/java/android/media/tv/extension/cam/ICamDrmInfoListener.aidl
new file mode 100644
index 000000000000..c727837ed07e
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamDrmInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamDrmInfoListener {
+ void onCamDrmInfoChanged(int slotId, in Bundle camDrmInfo);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamHostControlAskReleaseReplyCallback.aidl b/media/java/android/media/tv/extension/cam/ICamHostControlAskReleaseReplyCallback.aidl
new file mode 100644
index 000000000000..83f2c01e4681
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlAskReleaseReplyCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface ICamHostControlAskReleaseReplyCallback {
+ void onAskReleaseReply(String sessionToken, int replyStatus);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamHostControlInfoListener.aidl b/media/java/android/media/tv/extension/cam/ICamHostControlInfoListener.aidl
new file mode 100644
index 000000000000..f48ca57cccdc
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlInfoListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface ICamHostControlInfoListener {
+ void onCamHostControlInfoChanged(String sessionToken, int sessionStatus);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamHostControlService.aidl b/media/java/android/media/tv/extension/cam/ICamHostControlService.aidl
new file mode 100644
index 000000000000..6f6c376c1ffa
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlService.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamHostControlAskReleaseReplyCallback;
+import android.media.tv.extension.cam.ICamHostControlInfoListener;
+
+/**
+ * @hide
+ */
+interface ICamHostControlService {
+ // Register the listener to monitor host control session updates.
+ void addCamHostcontrolInfoListener(ICamHostControlInfoListener listener);
+ // Unregister ICamHostControlInfoListener and stop monitoring.
+ void removeCamHostcontrolInfoListener(ICamHostControlInfoListener listener);
+ // Request CICAM to release the resource.
+ int sendCamHostControlAskRelease(String sessionToken,
+ ICamHostControlAskReleaseReplyCallback callback);
+ // Enable/disable the host control mode.
+ void setHostControlMode(String sessionToken, boolean enable);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlag.aidl b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlag.aidl
new file mode 100644
index 000000000000..25a78b99d659
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlag.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlagListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamHostControlTuneQuietlyFlag {
+ // Register listener to notify host control tune_quietly_flag.
+ void addHcTuneQuietlyFlagListener(ICamHostControlTuneQuietlyFlagListener listener);
+ // Remove listener and stop monitor host control tune_quietly_flag.
+ void removeHcTuneQuietlyFlagListener(ICamHostControlTuneQuietlyFlagListener listener);
+ // Returns host control tune_quietly_flag value.
+ Bundle getHcTuneQuietlyFlag(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlagListener.aidl b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlagListener.aidl
new file mode 100644
index 000000000000..5967124e5202
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlagListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface ICamHostControlTuneQuietlyFlagListener {
+ void onHcTuneQuietlyFlagChanged(String sessionToken, int tuneQuietlyFlag);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamInfoListener.aidl b/media/java/android/media/tv/extension/cam/ICamInfoListener.aidl
new file mode 100644
index 000000000000..5410bffaa92d
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamInfoListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamInfoListener {
+ void onCamInfoChanged(int slotId, in Bundle updatedCamInfo);
+ void onSlotInfoChanged(int slotId, in Bundle updatedSlotInfo);
+ void onNewTypeCamInsert(int slotId, in Bundle newCamType);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamMonitoringService.aidl b/media/java/android/media/tv/extension/cam/ICamMonitoringService.aidl
new file mode 100644
index 000000000000..7b8014c5880f
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamMonitoringService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamMonitoringService {
+ // Register a listener for slot/CAM info updates.
+ void addCamInfoListener(in ICamInfoListener listener);
+ // Unregister a listener for slot/CAM info updates.
+ void removeCamInfoListener(in ICamInfoListener listener);
+ // Get CAM information for the specified slot.
+ Bundle getCamInfo(int slotId);
+ // Get slot information.
+ Bundle getSlotInfo(int slotId);
+ // Returns list of slot Ids.
+ int[] getSlotIds();
+ // Check if the country supports CAM.
+ boolean isCamSupported();
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamPinCapabilityListener.aidl b/media/java/android/media/tv/extension/cam/ICamPinCapabilityListener.aidl
new file mode 100644
index 000000000000..f92304af9ade
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamPinCapabilityListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamPinCapabilityListener {
+ void onCamPinCapabilityChanged(int slotId, in Bundle bundle);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamPinService.aidl b/media/java/android/media/tv/extension/cam/ICamPinService.aidl
new file mode 100644
index 000000000000..3f6cb2813c74
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamPinService.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamPinCapabilityListener;
+import android.media.tv.extension.cam.ICamPinStatusListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamPinService {
+ // Register ICamPinCapabilityListener to get CICAM updates.
+ void addCamPinCapabilityListener(in ICamPinCapabilityListener listener);
+ // Unregister ICamPinCapabilityListener and stop monitor PIN status and PIN capability.
+ void removeCamPinCapabilityListener(in ICamPinCapabilityListener listener);
+ // Send the PinCode that needs to be validated by CICAM.
+ int requestCamPinValidation(int slotId, in int[] pinCode, in ICamPinStatusListener listener);
+ // Get the PIN capabilities of the CICAM.
+ int getCamPinCapability(int slotId, out Bundle camPinCapability);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamPinStatusListener.aidl b/media/java/android/media/tv/extension/cam/ICamPinStatusListener.aidl
new file mode 100644
index 000000000000..efbc394897d3
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamPinStatusListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamPinStatusListener {
+ void onCamPinValidationReply(int slotId, in Bundle bundle);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamProfileInterface.aidl b/media/java/android/media/tv/extension/cam/ICamProfileInterface.aidl
new file mode 100644
index 000000000000..3f1d40caa9c9
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamProfileInterface.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamProfileInterface {
+ // Get CAM service update information for special slot.
+ Bundle getCamServiceUpdateInfo(int slotNumber);
+ // Request CAM TIS resend cam info update broadcast message when APK boot up.
+ void requestResendProfileInfoBroadcastACON();
+}
diff --git a/media/java/android/media/tv/extension/cam/IContentControlService.aidl b/media/java/android/media/tv/extension/cam/IContentControlService.aidl
new file mode 100644
index 000000000000..6db79abacb76
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/IContentControlService.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamDrmInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IContentControlService {
+ // Register the listener to notify the DRM info changed by the CICAM.
+ void addCamDrmInfoListener(in ICamDrmInfoListener listener);
+ // Unregister listener to stop monitor DRM Info.
+ void removeCamDrmInfoListener(in ICamDrmInfoListener listener);
+ // Get the DRM Info of current watching channel.
+ int getCamDrmInfo(int slotId, out Bundle camDrmInfo);
+}
diff --git a/media/java/android/media/tv/extension/cam/IEnterMenuErrorCallback.aidl b/media/java/android/media/tv/extension/cam/IEnterMenuErrorCallback.aidl
new file mode 100644
index 000000000000..ff61ddcbcc2f
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/IEnterMenuErrorCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface IEnterMenuErrorCallback {
+ void onAppInfoEnterMenuError();
+}
diff --git a/media/java/android/media/tv/extension/cam/IMmiInterface.aidl b/media/java/android/media/tv/extension/cam/IMmiInterface.aidl
new file mode 100644
index 000000000000..17a2a9c6771f
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/IMmiInterface.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.media.tv.extension.cam.IEnterMenuErrorCallback;
+import android.media.tv.extension.cam.IMmiSession;
+import android.media.tv.extension.cam.IMmiStatusCallback;
+
+
+/**
+ * @hide
+ */
+interface IMmiInterface {
+ // Open a session for MMI.
+ IMmiSession openSession(int slotId, IMmiStatusCallback callback);
+ // Request to display CI Module setup screen.
+ void appInfoEnterMenu(int slotId, IEnterMenuErrorCallback callback);
+}
diff --git a/media/java/android/media/tv/extension/cam/IMmiSession.aidl b/media/java/android/media/tv/extension/cam/IMmiSession.aidl
new file mode 100644
index 000000000000..c4f276219c55
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/IMmiSession.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+/**
+ * @hide
+ */
+interface IMmiSession {
+ // Send user answers to CAM on the MMI Menu screen.
+ void setMenuListAnswer(int response);
+ // Send user answers to CAM on the MMI Enq screen.
+ void setEnquiryAnswer(int answerId, String answer);
+ // Send CloseMmi APDU to Cam.
+ void closeMmi();
+ // Release MMI session.
+ void close();
+}
diff --git a/media/java/android/media/tv/extension/cam/IMmiStatusCallback.aidl b/media/java/android/media/tv/extension/cam/IMmiStatusCallback.aidl
new file mode 100644
index 000000000000..3e68ced6a1ce
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/IMmiStatusCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IMmiStatusCallback {
+ void onMmiEnq(in Bundle request);
+ void onMmiListMenu(in Bundle request);
+ void onMmiClose();
+}
diff --git a/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl b/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl
new file mode 100644
index 000000000000..fa701b3c01ad
--- /dev/null
+++ b/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.clienttoken;
+
+/**
+ * @hide
+ */
+interface IClientToken {
+ String generateClientToken();
+}
diff --git a/media/java/android/media/tv/extension/event/IEventDownload.aidl b/media/java/android/media/tv/extension/event/IEventDownload.aidl
new file mode 100644
index 000000000000..29c7553e1014
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventDownload.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.event;
+
+import android.media.tv.extension.event.IEventDownloadListener;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+interface IEventDownload {
+ // Create an event download session and return it as a Ibinder for DVB/DTMB
+ IBinder createSession(in Bundle eventDownloadParams, in IEventDownloadListener listener);
+}
diff --git a/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl b/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl
new file mode 100644
index 000000000000..6d7d61f15d27
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.event;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IEventDownloadListener {
+ void onCompleted(in Bundle status);
+}
diff --git a/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl b/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl
new file mode 100644
index 000000000000..fe7ee37b324b
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.event;
+
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IEventDownloadSession {
+ // Determine to execute barker channel or silent tune flow for related service type
+ int isBarkerOrSequentialDownloadByServiceType(in Bundle eventDownloadParams);
+ // Determine whether to start barker channel or silent tune flow.
+ int isBarkerOrSequentialDownloadByServiceRecord(in Bundle eventDownloadParams);
+ // Start event download.
+ void startTuningMultiplex(in Uri channelUri);
+ // Set active window channels.
+ void setActiveWindowChannelInfo(in Uri[] activeWinChannelInfos);
+ // Cancel barker channel or silent tune flow.
+ void cancel();
+ // Release barker channel or silent tune flow.
+ void release();
+}
diff --git a/media/java/android/media/tv/extension/event/IEventMonitor.aidl b/media/java/android/media/tv/extension/event/IEventMonitor.aidl
new file mode 100644
index 000000000000..f6e7bd134e78
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventMonitor.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.event;
+
+import android.media.tv.extension.event.IEventMonitorListener;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IEventMonitor {
+ // Get present event information.
+ Bundle getPresentEventInfo(long channelDbId);
+ // Add present event information listener.
+ void addPresentEventInfoListener(in IEventMonitorListener listener);
+ // Remove present event information listener.
+ void removePresentEventInfoListener(in IEventMonitorListener listener);
+ // Get following event information.
+ Bundle getFollowingEventInfo(long channelDbId);
+ // Add following event information listener.
+ void addFollowingEventInfoListener(in IEventMonitorListener listener);
+ // Remove following event information listener.
+ void removeFollowingEventInfoListener(in IEventMonitorListener listener);
+ // Get SDT guidance information.
+ Bundle getSdtGuidanceInfo(long channelDbId);
+ // Set Event Background channel list info.
+ void setBgmTuneChannelInfo(in Uri[] tuneChannelInfos);
+}
diff --git a/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl b/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl
new file mode 100644
index 000000000000..a00e5422a7e0
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.event;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IEventMonitorListener {
+ void onInfoChanged(long channelDbId, in Bundle eventinfo);
+}
diff --git a/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl b/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl
new file mode 100644
index 000000000000..2a2e71a53993
--- /dev/null
+++ b/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.oad;
+
+/**
+ * @hide
+ */
+interface IOadUpdateInterface {
+ // Enable or disable the OAD function.
+ void setOadStatus(boolean enable);
+ // Get status of OAD function.
+ boolean getOadStatus();
+ // Start OAD scan of all frequency in the program list.
+ void startScan();
+ // Stop OAD scan of all frequency in the program list.
+ void stopScan();
+ // Start OAD detect for the current channel.
+ void startDetect();
+ // Stop OAD detect for the current channel.
+ void stopDetect();
+ // Start OAD download after it has been detected or scanned.
+ void startDownload();
+ // Stop OAD download.
+ void stopDownload();
+ // Retrieves current OAD software version.
+ int getSoftwareVersion();
+}
diff --git a/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl b/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl
new file mode 100644
index 000000000000..62f151145472
--- /dev/null
+++ b/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.pvr;
+
+/**
+ * @hide
+ */
+oneway interface IDeleteRecordedContentsCallback {
+ void onRecordedContentsDeleted(in String[] contentUri, in int[] result);
+}
diff --git a/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl b/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl
new file mode 100644
index 000000000000..64f8fc2188b7
--- /dev/null
+++ b/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.pvr;
+
+/**
+ * @hide
+ */
+interface IGetInfoRecordedContentsCallback {
+ void onRecordedContentsGetInfo(int result);
+}
diff --git a/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl b/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl
new file mode 100644
index 000000000000..74a15b8e0b94
--- /dev/null
+++ b/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.pvr;
+
+import android.media.tv.extension.pvr.IDeleteRecordedContentsCallback;
+import android.media.tv.extension.pvr.IGetInfoRecordedContentsCallback;
+
+
+/**
+ * @hide
+ */
+interface IRecordedContents {
+ // Delete recorded contents by URIs
+ // using callback to notify the result or any errors during the deletion process.
+ void deleteRecordedContents(in String[] contentUri,
+ in IDeleteRecordedContentsCallback callback);
+ // Get the channel lock status for recorded content identified by the URI provided in sync way.
+ int getRecordedContentsLockInfoSync(String contentUri);
+ // Get the channel lock status for recorded content identified by the URI provided in async way.
+ void getRecordedContentsLockInfoAsync(String contentUri,
+ in IGetInfoRecordedContentsCallback callback);
+}
diff --git a/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl
new file mode 100644
index 000000000000..bf1a385f05ae
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.rating;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IDownloadableRatingTableMonitor {
+ // Get RRT rating info on downloadable rating data
+ Bundle[] getTable();
+}
diff --git a/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl
new file mode 100644
index 000000000000..06cac3d0d411
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.rating;
+
+import android.media.tv.extension.rating.IPmtRatingListener;
+
+/**
+ * @hide
+ */
+interface IPmtRatingInterface {
+ // Get Pmt rating information.
+ String getPmtRating(String sessionToken);
+ // Register a listener for pmt rating updates.
+ void addPmtRatingListener(String clientToken, in IPmtRatingListener listener);
+ // Remove the previously added IPmtRatingListener.
+ void removePmtRatingListener(in IPmtRatingListener listener);
+}
diff --git a/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl
new file mode 100644
index 000000000000..d88ae9425f8c
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.rating;
+
+/**
+ * @hide
+ */
+oneway interface IPmtRatingListener {
+ void onPmtRatingChanged(String sessionToken, String newTvContentRating);
+}
diff --git a/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl b/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl
new file mode 100644
index 000000000000..a490491d7acc
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.rating;
+
+import android.media.tv.extension.rating.IProgramRatingInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IProgramRatingInfo {
+ // Register a listener to receive notifications when ProgramRatingInfo is updated.
+ void addProgramRatingInfoListener(String clientToken, in IProgramRatingInfoListener listener);
+ // Remove a listener for ProgramRatingInfo update notifications.
+ void removeProgramRatingInfoListener(in IProgramRatingInfoListener listener);
+ // Get ProgramRatingInfo that may only be obtained when viewing.
+ Bundle getProgramRatingInfo(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl
new file mode 100644
index 000000000000..6777cd3035d8
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.rating;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IProgramRatingInfoListener {
+ void onProgramInfoChanged(String sessionToken,in Bundle changedProgramInfo);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderQuantization.kt b/media/java/android/media/tv/extension/rating/IRatingInterface.aidl
index 033d55cc9b61..d68fe763ef28 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderQuantization.kt
+++ b/media/java/android/media/tv/extension/rating/IRatingInterface.aidl
@@ -14,13 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.haptics.slider
+package android.media.tv.extension.rating;
-interface SliderQuantization {
- /** What is the step size between discrete steps of the slider */
- val stepSize: Float
+import android.os.Bundle;
- data class Continuous(override val stepSize: Float = Float.MIN_VALUE) : SliderQuantization
-
- data class Discrete(override val stepSize: Float) : SliderQuantization
+/**
+ * @hide
+ */
+interface IRatingInterface {
+ // Get RRT rating information
+ Bundle getRRTRatingInfo();
+ // Set RRT rating information when user select
+ boolean setRRTRatingInfo(in Bundle param);
+ // Reset RRT5 to clear information
+ boolean setResetRrt5();
}
diff --git a/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl
new file mode 100644
index 000000000000..bad40676e8aa
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.rating;
+
+import android.media.tv.extension.rating.IVbiRatingListener;
+
+/**
+ * @hide
+ */
+interface IVbiRatingInterface {
+ // Get Vbi rating.
+ String getVbiRating(String sessionToken);
+ // Register a listener for Vbi rating updates.
+ void addVbiRatingListener(String clientToken, in IVbiRatingListener listener);
+ // Remove the previously added VbiRatingListener.
+ void removeVbiRatingListener(in IVbiRatingListener listener);
+}
diff --git a/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl
new file mode 100644
index 000000000000..36d523f97613
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.rating;
+
+/**
+ * @hide
+ */
+oneway interface IVbiRatingListener {
+ void onVbiRatingChanged(String sessionToken, String newTvContentRating);
+}
diff --git a/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl
new file mode 100644
index 000000000000..ff78aa4be39c
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.IFavoriteNetworkListener;
+import android.os.Bundle;
+
+/**
+ * Country: Norway
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ * (Operator: RiksTV)
+ *
+ * @hide
+ */
+interface IFavoriteNetwork {
+ // Get the favorite network information,If there are no conflicts, the array of Bundle is empty.
+ Bundle[] getFavoriteNetworks();
+ // Select and set one of two or more favorite networks detected by the service scan.
+ int setFavoriteNetwork(in Bundle favoriteNetworkSettings);
+ // Set the listener to be invoked when two or more favorite networks are detected.
+ int setListener(in IFavoriteNetworkListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl
new file mode 100644
index 000000000000..699422493dd6
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IFavoriteNetworkListener {
+ void onDetectFavoriteNetwork(in Bundle detectFavoriteNetworks);
+}
diff --git a/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl
new file mode 100644
index 000000000000..cdf6e23f4b47
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+/**
+ * @hide
+ */
+interface IHDPlusInfo {
+ // Specifying a HDPlusInfo and start a network scan.
+ int setHDPlusInfo(String isBlindScanContinue, String isHDMode);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnConflict.aidl b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl
new file mode 100644
index 000000000000..5dff39eb5920
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.ILcnConflictListener;
+import android.os.Bundle;
+
+/**
+ * Country: Italy, France
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ *
+ * @hide
+ */
+interface ILcnConflict {
+ // Get the LCN conflict groups information, If there are no conflicts, the array of Bundle is empty.
+ Bundle[] getLcnConflictGroups();
+ // Resolve LCN conflicts caused by service scans.
+ int resolveLcnConflict(in Bundle[] lcnConflictSettings);
+ // Set the listener to be invoked the LCN conflict event.
+ int setListener(in ILcnConflictListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl
new file mode 100644
index 000000000000..6bbbeb8e1e06
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ILcnConflictListener {
+ void onDetectLcnConflict(in Bundle detectLcnConflicts);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl
new file mode 100644
index 000000000000..f9a9d345a575
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.ILcnV2ChannelListListener;
+import android.os.Bundle;
+
+/**
+ * Country: (NorDig etc.)
+ * Broadcast Type: BROADCAST_TYPE_DVB_T, BROADCAST_TYPE_DVB_C
+ *
+ * @hide
+ */
+interface ILcnV2ChannelList {
+ // Get the LCN V2 channel list information. If there are no conflicts, the array of Bundle is empty.
+ Bundle[] getLcnV2ChannelLists();
+ // Select and set one of two or more LCN V2 channel list detected by the service scan.
+ int setLcnV2ChannelList(in Bundle lcnV2ChannelListSettings);
+ // Set the listener to be invoked when two or more LCN V2 channel list are detected.
+ int setListener(in ILcnV2ChannelListListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl
new file mode 100644
index 000000000000..cbdb83c656f4
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ILcnV2ChannelListListener {
+ void onDetectLcnV2ChannelList(in Bundle detectLcnV2ChannelList);
+}
diff --git a/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl
new file mode 100644
index 000000000000..770f8668983e
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.IOperatorDetectionListener;
+import android.os.Bundle;
+
+/**
+ * Country: Any
+ * Broadcast Type: BROADCAST_TYPE_DVB_S
+ * (Operator: M7)
+ *
+ * @hide
+ */
+interface IOperatorDetection {
+ // Set the operator selected info for scanning.
+ int setOperatorDetection(in Bundle operatorSelected);
+ // Set the listener to be invoked when one or more operator detection has been detected by
+ // operator detection searches.
+ int setListener(in IOperatorDetectionListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl
new file mode 100644
index 000000000000..7dcd46177c43
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+oneway interface IOperatorDetectionListener {
+ void onDetectOperatorDetectionList(in Bundle[] detectOperatorDetectionList);
+}
diff --git a/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl
new file mode 100644
index 000000000000..fe755f873110
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.IRegionChannelListListener;
+
+/**
+ * @hide
+ */
+interface IRegionChannelList {
+ // Set the region channel list for scanning.
+ int setRegionChannelList(String regionChannelList);
+ // Set the listener to be invoked when one or more region channel list has been detected by
+ // region channel list searches.
+ int setListener(in IRegionChannelListListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl
new file mode 100644
index 000000000000..06b0eb5537a2
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+/**
+ * @hide
+ */
+oneway interface IRegionChannelListListener {
+ void onDetectRegionChannelList(in String[] detectRegionChannelList);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanInterface.aidl b/media/java/android/media/tv/extension/scan/IScanInterface.aidl
new file mode 100644
index 000000000000..b44d1d243150
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanInterface.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.IScanListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanInterface {
+ IBinder createSession(int broadcastType, String countryCode, String operator,
+ in IScanListener listener);
+ Bundle getParameters(int broadcastType, String countryCode, String operator,
+ in Bundle params);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanListener.aidl b/media/java/android/media/tv/extension/scan/IScanListener.aidl
new file mode 100644
index 000000000000..2c4807f97c58
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanListener.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IScanListener {
+ // notify events during scan.
+ void onEvent(in Bundle eventArgs);
+ // notify the scan progress.
+ void onScanProgress(String scanProgress, in Bundle scanProgressInfo);
+ // notify the scan completion.
+ void onScanCompleted(int scanResult);
+ // notify that the temporaily held channel list is stored.
+ void onStoreCompleted(int storeResult);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl
new file mode 100644
index 000000000000..b8074fc4a9bd
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+/**
+ * For satellite search function.
+ * @hide
+ */
+interface IScanSatSearch {
+ // Set currecnt LNB as customized LNB, default LNB is universal LNB
+ int setCustomizedLnb(String customizedLnb);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanSession.aidl b/media/java/android/media/tv/extension/scan/IScanSession.aidl
new file mode 100644
index 000000000000..d42eca1342b5
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanSession.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanSession {
+ // Start a service scan.
+ int startScan(int broadcastType, String countryCode, String operator, in int[] frequency,
+ String scanType, String languageCode);
+ // Reset the scan information held in TIS.
+ int resetScan();
+ // Cancel scan.
+ int cancelScan();
+
+ // Get available interface for created ScanExtension interface.
+ String[] getAvailableExtensionInterfaceNames();
+ // Get extension interface for Scan.
+ IBinder getExtensionInterface(String name);
+
+ // Clear the results of the service scan from the service database.
+ int clearServiceList(in Bundle optionalClearParams);
+ // Store the results of the service scan from the service database.
+ int storeServiceList();
+ // Get a service information specified by the service information ID.
+ Bundle getServiceInfo(String serviceInfoId, in String[] keys);
+ // Get a service information ID list.
+ String[] getServiceInfoIdList();
+ // Get a list of service info by the filter.
+ Bundle getServiceInfoList(in Bundle filterInfo, in String[] keys);
+ // Update the service information.
+ int updateServiceInfo(in Bundle serviceInfo);
+ // Updates the service information for the specified service information ID in array list.
+ int updateServiceInfoByList(in Bundle[] serviceInfo);
+
+ /* DVBI specific functions */
+ // Get all of the serviceLists, parsed from Local TV storage, Broadcast, USB file discovery.
+ Bundle getServiceLists();
+ // Users choose one serviceList from the serviceLists, and install the services.
+ int setServiceList(int serviceListRecId);
+ // Get all of the packageData, parsed from the selected serviceList XML.
+ Bundle getPackageData();
+ // Choose the package using package id and install the corresponding services.
+ int setPackage(String packageId);
+ // Get all of the countryRegionData, parsed from the selected serviceList XML.
+ Bundle getCountryRegionData();
+ // Choose the countryRegion using countryRegion id, and install the corresponding services.
+ int setCountryRegion(String regionId);
+ // Get all of the regionData, parsed from the selected serviceList XML.
+ Bundle getRegionData();
+ // Choose the region using the regionData id, and install the corresponding services.
+ int setRegion(String regionId);
+
+ // Get unique session token for the scan.
+ String getSessionToken();
+ // Release scan resource, the register listener will be released.
+ int release();
+}
diff --git a/media/java/android/media/tv/extension/scan/ITargetRegion.aidl b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl
new file mode 100644
index 000000000000..417e12243b82
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.ITargetRegionListener;
+
+import android.os.Bundle;
+
+/**
+ * Country: U.K.
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ *
+ * @hide
+ */
+interface ITargetRegion {
+ // Get the target regions information. If there are no conflicts, the array of Bundle is empty.
+ Bundle[] getTargetRegions();
+ // Select and set one of two or more target region detected by the service scan.
+ int setTargetRegion(in Bundle targetRegionSettings);
+ // Set the listener to be invoked when two or more regions are detected.
+ int setListener(in ITargetRegionListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl
new file mode 100644
index 000000000000..9d6aa8e8ea31
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ITargetRegionListener {
+ void onDetectTargetRegion(in Bundle detectTargetRegions);
+}
diff --git a/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl
new file mode 100644
index 000000000000..f25952c1cbdc
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+import android.media.tv.extension.scan.ITkgsInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ITkgsInfo {
+ int setPrefServiceList(String prefServiceList);
+ int setTkgsInfoListener(in ITkgsInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl
new file mode 100644
index 000000000000..e3dcf2d4c5ad
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scan;
+
+/**
+ * @hide
+ */
+oneway interface ITkgsInfoListener {
+ void onServiceList(in String[] serviceList);
+ void onTableVersionUpdate(int tableVersion);
+ void onUserMessage(String strMessage);
+}
diff --git a/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl
new file mode 100644
index 000000000000..bda60edc48c1
--- /dev/null
+++ b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scanbsu;
+
+import android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdateListener;
+
+/**
+ * @hide
+ */
+interface IScanBackgroundServiceUpdate {
+ // Set the listener for background service update
+ // receives notifications for svl/tsl/nwl update during background service update.
+ void addBackgroundServiceUpdateListener(String clientToken,
+ in IScanBackgroundServiceUpdateListener listener);
+ // Remove the listener for background service update to stop receiving notifications
+ // for svl/tsl/nwl update during background service update.
+ void removeBackgroundServiceUpdateListener(in IScanBackgroundServiceUpdateListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl
new file mode 100644
index 000000000000..d9bcbedb234a
--- /dev/null
+++ b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.scanbsu;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanBackgroundServiceUpdateListener {
+ // On background service update add/delete/update svl records.
+ void onChannelListUpdate(String sessionToken, out Bundle[] updateInfos);
+ // On background service update add/delete/update nwl records.
+ void onNetworkListUpdate(String sessionToken, out Bundle[] updateInfos);
+ // On background service update add/delete/update tsl records.
+ void onTransportStreamingListUpdate(String sessionToken, out Bundle[] updateInfos);
+}
diff --git a/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl b/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl
new file mode 100644
index 000000000000..57f3b4ab5017
--- /dev/null
+++ b/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.screenmode;
+
+/**
+ * @hide
+ */
+interface IScreenModeSettings {
+ // Set screen mode information using a JSON string.
+ void setScreenModeSettings(String sessionToken, String setting);
+ // Get the overscan index which TIS session is applied.
+ int getOverScanIndex(String sessionToken);
+ // Get status that TIS session is support overscan or not.
+ boolean getSupportApplyOverScan(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl b/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl
new file mode 100644
index 000000000000..cb6aeccb5b57
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IChannelListTransfer {
+ // Parse XML file and import Channels information.
+ void importChannelList(in ParcelFileDescriptor pfd);
+ // Get Channels information for export and create XML file.
+ void exportChannelList(in ParcelFileDescriptor pfd);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceList.aidl b/media/java/android/media/tv/extension/servicedb/IServiceList.aidl
new file mode 100644
index 000000000000..51daa80ccbd6
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceList.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceList {
+ // Get a list of the Service list IDs quivalent to COLUMN_CHANNEL_LIST_ID
+ // in the Channels table of TvProvider.
+ String[] getServiceListIds();
+ // Get the information associated with the Service list.
+ Bundle getServiceListInfo(String serviceListId, in String[] keys);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
new file mode 100644
index 000000000000..1b1577ffc015
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+import android.media.tv.extension.servicedb.IServiceListEditListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceListEdit {
+ // Open in edit mode. Must call close() after edit is done.
+ int open(IServiceListEditListener listener);
+ // Method to close in edit mode.
+ int close();
+ // Method to commit changes made to service database.
+ int commit();
+ // Method to commit and close the changes.
+ int userEditCommit();
+
+ // Get a service/transportStream/Network/Satellite record information specified by
+ // serviceInfoId and keys from tvdb.
+ Bundle getServiceInfoFromDatabase(String serviceInfoId, in String[] keys);
+ // Get a list of all service records' information specified by serviceListId and keys from tvdb.
+ Bundle getServiceInfoListFromDatabase(String serviceListId, in String[] keys);
+ // Get a list of all service info IDs in the service list of serviceListId from tvdb.
+ String[] getServiceInfoIdsFromDatabase(String inServiceListId);
+ // Update a service information by the contents of serviceInfo;
+ int updateServiceInfoFromDatabase(in Bundle updateServiceInfo);
+ // Update all service information by the contents of serviceInfoList.
+ int updateServiceInfoByListFromDatabase(in Bundle[] updateServiceInfoList);
+ // Remove a service information of the serviceInfoId from the service list.
+ int removeServiceInfoFromDatabase(String serviceInfoId);
+ // Remove all service information of the serviceInfoId from the service list.
+ int removeServiceInfoByListFromDatabase(in String[] serviceInfoIdList);
+ // Get a list of the Service list IDs which is equivalent to COLUMN_CHANNEL_LIST_ID
+ // in Channels table from tv db.
+ String[] getServiceListChannelIds();
+ // Get the information associated with the Service list Channel id.
+ Bundle getServiceListInfoByChannelId(String serviceListChannelId, in String[] keys);
+
+ // Get a list of transportStream records' information specified by serviceListId and keys.
+ Bundle getTransportStreamInfoList(String serviceListId, in String[] keys);
+ // Get a list of transportStream records' information specified by serviceListId and keys
+ // from work db.
+ Bundle getTransportStreamInfoListForce(String serviceListId, in String[] keys);
+
+ // Get a list of network records' information specified by serviceListId and keys.
+ Bundle getNetworkInfoList(String serviceListId, in String[] keys);
+ // Get a list of satellite records' information specified by serviceListId and keys.
+ Bundle getSatelliteInfoList(String serviceListId, in String[] keys);
+
+ // Decompress whole bundle value of single service/transportStream/Network/Satellite record.
+ // RecordInfoBundle:a single record got from database by getServiceInfoFromDatabase()
+ String toRecordInfoByType(in Bundle recordInfoBundle, String recordType);
+ // Set channels(tv.db) modified result to middleware database(SVL/TSL/NWL/SATL).
+ int putRecordIdList(String serviceListId, in Bundle recordIdListBundle, int optType);
+
+ // Add predefined ServiceListInfo of Hotbird 13E in scan two satellite scene EU region
+ // following by commit().
+ String addPredefinedServiceListInfo(int broadcastType, String serviceListType,
+ String serviceListPrefix, String countryCode, int operatorId);
+ // Add predefined channels of Hotbird 13E in scan two satellite scene EU region.
+ int addPredefinedChannelList(String serviceListId, in Bundle[] predefinedListBundle);
+ // Add predefined satellite info of Hotbird 13E in scan two satellite scene EU region.
+ int addPredefinedSatInfo(String serviceListId, in Bundle predefinedSatInfoBundle);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl
new file mode 100644
index 000000000000..e227eda47d4f
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListEditListener {
+ void onCompleted(int requestId, int result);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl
new file mode 100644
index 000000000000..c57e8f97ed4c
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListExportListener {
+ void onExported(int exportResult);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl
new file mode 100644
index 000000000000..fcde581548f6
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IServiceListExportSession {
+ // Start export service list with reserved parameters.
+ int exportServiceList(in ParcelFileDescriptor pfd, in Bundle exportParams);
+ // Release export resources.
+ int release();
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
new file mode 100644
index 000000000000..abd8320df11d
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+interface IServiceListImportListener {
+ void onImported(int importResult);
+ void onPreloaded(int preloadResult);
+} \ No newline at end of file
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl
new file mode 100644
index 000000000000..1f1ae010a444
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IServiceListImportSession {
+ // Start import service list. Should call after preload and before release.
+ int importServiceList(in ParcelFileDescriptor pfd, in Bundle importParams);
+ // Preparing for import.
+ int preload(in ParcelFileDescriptor pfd);
+ // Release import resources.
+ int release();
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl
new file mode 100644
index 000000000000..7c9c5c8a8048
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListSetChannelListListener {
+ void onCompleted(int setChannelListResult);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl
new file mode 100644
index 000000000000..b0527b3709b7
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceListSetChannelListSession {
+ // Set channelList with channelinfo bundles, serviceListInfo, and operation type.
+ int setChannelList(in Bundle[] channelsInfo, in Bundle ServiceListInfoBundle, int optType);
+ // Release set channellist resources.
+ int release();
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl
new file mode 100644
index 000000000000..91fb15728b06
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.servicedb;
+
+import android.media.tv.extension.servicedb.IServiceListExportListener;
+import android.media.tv.extension.servicedb.IServiceListImportListener;
+import android.media.tv.extension.servicedb.IServiceListSetChannelListListener;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+interface IServiceListTransferInterface {
+ IBinder createExportSession(in IServiceListExportListener listener);
+ IBinder createImportSession(in IServiceListImportListener listener);
+ IBinder createSetChannelListSession(in IServiceListSetChannelListListener listener);
+}
diff --git a/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl b/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl
new file mode 100644
index 000000000000..742191ff3c05
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IAnalogAudioInfo {
+ Bundle getAnalogAudioInfo(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl b/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl
new file mode 100644
index 000000000000..4c953a08364a
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+import android.media.tv.extension.signal.IAudioSignalInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IAudioSignalInfo {
+ // Get audio signal information.
+ Bundle getAudioSignalInfo(String sessionToken);
+ // Notify TIS whether user selects audio track via mts button on the remote control.
+ void notifyMtsSelectTrackFlag(boolean mtsFlag);
+ // Get the audio track id selected via mts.
+ String getMtsSelectedTrackId();
+ // Register a listener to receive the updated audio signal information.
+ void addAudioSignalInfoListener(String clientToken, in IAudioSignalInfoListener listener);
+ // Remove a listener for audio signal information update notifications.
+ void removeAudioSignalInfoListener(in IAudioSignalInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl
new file mode 100644
index 000000000000..adf239ab1b32
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IAudioSignalInfoListener {
+ void onAudioSignalInfoChanged(String sessionToken, in Bundle changedSignalInfo);
+}
diff --git a/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl
new file mode 100644
index 000000000000..bd468b2e7f34
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+/**
+ * @hide
+ */
+oneway interface IHdmiSignalInfoListener {
+ void onSignalInfoChanged(String sessionToken);
+ void onLowLatencyModeChanged(int enable);
+}
diff --git a/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl b/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl
new file mode 100644
index 000000000000..39625e3c958d
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+import android.media.tv.extension.signal.IHdmiSignalInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IHdmiSignalInterface {
+ // Register a listener for Hdmi Signal Info updates.
+ void addHdmiSignalInfoListener(String inputId, in IHdmiSignalInfoListener listener);
+ // Remove a listener for Hdmi Signal Info update notifications.
+ void removeHdmiSignalInfoListener(String inputId, in IHdmiSignalInfoListener listener);
+ // Obtain HdmiSignalInfo based on the inputId and sessionToken.
+ Bundle getHdmiSignalInfo(String sessionToken);
+ // Enable/disable low-latency decoding mode.
+ void setLowLatency(String sessionToken, int mode);
+ // Enable/disable force-VRR mode.
+ void setForceVrr(String sessionToken, int mode);
+}
diff --git a/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl
new file mode 100644
index 000000000000..7f05e7033aeb
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+import android.media.tv.extension.signal.ITunerFrontendSignalInfoListener;
+import android.os.Bundle;
+
+/**
+* @hide
+*/
+interface ITunerFrontendSignalInfoInterface {
+ Bundle getFrontendSignalInfo(String sessionToken);
+ void setFrontendSignalInfoListener(in ITunerFrontendSignalInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl
new file mode 100644
index 000000000000..9c22a3570cce
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+/**
+* @hide
+*/
+oneway interface ITunerFrontendSignalInfoListener {
+ void onFrontendStatusChanged(int frontendStatus);
+}
diff --git a/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl b/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl
new file mode 100644
index 000000000000..b17142acf2ab
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+import android.media.tv.extension.signal.IVideoSignalInfoListener;
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+interface IVideoSignalInfo {
+ void addVideoSignalInfoListener(String clientToken, in IVideoSignalInfoListener listener);
+ void removeVideoSignalInfoListener(in IVideoSignalInfoListener listener);
+ Bundle getVideoSignalInfo(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl
new file mode 100644
index 000000000000..aafc192f32fa
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.signal;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IVideoSignalInfoListener {
+ void onVideoSignalInfoChanged(String sessionToken, in Bundle changedSignalInfo);
+}
diff --git a/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl
new file mode 100644
index 000000000000..a3725e4e25db
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.teletext;
+
+import android.media.tv.extension.teletext.IDataServiceSignalInfoListener;
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+interface IDataServiceSignalInfo {
+ // Get Teletext data service signal information.
+ Bundle getDataServiceSignalInfo(String sessionToken);
+ // Add a listener that receives notifications of teletext running information.
+ void addDataServiceSignalInfoListener(String clientToken,
+ IDataServiceSignalInfoListener listener);
+ // Remove a listener that receives notifications of Teletext running information.
+ void removeDataServiceSignalInfoListener(String clientToken,
+ IDataServiceSignalInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl
new file mode 100644
index 000000000000..0e99bf5cc955
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.teletext;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IDataServiceSignalInfoListener {
+ void onDataServiceSignalInfoChanged (String sessionToken, in Bundle changedSignalInfo);
+}
diff --git a/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl b/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl
new file mode 100644
index 000000000000..c96ffc02f438
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.teletext;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ITeletextPageSubCode {
+ // Get Teletext page number
+ Bundle getTeletextPageNumber(String sessionToken);
+ // Set Teletext page number.
+ void setTeleltextPageNumber(String sessionToken, int pageNumber);
+ // Get Teletext sub page number.
+ Bundle getTeletextPageSubCode(String sessionToken);
+ // Set Teletext sub page number.
+ void setTeletextPageSubCode(String sessionToken, int pageSubCode);
+ // Get Teletext TopInfo.
+ Bundle getTeletextHasTopInfo(String sessionToken);
+ // Get Teletext TopBlockList.
+ Bundle getTeletextTopBlockList(String sessionToken);
+ // Get Teletext TopGroupList.
+ Bundle getTeletextTopGroupList(String sessionToken, int indexGroup);
+ // Get Teletext TopPageList.
+ Bundle getTeletextTopPageList(String sessionToken, int indexPage);
+}
diff --git a/media/java/android/media/tv/extension/time/IBroadcastTime.aidl b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl
new file mode 100644
index 000000000000..123d00f9faf4
--- /dev/null
+++ b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.time;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IBroadcastTime {
+ long getUtcTime();
+ long getLocalTime();
+ Bundle getTimeZoneInfo();
+ long getUtcTimePerStream(String SessionToken);
+ long getLocalTimePerStream(String SessionToken);
+} \ No newline at end of file
diff --git a/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl b/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl
new file mode 100644
index 000000000000..88e50844f998
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.tune;
+
+import android.media.tv.extension.tune.IChannelTunedListener;
+
+/*
+* @hide
+*/
+interface IChannelTunedInterface {
+ void addChannelTunedListener(in IChannelTunedListener listener);
+ void removeChannelTunedListener(in IChannelTunedListener listener);
+}
diff --git a/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl b/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl
new file mode 100644
index 000000000000..46875463402d
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.tune;
+
+import android.os.Bundle;
+
+/*
+* @hide
+*/
+oneway interface IChannelTunedListener {
+ void onChannelTuned(String sessionToken, in Bundle channelTunedInfo);
+}
diff --git a/media/java/android/media/tv/extension/tune/IMuxTune.aidl b/media/java/android/media/tv/extension/tune/IMuxTune.aidl
new file mode 100644
index 000000000000..4e9dbdae6643
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IMuxTune.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.tune;
+
+import android.media.tv.extension.tune.IMuxTuneSession;
+
+/**
+* @hide
+*/
+interface IMuxTune {
+ IMuxTuneSession createSession(int broadcastType, String clientToken);
+}
diff --git a/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl b/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl
new file mode 100644
index 000000000000..5ad72b48b50b
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.tv.extension.tune;
+
+import android.os.Bundle;
+
+/**
+* @hide
+*/
+interface IMuxTuneSession {
+ // Start mux tune with tune params.
+ void start(int broadcastType, int frequency, int brandwith, in Bundle muxTuneParams);
+ // Stop mux tune.
+ void stop();
+ // Release muxtune resources.
+ void release();
+ // Get the session token created by TIS to identify different sessions.
+ String getSessionToken();
+}
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index 4de68634af5e..4b832aee49c5 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -2,6 +2,22 @@ package: "android.media.tv.flags"
container: "system"
flag {
+ name: "enable_le_audio_broadcast_ui"
+ is_exported: true
+ namespace: "media_tv"
+ description: "Enable Broadcast UI for LE Audio on TV."
+ bug: "378732734"
+}
+
+flag {
+ name: "enable_le_audio_unicast_ui"
+ is_exported: true
+ namespace: "media_tv"
+ description: "Enable Unicast UI for LE Audio on TV."
+ bug: "378732734"
+}
+
+flag {
name: "broadcast_visibility_types"
is_exported: true
namespace: "media_tv"
@@ -77,6 +93,22 @@ flag {
name: "set_resource_holder_retain"
is_exported: true
namespace: "media_tv"
- description : "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA."
+ description: "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA."
bug: "372973197"
}
+
+flag {
+ name: "mediacas_update_client_profile_priority"
+ is_exported: true
+ namespace: "media_tv"
+ description: "Feature flag to add updateResourcePriority api to MediaCas"
+ bug: "372971241"
+}
+
+flag {
+ name: "apply_picture_profiles"
+ is_exported: true
+ namespace: "media_tv"
+ description : "Feature flag to enable APIs for applying picture profiles"
+ bug: "337330263"
+}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 635572d12cc5..9e9699ff6bc6 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -271,6 +271,38 @@ public class TvInteractiveAppView extends ViewGroup {
}
}
+ /**
+ * Controls whether the TvInteractiveAppView's surface is placed on top of other regular surface
+ * views in the window (but still behind the window itself).
+ *
+ * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
+ *
+ * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false}
+ * otherwise.
+ */
+ @FlaggedApi(Flags.FLAG_TIAF_V_APIS)
+ public void setZOrderMediaOverlay(boolean isMediaOverlay) {
+ if (mSurfaceView != null) {
+ mSurfaceView.setZOrderOnTop(false);
+ mSurfaceView.setZOrderMediaOverlay(isMediaOverlay);
+ }
+ }
+
+ /**
+ * Controls whether the TvInterActiveAppView's surface is placed on top of its window.
+ *
+ * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
+ *
+ * @param onTop {@code true} to be on top of its window, {@code false} otherwise.
+ */
+ @FlaggedApi(Flags.FLAG_TIAF_V_APIS)
+ public void setZOrderOnTop(boolean onTop) {
+ if (mSurfaceView != null) {
+ mSurfaceView.setZOrderMediaOverlay(false);
+ mSurfaceView.setZOrderOnTop(onTop);
+ }
+ }
+
private void resetSurfaceView() {
if (mSurfaceView != null) {
mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback);
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 898a8bf02edb..4de71235df8c 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -63,7 +63,7 @@ public class FrontendStatus {
FRONTEND_STATUS_TYPE_DVBT_CELL_IDS, FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO,
FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL, FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST,
FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED, FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS,
- FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS, FRONTEND_STATUS_TYPE_STANDARD_EXT})
+ FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS, FRONTEND_STATUS_TYPE_STANDARD_EXTENSION})
@Retention(RetentionPolicy.SOURCE)
public @interface FrontendStatusType {}
@@ -317,7 +317,7 @@ public class FrontendStatus {
* Standard extension.
*/
@FlaggedApi(Flags.FLAG_TUNER_W_APIS)
- public static final int FRONTEND_STATUS_TYPE_STANDARD_EXT =
+ public static final int FRONTEND_STATUS_TYPE_STANDARD_EXTENSION =
android.hardware.tv.tuner.FrontendStatusType.STANDARD_EXT;
/** @hide */
@@ -567,7 +567,7 @@ public class FrontendStatus {
private Long mIptvPacketsReceived;
private Integer mIptvWorstJitterMs;
private Integer mIptvAverageJitterMs;
- private StandardExt mStandardExt;
+ private StandardExtension mStandardExtension;
// Constructed and fields set by JNI code.
private FrontendStatus() {
@@ -1298,12 +1298,12 @@ public class FrontendStatus {
*/
@NonNull
@FlaggedApi(Flags.FLAG_TUNER_W_APIS)
- public StandardExt getStandardExt() {
+ public StandardExtension getStandardExtension() {
TunerVersionChecker.checkHigherOrEqualVersionTo(
- TunerVersionChecker.TUNER_VERSION_4_0, "StandardExt status");
- if (mStandardExt == null) {
- throw new IllegalStateException("StandardExt status is empty");
+ TunerVersionChecker.TUNER_VERSION_4_0, "StandardExtension status");
+ if (mStandardExtension == null) {
+ throw new IllegalStateException("StandardExtension status is empty");
}
- return mStandardExt;
+ return mStandardExtension;
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/StandardExt.java b/media/java/android/media/tv/tuner/frontend/StandardExtension.java
index 490727278b46..8bff3dd99cdb 100644
--- a/media/java/android/media/tv/tuner/frontend/StandardExt.java
+++ b/media/java/android/media/tv/tuner/frontend/StandardExtension.java
@@ -29,16 +29,16 @@ import android.media.tv.flags.Flags;
*/
@SystemApi
@FlaggedApi(Flags.FLAG_TUNER_W_APIS)
-public final class StandardExt {
- private final int mDvbsStandardExt;
- private final int mDvbtStandardExt;
+public final class StandardExtension {
+ private final int mDvbsStandardExtension;
+ private final int mDvbtStandardExtension;
/**
* Private constructor called by JNI only.
*/
- private StandardExt(int dvbsStandardExt, int dvbtStandardExt) {
- mDvbsStandardExt = dvbsStandardExt;
- mDvbtStandardExt = dvbtStandardExt;
+ private StandardExtension(int dvbsStandardExtension, int dvbtStandardExtension) {
+ mDvbsStandardExtension = dvbsStandardExtension;
+ mDvbtStandardExtension = dvbtStandardExtension;
}
/**
@@ -50,11 +50,11 @@ public final class StandardExt {
* @see android.media.tv.tuner.frontend.DvbsFrontendSettings
*/
@DvbsFrontendSettings.Standard
- public int getDvbsStandardExt() {
- if (mDvbsStandardExt == FrontendDvbsStandard.UNDEFINED) {
+ public int getDvbsStandardExtension() {
+ if (mDvbsStandardExtension == FrontendDvbsStandard.UNDEFINED) {
throw new IllegalStateException("No DVB-S standard transition");
}
- return mDvbsStandardExt;
+ return mDvbsStandardExtension;
}
/**
@@ -66,10 +66,10 @@ public final class StandardExt {
* @see android.media.tv.tuner.frontend.DvbtFrontendSettings
*/
@DvbtFrontendSettings.Standard
- public int getDvbtStandardExt() {
- if (mDvbtStandardExt == FrontendDvbtStandard.UNDEFINED) {
+ public int getDvbtStandardExtension() {
+ if (mDvbtStandardExtension == FrontendDvbtStandard.UNDEFINED) {
throw new IllegalStateException("No DVB-T standard transition");
}
- return mDvbtStandardExt;
+ return mDvbtStandardExtension;
}
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index c44e26f17b5e..f09dc7218d7d 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -104,6 +104,7 @@ cc_library_shared {
"libgrallocusage",
"libmedia_midiiowrapper",
"android.companion.virtualdevice.flags-aconfig-cc",
+ "android.media.codec-aconfig-cc",
"android.media.playback.flags-aconfig-cc",
],
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 001653b08f0c..fc184fe5c872 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -39,6 +39,8 @@
#include <C2Buffer.h>
#include <C2PlatformSupport.h>
+#include <android_media_codec.h>
+
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -189,6 +191,22 @@ static struct {
jmethodID setId;
} gBufferInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctorId;
+ jfieldID resourceId;
+ jfieldID capacityId;
+ jfieldID availableId;
+} gGlobalResourceInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctorId;
+ jfieldID resourceId;
+ jfieldID staticCountId;
+ jfieldID perFrameCountId;
+} gInstanceResourceInfo;
+
struct fields_t {
jmethodID postEventFromNativeID;
jmethodID lockAndGetContextID;
@@ -1129,6 +1147,37 @@ status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject names
return mCodec->unsubscribeFromVendorParameters(names);
}
+static jobject getJavaResources(
+ JNIEnv *env,
+ const std::vector<MediaCodec::InstanceResourceInfo>& resources) {
+ jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
+ for (const MediaCodec::InstanceResourceInfo& res : resources) {
+ ScopedLocalRef<jobject> object{env, env->NewObject(
+ gInstanceResourceInfo.clazz, gInstanceResourceInfo.ctorId)};
+ ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())};
+ env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get());
+ env->SetLongField(object.get(),
+ gInstanceResourceInfo.staticCountId,
+ (jlong)res.mStaticCount);
+ env->SetLongField(object.get(),
+ gInstanceResourceInfo.perFrameCountId,
+ (jlong)res.mPerFrameCount);
+ (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get());
+ }
+
+ return resourcesObj;
+}
+
+status_t JMediaCodec::getRequiredResources(JNIEnv *env, jobject *resourcesObj) {
+ std::vector<MediaCodec::InstanceResourceInfo> resources;
+ status_t status = mCodec->getRequiredResources(resources);
+ if (status != OK) {
+ return status;
+ }
+ *resourcesObj = getJavaResources(env, resources);
+ return OK;
+}
+
static jthrowable createCodecException(
JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
ScopedLocalRef<jclass> clazz(
@@ -1475,6 +1524,10 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
obj = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
break;
}
+ case MediaCodec::CB_REQUIRED_RESOURCES_CHANGED:
+ {
+ break;
+ }
default:
TRESPASS();
@@ -3560,6 +3613,64 @@ static void android_media_MediaCodec_unsubscribeFromVendorParameters(
return;
}
+static jobject getJavaResources(
+ JNIEnv *env,
+ const std::vector<MediaCodec::GlobalResourceInfo>& resources) {
+ jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
+ for (const MediaCodec::GlobalResourceInfo& res : resources) {
+ ScopedLocalRef<jobject> object{env, env->NewObject(
+ gGlobalResourceInfo.clazz, gGlobalResourceInfo.ctorId)};
+ ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())};
+ env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get());
+ env->SetLongField(object.get(), gGlobalResourceInfo.capacityId, (jlong)res.mCapacity);
+ env->SetLongField(object.get(), gGlobalResourceInfo.availableId, (jlong)res.mAvailable);
+ (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get());
+ }
+
+ return resourcesObj;
+}
+
+static jobject android_media_MediaCodec_getGloballyAvailableResources(
+ JNIEnv *env, jobject thiz) {
+ (void)thiz;
+ std::vector<MediaCodec::GlobalResourceInfo> resources;
+ status_t status = MediaCodec::getGloballyAvailableResources(resources);
+ if (status != OK) {
+ if (status == ERROR_UNSUPPORTED) {
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ "Function Not Implemented");
+ } else {
+ throwExceptionAsNecessary(env, status, nullptr);
+ }
+ return nullptr;
+ }
+
+ return getJavaResources(env, resources);
+}
+
+static jobject android_media_MediaCodec_getRequiredResources(
+ JNIEnv *env, jobject thiz) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+ if (codec == nullptr || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
+ return nullptr;
+ }
+
+ jobject ret = nullptr;
+ status_t status = codec->getRequiredResources(env, &ret);
+ if (status != OK) {
+ if (status == ERROR_UNSUPPORTED) {
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ "Function Not Implemented");
+ } else {
+ throwExceptionAsNecessary(env, status, nullptr);
+ }
+ return nullptr;
+ }
+
+ return ret;
+}
+
static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
ScopedLocalRef<jclass> clazz(
env, env->FindClass("android/media/MediaCodec"));
@@ -3905,6 +4016,36 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
gFields.bufferInfoPresentationTimeUs =
env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
+
+ // Since these TestApis are defined under the flag, make sure they are
+ // accessed only when the flag is set.
+ if (android::media::codec::codec_availability()) {
+ clazz.reset(env->FindClass("android/media/MediaCodec$GlobalResourceInfo"));
+ CHECK(clazz.get() != NULL);
+ gGlobalResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+ gGlobalResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gGlobalResourceInfo.ctorId != NULL);
+ gGlobalResourceInfo.resourceId =
+ env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
+ CHECK(gGlobalResourceInfo.resourceId != NULL);
+ gGlobalResourceInfo.capacityId = env->GetFieldID(clazz.get(), "mCapacity", "J");
+ CHECK(gGlobalResourceInfo.capacityId != NULL);
+ gGlobalResourceInfo.availableId = env->GetFieldID(clazz.get(), "mAvailable", "J");
+ CHECK(gGlobalResourceInfo.availableId != NULL);
+
+ clazz.reset(env->FindClass("android/media/MediaCodec$InstanceResourceInfo"));
+ CHECK(clazz.get() != NULL);
+ gInstanceResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+ gInstanceResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gInstanceResourceInfo.ctorId != NULL);
+ gInstanceResourceInfo.resourceId =
+ env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
+ CHECK(gInstanceResourceInfo.resourceId != NULL);
+ gInstanceResourceInfo.staticCountId= env->GetFieldID(clazz.get(), "mStaticCount", "J");
+ CHECK(gInstanceResourceInfo.staticCountId != NULL);
+ gInstanceResourceInfo.perFrameCountId = env->GetFieldID(clazz.get(), "mPerFrameCount", "J");
+ CHECK(gInstanceResourceInfo.perFrameCountId != NULL);
+ }
}
static void android_media_MediaCodec_native_setup(
@@ -4261,6 +4402,12 @@ static const JNINativeMethod gMethods[] = {
{ "native_finalize", "()V",
(void *)android_media_MediaCodec_native_finalize },
+
+ { "native_getGloballyAvailableResources", "()Ljava/util/List;",
+ (void *)android_media_MediaCodec_getGloballyAvailableResources},
+
+ { "native_getRequiredResources", "()Ljava/util/List;",
+ (void *)android_media_MediaCodec_getRequiredResources},
};
static const JNINativeMethod gLinearBlockMethods[] = {
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index c9b6b7f6f337..930dbbeb7f30 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -185,6 +185,8 @@ struct JMediaCodec : public AHandler {
status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names);
+ status_t getRequiredResources(JNIEnv *env, jobject *resourcesObj);
+
bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
const sp<ICrypto> &getCrypto() { return mCrypto; }
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d05ee551c172..a94230014437 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1362,13 +1362,26 @@ static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject t
return mp->setOutputDevice(device_id) == NO_ERROR;
}
-static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+static jintArray android_media_MediaPlayer_getRoutedDeviceIds(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
- return AUDIO_PORT_HANDLE_NONE;
+ return NULL;
+ }
+ DeviceIdVector deviceIds;
+ // TODO: b/379161379 - Should we throw an exception if the result is not ok?
+ mp->getRoutedDeviceIds(deviceIds);
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
}
- return mp->getRoutedDeviceId();
+ jint* values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
+ }
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
static void android_media_MediaPlayer_enableDeviceCallback(
@@ -1452,7 +1465,8 @@ static const JNINativeMethod gMethods[] = {
// AudioRouting
{"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I",
+ (void *)android_media_MediaPlayer_getRoutedDeviceIds},
{"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback},
};
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 9a6d5d7d730a..643fc8a2d925 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -722,21 +722,31 @@ android_media_MediaRecorder_setInputDevice(JNIEnv *env, jobject thiz, jint devic
return true;
}
-static jint
-android_media_MediaRecorder_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+static jintArray
+android_media_MediaRecorder_getRoutedDeviceIds(JNIEnv *env, jobject thiz)
{
- ALOGV("android_media_MediaRecorder_getRoutedDeviceId");
+ ALOGV("android_media_MediaRecorder_getRoutedDeviceIds");
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
if (mr == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return AUDIO_PORT_HANDLE_NONE;
+ return NULL;
}
- audio_port_handle_t deviceId;
- process_media_recorder_call(env, mr->getRoutedDeviceId(&deviceId),
- "java/lang/RuntimeException", "getRoutedDeviceId failed.");
- return (jint) deviceId;
+ DeviceIdVector deviceIds;
+ process_media_recorder_call(env, mr->getRoutedDeviceIds(deviceIds),
+ "java/lang/RuntimeException", "getRoutedDeviceIds failed.");
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
+ }
+ jint* values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
+ }
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
static void
@@ -880,7 +890,8 @@ static const JNINativeMethod gMethods[] = {
{"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaRecorder_native_getMetrics},
{"native_setInputDevice", "(I)Z", (void *)android_media_MediaRecorder_setInputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaRecorder_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I",
+ (void *)android_media_MediaRecorder_getRoutedDeviceIds},
{"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaRecorder_enableDeviceCallback},
{"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones},
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 80ca4f239a26..2fe069af638a 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -2940,10 +2940,10 @@ jobject JTuner::getFrontendStatus(jintArray types) {
break;
}
case FrontendStatus::Tag::standardExt: {
- jfieldID field = env->GetFieldID(clazz, "mStandardExt",
- "Landroid/media/tv/tuner/frontend/StandardExt;");
+ jfieldID field = env->GetFieldID(clazz, "mStandardExtension",
+ "Landroid/media/tv/tuner/frontend/StandardExtension;");
ScopedLocalRef standardExtClazz(env,
- env->FindClass("android/media/tv/tuner/frontend/StandardExt"));
+ env->FindClass("android/media/tv/tuner/frontend/StandardExtension"));
jmethodID initStandardExt = env->GetMethodID(standardExtClazz.get(), "<init>",
"(II)V");
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 ac85ab7f6a6e..88c1c434cc0d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -257,6 +257,16 @@ public class CameraBinderTest extends AndroidTestCase {
public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
// TODO Auto-generated method stub
}
+
+ /*
+ * (non-Javadoc)
+ * @see android.hardware.camera2.ICameraDeviceCallbacks#onClientSharedAccessPriorityChanged
+ */
+ @Override
+ public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+ // TODO Auto-generated method stub
+ }
+
}
@SmallTest
@@ -276,7 +286,7 @@ public class CameraBinderTest extends AndroidTestCase {
0 /*oomScoreOffset*/,
getContext().getApplicationInfo().targetSdkVersion,
ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution,
- DEVICE_POLICY_DEFAULT);
+ DEVICE_POLICY_DEFAULT, false/*sharedMode*/);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -320,6 +330,13 @@ public class CameraBinderTest extends AndroidTestCase {
Log.v(TAG, String.format("Camera " + cameraId + " torch strength level changed to "
+ torchStrength ));
}
+ @Override
+ public void onCameraOpenedInSharedMode(String cameraId, String clientPackageName,
+ int deviceId, boolean primaryClient) {
+ Log.v(TAG, "Camera " + cameraId + " is opened in shared mode by "
+ + "client package " + clientPackageName + " as primary client="
+ + primaryClient);
+ }
}
/**
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 35ad924cee74..3758c515c1a5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -175,6 +175,15 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
// TODO Auto-generated method stub
}
+
+ /**
+ * (non-Javadoc)
+ * @see android.hardware.camera2.ICameraDeviceCallbacks#onClientSharedAccessPriorityChanged
+ */
+ @Override
+ public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+ // TODO Auto-generated method stub
+ }
}
class IsMetadataNotEmpty implements ArgumentMatcher<CameraMetadataNative> {
@@ -250,7 +259,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
/*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion,
- ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution, DEVICE_POLICY_DEFAULT);
+ ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution, DEVICE_POLICY_DEFAULT,
+ /*sharedMode*/false);
assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index c9807e626429..58aa56babb64 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -46,7 +46,7 @@ public final class FakeIMediaProjection extends IMediaProjection.Stub {
}
@Override
- public void stop() throws RemoteException {
+ public void stop(@StopReason int stopReason) throws RemoteException {
// Pass along to the client's callback wrapper.
mIMediaProjectionCallback.onStop();
}
diff --git a/native/android/dynamic_instrumentation_manager.cpp b/native/android/dynamic_instrumentation_manager.cpp
index d9bacb116f96..532213611cf1 100644
--- a/native/android/dynamic_instrumentation_manager.cpp
+++ b/native/android/dynamic_instrumentation_manager.cpp
@@ -65,7 +65,7 @@ ADynamicInstrumentationManager_TargetProcess* ADynamicInstrumentationManager_Tar
}
void ADynamicInstrumentationManager_TargetProcess_destroy(
- ADynamicInstrumentationManager_TargetProcess* instance) {
+ const ADynamicInstrumentationManager_TargetProcess* instance) {
delete instance;
}
@@ -96,7 +96,7 @@ ADynamicInstrumentationManager_MethodDescriptor_create(const char* fullyQualifie
}
void ADynamicInstrumentationManager_MethodDescriptor_destroy(
- ADynamicInstrumentationManager_MethodDescriptor* instance) {
+ const ADynamicInstrumentationManager_MethodDescriptor* instance) {
delete instance;
}
@@ -112,29 +112,29 @@ ADynamicInstrumentationManager_ExecutableMethodFileOffsets_create() {
}
const char* ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
return instance->containerPath.c_str();
}
uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
return instance->containerOffset;
}
uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
return instance->methodOffset;
}
void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
delete instance;
}
int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets(
const ADynamicInstrumentationManager_TargetProcess* targetProcess,
const ADynamicInstrumentationManager_MethodDescriptor* methodDescriptor,
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets** out) {
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets** out) {
android::os::instrumentation::TargetProcess targetProcessParcel;
targetProcessParcel.uid = targetProcess->uid;
targetProcessParcel.pid = targetProcess->pid;
diff --git a/native/android/include_platform/android/dynamic_instrumentation_manager.h b/native/android/include_platform/android/dynamic_instrumentation_manager.h
index 6c46288954bf..ab9f37034a22 100644
--- a/native/android/include_platform/android/dynamic_instrumentation_manager.h
+++ b/native/android/include_platform/android/dynamic_instrumentation_manager.h
@@ -51,7 +51,7 @@ ADynamicInstrumentationManager_TargetProcess* _Nonnull
* @param instance returned from ADynamicInstrumentationManager_TargetProcess_create.
*/
void ADynamicInstrumentationManager_TargetProcess_destroy(
- ADynamicInstrumentationManager_TargetProcess* _Nonnull instance) __INTRODUCED_IN(36);
+ const ADynamicInstrumentationManager_TargetProcess* _Nonnull instance) __INTRODUCED_IN(36);
/**
* Initializes an ADynamicInstrumentationManager_MethodDescriptor. Caller must clean up when they
@@ -74,7 +74,8 @@ ADynamicInstrumentationManager_MethodDescriptor* _Nonnull
* @param instance returned from ADynamicInstrumentationManager_MethodDescriptor_create.
*/
void ADynamicInstrumentationManager_MethodDescriptor_destroy(
- ADynamicInstrumentationManager_MethodDescriptor* _Nonnull instance) __INTRODUCED_IN(36);
+ const ADynamicInstrumentationManager_MethodDescriptor* _Nonnull instance)
+ __INTRODUCED_IN(36);
/**
* Get the containerPath calculated by
@@ -83,7 +84,7 @@ void ADynamicInstrumentationManager_MethodDescriptor_destroy(
* @return The OS path of the containing file.
*/
const char* _Nullable ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
__INTRODUCED_IN(36);
/**
* Get the containerOffset calculated by
@@ -92,7 +93,7 @@ const char* _Nullable ADynamicInstrumentationManager_ExecutableMethodFileOffsets
* @return The offset of the containing file within the process' memory.
*/
uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
__INTRODUCED_IN(36);
/**
* Get the methodOffset calculated by ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
@@ -100,7 +101,7 @@ uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainer
* @return The offset of the method within the containing file.
*/
uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
__INTRODUCED_IN(36);
/**
* Clean up an ADynamicInstrumentationManager_ExecutableMethodFileOffsets.
@@ -108,7 +109,7 @@ uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOff
* @param instance returned from ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
*/
void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
__INTRODUCED_IN(36);
/**
* Provides ART metadata about the described java method within the target process.
@@ -124,7 +125,7 @@ void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets(
const ADynamicInstrumentationManager_TargetProcess* _Nonnull targetProcess,
const ADynamicInstrumentationManager_MethodDescriptor* _Nonnull methodDescriptor,
- ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull* _Nullable out)
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nullable* _Nonnull out)
__INTRODUCED_IN(36);
__END_DECLS
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index a0460572abfc..9da7becba332 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -355,18 +355,29 @@ LIBANDROID {
APerformanceHint_getManager; # introduced=Tiramisu
APerformanceHint_createSession; # introduced=Tiramisu
APerformanceHint_getPreferredUpdateRateNanos; # introduced=Tiramisu
+ APerformanceHint_getMaxGraphicsPipelineThreadsCount; # introduced=36
APerformanceHint_updateTargetWorkDuration; # introduced=Tiramisu
APerformanceHint_reportActualWorkDuration; # introduced=Tiramisu
APerformanceHint_closeSession; # introduced=Tiramisu
APerformanceHint_setThreads; # introduced=UpsideDownCake
APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream
APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream
+ APerformanceHint_createSessionUsingConfig; # introduced=36
+ APerformanceHint_notifyWorkloadIncrease; # introduced=36
+ APerformanceHint_notifyWorkloadReset; # introduced=36
+ APerformanceHint_borrowSessionFromJava; # introduced=36
AWorkDuration_create; # introduced=VanillaIceCream
AWorkDuration_release; # introduced=VanillaIceCream
AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream
AWorkDuration_setActualTotalDurationNanos; # introduced=VanillaIceCream
AWorkDuration_setActualCpuDurationNanos; # introduced=VanillaIceCream
AWorkDuration_setActualGpuDurationNanos; # introduced=VanillaIceCream
+ ASessionCreationConfig_create; # introduced=36
+ ASessionCreationConfig_release; # introduced=36
+ ASessionCreationConfig_setTids; # introduced=36
+ ASessionCreationConfig_setTargetWorkDurationNanos; # introduced=36
+ ASessionCreationConfig_setPreferPowerEfficiency; # introduced=36
+ ASessionCreationConfig_setGraphicsPipeline; # introduced=36
local:
*;
};
@@ -376,9 +387,15 @@ LIBANDROID_PLATFORM {
AThermal_setIThermalServiceForTesting;
APerformanceHint_setIHintManagerForTesting;
APerformanceHint_sendHint;
+ APerformanceHint_setUseGraphicsPipelineForTesting;
APerformanceHint_getThreadIds;
APerformanceHint_createSessionInternal;
+ APerformanceHint_createSessionUsingConfigInternal;
APerformanceHint_setUseFMQForTesting;
+ APerformanceHint_getRateLimiterPropertiesForTesting;
+ APerformanceHint_setUseNewLoadHintBehaviorForTesting;
+ APerformanceHint_closeSessionFromJava;
+ APerformanceHint_createSessionFromJava;
extern "C++" {
ASurfaceControl_registerSurfaceStatsListener*;
ASurfaceControl_unregisterSurfaceStatsListener*;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 15f77cebf3ba..883e139cca0a 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -26,6 +26,7 @@
#include <aidl/android/hardware/power/WorkDurationFixedV1.h>
#include <aidl/android/os/IHintManager.h>
#include <aidl/android/os/IHintSession.h>
+#include <aidl/android/os/SessionCreationConfig.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <android/binder_manager.h>
@@ -33,12 +34,15 @@
#include <android/performance_hint.h>
#include <android/trace.h>
#include <android_os.h>
+#include <cutils/trace.h>
#include <fmq/AidlMessageQueue.h>
#include <inttypes.h>
+#include <jni_wrappers.h>
#include <performance_hint_private.h>
#include <utils/SystemClock.h>
#include <chrono>
+#include <format>
#include <future>
#include <set>
#include <utility>
@@ -62,6 +66,29 @@ struct APerformanceHintSession;
constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
struct AWorkDuration : public hal::WorkDuration {};
+struct ASessionCreationConfig : public SessionCreationConfig {};
+
+bool kForceGraphicsPipeline = false;
+
+bool useGraphicsPipeline() {
+ return android::os::adpf_graphics_pipeline() || kForceGraphicsPipeline;
+}
+
+// A pair of values that determine the behavior of the
+// load hint rate limiter, to only allow "X hints every Y seconds"
+constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count();
+constexpr double kMaxLoadHintsPerInterval = 20;
+constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval;
+bool kForceNewHintBehavior = false;
+
+template <class T>
+constexpr int32_t enum_size() {
+ return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
+}
+
+bool useNewLoadHintBehavior() {
+ return android::os::adpf_use_load_hints() || kForceNewHintBehavior;
+}
// Shared lock for the whole PerformanceHintManager and sessions
static std::mutex sHintMutex = std::mutex{};
@@ -76,7 +103,8 @@ public:
hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
int64_t targetDurationNanos) REQUIRES(sHintMutex);
- bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex);
+ bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint,
+ int64_t now) REQUIRES(sHintMutex);
bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
REQUIRES(sHintMutex);
void setToken(ndk::SpAIBinder& token);
@@ -86,10 +114,11 @@ public:
private:
template <HalChannelMessageContents::Tag T, bool urgent = false,
class C = HalChannelMessageContents::_at<T>>
- bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1)
- REQUIRES(sHintMutex);
+ bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1,
+ int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex);
template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
- void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex);
+ void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now)
+ REQUIRES(sHintMutex);
bool isActiveLocked() REQUIRES(sHintMutex);
bool updatePersistentTransaction() REQUIRES(sHintMutex);
@@ -117,9 +146,18 @@ public:
APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
int64_t initialTargetWorkDurationNanos,
- hal::SessionTag tag = hal::SessionTag::APP);
+ hal::SessionTag tag = hal::SessionTag::APP,
+ bool isJava = false);
+ APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
+
+ APerformanceHintSession* createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
+ hal::SessionTag tag = hal::SessionTag::APP,
+ bool isJava = false);
int64_t getPreferredRateNanos() const;
+ int32_t getMaxGraphicsPipelineThreadsCount();
FMQWrapper& getFMQWrapper();
+ bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
+ void initJava(JNIEnv* _Nonnull env);
private:
// Necessary to create an empty binder object
@@ -137,25 +175,34 @@ private:
std::shared_ptr<IHintManager> mHintManager;
ndk::SpAIBinder mToken;
const int64_t mPreferredRateNanos;
+ std::optional<int32_t> mMaxGraphicsPipelineThreadsCount;
FMQWrapper mFMQWrapper;
+ double mHintBudget = kMaxLoadHintsPerInterval;
+ int64_t mLastBudgetReplenish = 0;
+ bool mJavaInitialized = false;
+ jclass mJavaSessionClazz;
+ jfieldID mJavaSessionNativePtr;
};
struct APerformanceHintSession {
public:
APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
- int64_t targetDurationNanos,
+ int64_t targetDurationNanos, bool isJava,
std::optional<hal::SessionConfig> sessionConfig);
APerformanceHintSession() = delete;
~APerformanceHintSession();
int updateTargetWorkDuration(int64_t targetDurationNanos);
int reportActualWorkDuration(int64_t actualDurationNanos);
- int sendHint(SessionHint hint);
+ int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName);
+ int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName);
+ int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName);
int setThreads(const int32_t* threadIds, size_t size);
int getThreadIds(int32_t* const threadIds, size_t* size);
int setPreferPowerEfficiency(bool enabled);
int reportActualWorkDuration(AWorkDuration* workDuration);
+ bool isJava();
private:
friend struct APerformanceHintManager;
@@ -173,17 +220,23 @@ private:
// Last target hit timestamp
int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
// Last hint reported from sendHint indexed by hint value
+ // This is only used by the old rate limiter impl and is replaced
+ // with the new rate limiter under a flag
std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
// Cached samples
std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
+ // Is this session backing an SDK wrapper object
+ const bool mIsJava;
std::string mSessionName;
static int64_t sIDCounter GUARDED_BY(sHintMutex);
// The most recent set of thread IDs
std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
// Tracing helpers
- void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
+ void traceThreads(const std::vector<int32_t>& tids) REQUIRES(sHintMutex);
void tracePowerEfficient(bool powerEfficient);
+ void traceGraphicsPipeline(bool graphicsPipeline);
+ void traceModes(const std::vector<hal::SessionMode>& modesToEnable);
void traceActualDuration(int64_t actualDuration);
void traceBatchSize(size_t batchSize);
void traceTargetDuration(int64_t targetDuration);
@@ -255,30 +308,75 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa
return new APerformanceHintManager(manager, preferredRateNanos);
}
+bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
+ mHintBudget =
+ std::max(kMaxLoadHintsPerInterval,
+ mHintBudget +
+ static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate);
+ mLastBudgetReplenish = now;
+
+ // If this youngest timestamp isn't older than the timeout time, we can't send
+ if (hints.size() > mHintBudget) {
+ return false;
+ }
+ mHintBudget -= hints.size();
+ return true;
+}
+
APerformanceHintSession* APerformanceHintManager::createSession(
const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
- hal::SessionTag tag) {
- std::vector<int32_t> tids(threadIds, threadIds + size);
- std::shared_ptr<IHintSession> session;
+ hal::SessionTag tag, bool isJava) {
ndk::ScopedAStatus ret;
hal::SessionConfig sessionConfig{.id = -1};
- ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
- tag, &sessionConfig, &session);
+
+ SessionCreationConfig creationConfig{
+ .tids = std::vector<int32_t>(threadIds, threadIds + size),
+ .targetWorkDurationNanos = initialTargetWorkDurationNanos,
+ };
+
+ return APerformanceHintManager::createSessionUsingConfig(static_cast<ASessionCreationConfig*>(
+ &creationConfig),
+ tag, isJava);
+}
+
+APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
+ ASessionCreationConfig* sessionCreationConfig, hal::SessionTag tag, bool isJava) {
+ std::shared_ptr<IHintSession> session;
+ hal::SessionConfig sessionConfig{.id = -1};
+ ndk::ScopedAStatus ret;
+
+ ret = mHintManager->createHintSessionWithConfig(mToken, tag,
+ *static_cast<SessionCreationConfig*>(
+ sessionCreationConfig),
+ &sessionConfig, &session);
if (!ret.isOk() || !session) {
ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
return nullptr;
}
auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
- initialTargetWorkDurationNanos,
+ sessionCreationConfig->targetWorkDurationNanos, isJava,
sessionConfig.id == -1
? std::nullopt
: std::make_optional<hal::SessionConfig>(
std::move(sessionConfig)));
std::scoped_lock lock(sHintMutex);
- out->traceThreads(tids);
- out->traceTargetDuration(initialTargetWorkDurationNanos);
- out->tracePowerEfficient(false);
+ out->traceThreads(sessionCreationConfig->tids);
+ out->traceTargetDuration(sessionCreationConfig->targetWorkDurationNanos);
+ out->traceModes(sessionCreationConfig->modesToEnable);
+
+ return out;
+}
+
+APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env,
+ jobject sessionObj) {
+ initJava(env);
+ LOG_ALWAYS_FATAL_IF(!env->IsInstanceOf(sessionObj, mJavaSessionClazz),
+ "Wrong java type passed to APerformanceHint_getSessionFromJava");
+ APerformanceHintSession* out = reinterpret_cast<APerformanceHintSession*>(
+ env->GetLongField(sessionObj, mJavaSessionNativePtr));
+ LOG_ALWAYS_FATAL_IF(out == nullptr, "Java-wrapped native hint session is nullptr");
+ LOG_ALWAYS_FATAL_IF(!out->isJava(), "Unmanaged native hint session returned from Java SDK");
return out;
}
@@ -286,19 +384,44 @@ int64_t APerformanceHintManager::getPreferredRateNanos() const {
return mPreferredRateNanos;
}
+int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() {
+ if (!mMaxGraphicsPipelineThreadsCount.has_value()) {
+ int32_t threadsCount = -1;
+ ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount);
+ if (!ret.isOk()) {
+ ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s",
+ __FUNCTION__, ret.getMessage());
+ return -1;
+ }
+ if (threadsCount <= 0) {
+ threadsCount = -1;
+ }
+ mMaxGraphicsPipelineThreadsCount.emplace(threadsCount);
+ }
+ return mMaxGraphicsPipelineThreadsCount.value();
+}
+
FMQWrapper& APerformanceHintManager::getFMQWrapper() {
return mFMQWrapper;
}
-// ===================================== APerformanceHintSession implementation
+void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
+ if (mJavaInitialized) {
+ return;
+ }
+ jclass sessionClazz = FindClassOrDie(env, "android/os/PerformanceHintManager$Session");
+ mJavaSessionClazz = MakeGlobalRefOrDie(env, sessionClazz);
+ mJavaSessionNativePtr = GetFieldIDOrDie(env, mJavaSessionClazz, "mNativeSessionPtr", "J");
+ mJavaInitialized = true;
+}
-constexpr int kNumEnums =
- ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
+// ===================================== APerformanceHintSession implementation
+constexpr int kNumEnums = enum_size<hal::SessionHint>();
APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
std::shared_ptr<IHintSession> session,
int64_t preferredRateNanos,
- int64_t targetDurationNanos,
+ int64_t targetDurationNanos, bool isJava,
std::optional<hal::SessionConfig> sessionConfig)
: mHintManager(hintManager),
mHintSession(std::move(session)),
@@ -307,6 +430,7 @@ APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> h
mFirstTargetMetTimestamp(0),
mLastTargetMetTimestamp(0),
mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
+ mIsJava(isJava),
mSessionConfig(sessionConfig) {
if (sessionConfig->id > INT32_MAX) {
ALOGE("Session ID too large, must fit 32-bit integer");
@@ -361,31 +485,87 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano
return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
}
-int APerformanceHintSession::sendHint(SessionHint hint) {
+bool APerformanceHintSession::isJava() {
+ return mIsJava;
+}
+
+int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
+ const char*) {
std::scoped_lock lock(sHintMutex);
- if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
- ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
+ if (hints.empty()) {
return EINVAL;
}
- int64_t now = uptimeNanos();
+ for (auto&& hint : hints) {
+ if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) {
+ ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
+ return EINVAL;
+ }
+ }
- // Limit sendHint to a pre-detemined rate for safety
- if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
- return 0;
+ if (useNewLoadHintBehavior()) {
+ if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
+ return EBUSY;
+ }
+ }
+ // keep old rate limiter behavior for legacy flag
+ else {
+ for (auto&& hint : hints) {
+ if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) {
+ return EBUSY;
+ }
+ }
}
- if (!getFMQ().sendHint(mSessionConfig, hint)) {
- ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
+ if (!getFMQ().sendHints(mSessionConfig, hints, now)) {
+ for (auto&& hint : hints) {
+ ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint));
- if (!ret.isOk()) {
- ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
- return EPIPE;
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
+ return EPIPE;
+ }
}
}
- mLastHintSentTimestamp[hint] = now;
+
+ if (!useNewLoadHintBehavior()) {
+ for (auto&& hint : hints) {
+ mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now;
+ }
+ }
+
+ if (ATrace_isEnabled()) {
+ ATRACE_INSTANT("Sending load hint");
+ }
+
return 0;
}
+int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) {
+ std::vector<hal::SessionHint> hints(2);
+ hints.clear();
+ if (cpu) {
+ hints.push_back(hal::SessionHint::CPU_LOAD_UP);
+ }
+ if (gpu) {
+ hints.push_back(hal::SessionHint::GPU_LOAD_UP);
+ }
+ int64_t now = ::android::uptimeNanos();
+ return sendHints(hints, now, debugName);
+}
+
+int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) {
+ std::vector<hal::SessionHint> hints(2);
+ hints.clear();
+ if (cpu) {
+ hints.push_back(hal::SessionHint::CPU_LOAD_RESET);
+ }
+ if (gpu) {
+ hints.push_back(hal::SessionHint::GPU_LOAD_RESET);
+ }
+ int64_t now = ::android::uptimeNanos();
+ return sendHints(hints, now, debugName);
+}
+
int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
if (size == 0) {
ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
@@ -565,24 +745,25 @@ void FMQWrapper::stopChannel(IHintManager* manager) {
}
template <HalChannelMessageContents::Tag T, class C>
-void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) {
- new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{
- .sessionID = static_cast<int32_t>(config.id),
- .timeStampNanos = ::android::uptimeNanos(),
- .data = HalChannelMessageContents::make<T, C>(std::move(*message)),
- };
+void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) {
+ for (size_t i = 0; i < count; ++i) {
+ new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
+ .sessionID = static_cast<int32_t>(config.id),
+ .timeStampNanos = now,
+ .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))),
+ };
+ }
}
template <>
void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
hal::SessionConfig& config,
- size_t count) {
+ size_t count, int64_t now) {
for (size_t i = 0; i < count; ++i) {
hal::WorkDuration& message = messages[i];
new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
.sessionID = static_cast<int32_t>(config.id),
- .timeStampNanos =
- (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos,
+ .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
.data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
hal::WorkDurationFixedV1>({
.durationNanos = message.cpuDurationNanos,
@@ -595,7 +776,8 @@ void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkD
}
template <HalChannelMessageContents::Tag T, bool urgent, class C>
-bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) {
+bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count,
+ int64_t now) {
if (!isActiveLocked() || !config.has_value() || mCorrupted) {
return false;
}
@@ -609,7 +791,7 @@ bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* mess
return false;
}
}
- writeBuffer<T, C>(message, *config, count);
+ writeBuffer<T, C>(message, *config, count, now);
mQueue->commitWrite(count);
mEventFlag->wake(mWriteMask);
// Re-create the persistent transaction after writing
@@ -641,10 +823,9 @@ bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& con
return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
}
-bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) {
- return sendMessages<HalChannelMessageContents::hint>(config,
- reinterpret_cast<hal::SessionHint*>(
- &hint));
+bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config,
+ std::vector<hal::SessionHint>& hints, int64_t now) {
+ return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now);
}
bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
@@ -656,7 +837,7 @@ bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::Session
// ===================================== Tracing helpers
-void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
+void APerformanceHintSession::traceThreads(const std::vector<int32_t>& tids) {
std::set<int32_t> tidSet{tids.begin(), tids.end()};
// Disable old TID tracing
@@ -682,6 +863,30 @@ void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
}
+void APerformanceHintSession::traceGraphicsPipeline(bool graphicsPipeline) {
+ ATrace_setCounter((mSessionName + " graphics pipeline mode").c_str(), graphicsPipeline);
+}
+
+void APerformanceHintSession::traceModes(const std::vector<hal::SessionMode>& modesToEnable) {
+ // Iterate through all modes to trace, set to enable for all modes in modesToEnable,
+ // and set to disable for those are not.
+ for (hal::SessionMode mode :
+ {hal::SessionMode::POWER_EFFICIENCY, hal::SessionMode::GRAPHICS_PIPELINE}) {
+ bool isEnabled =
+ find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
+ switch (mode) {
+ case hal::SessionMode::POWER_EFFICIENCY:
+ tracePowerEfficient(isEnabled);
+ break;
+ case hal::SessionMode::GRAPHICS_PIPELINE:
+ traceGraphicsPipeline(isEnabled);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
}
@@ -724,6 +929,22 @@ APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager*
return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
}
+APerformanceHintSession* APerformanceHint_createSessionUsingConfig(
+ APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig) {
+ VALIDATE_PTR(manager);
+ VALIDATE_PTR(sessionCreationConfig);
+ return manager->createSessionUsingConfig(sessionCreationConfig);
+}
+
+APerformanceHintSession* APerformanceHint_createSessionUsingConfigInternal(
+ APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig,
+ SessionTag tag) {
+ VALIDATE_PTR(manager);
+ VALIDATE_PTR(sessionCreationConfig);
+ return manager->createSessionUsingConfig(sessionCreationConfig,
+ static_cast<hal::SessionTag>(tag));
+}
+
APerformanceHintSession* APerformanceHint_createSessionInternal(
APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
int64_t initialTargetWorkDurationNanos, SessionTag tag) {
@@ -733,11 +954,32 @@ APerformanceHintSession* APerformanceHint_createSessionInternal(
static_cast<hal::SessionTag>(tag));
}
+APerformanceHintSession* APerformanceHint_createSessionFromJava(
+ APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos) {
+ VALIDATE_PTR(manager)
+ VALIDATE_PTR(threadIds)
+ return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
+ hal::SessionTag::APP, true);
+}
+
+APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env,
+ jobject sessionObj) {
+ VALIDATE_PTR(env)
+ VALIDATE_PTR(sessionObj)
+ return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj);
+}
+
int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
VALIDATE_PTR(manager)
return manager->getPreferredRateNanos();
}
+int APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager* manager) {
+ VALIDATE_PTR(manager);
+ return manager->getMaxGraphicsPipelineThreadsCount();
+}
+
int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
int64_t targetDurationNanos) {
VALIDATE_PTR(session)
@@ -753,12 +995,24 @@ int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
void APerformanceHint_closeSession(APerformanceHintSession* session) {
VALIDATE_PTR(session)
+ if (session->isJava()) {
+ LOG_ALWAYS_FATAL("%s: Java-owned PerformanceHintSession cannot be closed in native",
+ __FUNCTION__);
+ return;
+ }
+ delete session;
+}
+
+void APerformanceHint_closeSessionFromJava(APerformanceHintSession* session) {
+ VALIDATE_PTR(session)
delete session;
}
int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
VALIDATE_PTR(session)
- return session->sendHint(hint);
+ std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)};
+ int64_t now = ::android::uptimeNanos();
+ return session->sendHints(hints, now, "HWUI hint");
}
int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
@@ -791,6 +1045,26 @@ int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
return session->reportActualWorkDuration(workDurationPtr);
}
+int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu,
+ const char* debugName) {
+ VALIDATE_PTR(session)
+ VALIDATE_PTR(debugName)
+ if (!useNewLoadHintBehavior()) {
+ return ENOTSUP;
+ }
+ return session->notifyWorkloadIncrease(cpu, gpu, debugName);
+}
+
+int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu,
+ const char* debugName) {
+ VALIDATE_PTR(session)
+ VALIDATE_PTR(debugName)
+ if (!useNewLoadHintBehavior()) {
+ return ENOTSUP;
+ }
+ return session->notifyWorkloadReset(cpu, gpu, debugName);
+}
+
AWorkDuration* AWorkDuration_create() {
return new AWorkDuration();
}
@@ -838,3 +1112,88 @@ void APerformanceHint_setIHintManagerForTesting(void* iManager) {
void APerformanceHint_setUseFMQForTesting(bool enabled) {
gForceFMQEnabled = enabled;
}
+
+ASessionCreationConfig* ASessionCreationConfig_create() {
+ return new ASessionCreationConfig();
+}
+
+void ASessionCreationConfig_release(ASessionCreationConfig* config) {
+ VALIDATE_PTR(config)
+
+ delete config;
+}
+
+int ASessionCreationConfig_setTids(ASessionCreationConfig* config, const pid_t* tids, size_t size) {
+ VALIDATE_PTR(config)
+ VALIDATE_PTR(tids)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ if (size <= 0) {
+ LOG_ALWAYS_FATAL_IF(size <= 0,
+ "%s: Invalid value. Thread id list size should be greater than zero.",
+ __FUNCTION__);
+ return EINVAL;
+ }
+ config->tids = std::vector<int32_t>(tids, tids + size);
+ return 0;
+}
+
+int ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig* config,
+ int64_t targetWorkDurationNanos) {
+ VALIDATE_PTR(config)
+ VALIDATE_INT(targetWorkDurationNanos, >= 0)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ config->targetWorkDurationNanos = targetWorkDurationNanos;
+ return 0;
+}
+
+int ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig* config, bool enabled) {
+ VALIDATE_PTR(config)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ if (enabled) {
+ config->modesToEnable.push_back(hal::SessionMode::POWER_EFFICIENCY);
+ } else {
+ std::erase(config->modesToEnable, hal::SessionMode::POWER_EFFICIENCY);
+ }
+ return 0;
+}
+
+int ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, bool enabled) {
+ VALIDATE_PTR(config)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ if (enabled) {
+ config->modesToEnable.push_back(hal::SessionMode::GRAPHICS_PIPELINE);
+ } else {
+ std::erase(config->modesToEnable, hal::SessionMode::GRAPHICS_PIPELINE);
+ }
+ return 0;
+}
+
+void APerformanceHint_setUseGraphicsPipelineForTesting(bool enabled) {
+ kForceGraphicsPipeline = enabled;
+}
+
+void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
+ int64_t* loadHintInterval) {
+ *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
+ *loadHintInterval = kLoadHintInterval;
+}
+
+void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
+ kForceNewHintBehavior = newBehavior;
+}
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index 9de3a6f525e6..c5fb80840b84 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -18,9 +18,11 @@
#include <aidl/android/hardware/power/ChannelConfig.h>
#include <aidl/android/hardware/power/SessionConfig.h>
+#include <aidl/android/hardware/power/SessionMode.h>
#include <aidl/android/hardware/power/SessionTag.h>
#include <aidl/android/hardware/power/WorkDuration.h>
#include <aidl/android/os/IHintManager.h>
+#include <aidl/android/os/SessionCreationConfig.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <android/performance_hint.h>
@@ -36,6 +38,7 @@ using namespace std::chrono_literals;
namespace hal = aidl::android::hardware::power;
using aidl::android::os::IHintManager;
using aidl::android::os::IHintSession;
+using aidl::android::os::SessionCreationConfig;
using ndk::ScopedAStatus;
using ndk::SpAIBinder;
using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
@@ -49,11 +52,13 @@ using namespace testing;
class MockIHintManager : public IHintManager {
public:
MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig,
- (const SpAIBinder& token, const ::std::vector<int32_t>& tids, int64_t durationNanos,
- hal::SessionTag tag, hal::SessionConfig* config,
+ (const SpAIBinder& token, hal::SessionTag tag,
+ const SessionCreationConfig& creationConfig, hal::SessionConfig* config,
std::shared_ptr<IHintSession>* _aidl_return),
(override));
MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
+ MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return),
+ (override));
MOCK_METHOD(ScopedAStatus, setHintSessionThreads,
(const std::shared_ptr<IHintSession>& hintSession,
const ::std::vector<int32_t>& tids),
@@ -66,6 +71,18 @@ public:
std::optional<hal::ChannelConfig>* _aidl_return),
(override));
MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override));
+ MOCK_METHOD(ScopedAStatus, getCpuHeadroom,
+ (const ::aidl::android::os::CpuHeadroomParamsInternal& in_params,
+ std::vector<float>* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, getCpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, getGpuHeadroom,
+ (const ::aidl::android::os::GpuHeadroomParamsInternal& in_params,
+ float* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
+ (override));
MOCK_METHOD(SpAIBinder, asBinder, (), (override));
MOCK_METHOD(bool, isRemote, (), (override));
};
@@ -90,7 +107,11 @@ class PerformanceHintTest : public Test {
public:
void SetUp() override {
mMockIHintManager = ndk::SharedRefBase::make<NiceMock<MockIHintManager>>();
+ APerformanceHint_getRateLimiterPropertiesForTesting(&mMaxLoadHintsPerInterval,
+ &mLoadHintInterval);
APerformanceHint_setIHintManagerForTesting(&mMockIHintManager);
+ APerformanceHint_setUseGraphicsPipelineForTesting(true);
+ APerformanceHint_setUseNewLoadHintBehaviorForTesting(true);
}
void TearDown() override {
@@ -103,21 +124,22 @@ public:
APerformanceHint_setUseFMQForTesting(mUsingFMQ);
ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
.WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); }));
+ ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); }));
return APerformanceHint_getManager();
}
APerformanceHintSession* createSession(APerformanceHintManager* manager,
int64_t targetDuration = 56789L, bool isHwui = false) {
mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
- int64_t sessionId = 123;
+ const int64_t sessionId = 123;
std::vector<int32_t> tids;
tids.push_back(1);
tids.push_back(2);
- ON_CALL(*mMockIHintManager,
- createHintSessionWithConfig(_, Eq(tids), Eq(targetDuration), _, _, _))
- .WillByDefault(DoAll(SetArgPointee<4>(hal::SessionConfig({.id = sessionId})),
- SetArgPointee<5>(std::shared_ptr<IHintSession>(mMockSession)),
+ ON_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _))
+ .WillByDefault(DoAll(SetArgPointee<3>(hal::SessionConfig({.id = sessionId})),
+ SetArgPointee<4>(std::shared_ptr<IHintSession>(mMockSession)),
[] { return ScopedAStatus::ok(); }));
ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] {
@@ -142,6 +164,43 @@ public:
return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
}
+ APerformanceHintSession* createSessionUsingConfig(APerformanceHintManager* manager,
+ SessionCreationConfig config,
+ bool isHwui = false) {
+ mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
+ const int64_t sessionId = 123;
+
+ ON_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _))
+ .WillByDefault(DoAll(SetArgPointee<3>(hal::SessionConfig({.id = sessionId})),
+ SetArgPointee<4>(std::shared_ptr<IHintSession>(mMockSession)),
+ [] { return ScopedAStatus::ok(); }));
+
+ ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+ ON_CALL(*mMockSession, sendHint(_)).WillByDefault([] { return ScopedAStatus::ok(); });
+ ON_CALL(*mMockSession, setMode(_, true)).WillByDefault([] { return ScopedAStatus::ok(); });
+ ON_CALL(*mMockSession, close()).WillByDefault([] { return ScopedAStatus::ok(); });
+ ON_CALL(*mMockSession, updateTargetWorkDuration(_)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+ ON_CALL(*mMockSession, reportActualWorkDuration(_, _)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+ ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+
+ if (isHwui) {
+ return APerformanceHint_createSessionUsingConfigInternal(
+ manager, reinterpret_cast<ASessionCreationConfig*>(&config), SessionTag::HWUI);
+ }
+
+ return APerformanceHint_createSessionUsingConfig(manager,
+ reinterpret_cast<ASessionCreationConfig*>(
+ &config));
+ }
+
void setFMQEnabled(bool enabled) {
mUsingFMQ = enabled;
if (enabled) {
@@ -176,6 +235,9 @@ public:
int kMockQueueSize = 20;
bool mUsingFMQ = false;
+ int32_t mMaxLoadHintsPerInterval;
+ int64_t mLoadHintInterval;
+
template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
void expectToReadFromFmq(C expected) {
hal::ChannelMessage readData;
@@ -218,7 +280,6 @@ TEST_F(PerformanceHintTest, TestSession) {
EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(Exactly(1));
result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos);
EXPECT_EQ(0, result);
-
result = APerformanceHint_updateTargetWorkDuration(session, -1L);
EXPECT_EQ(EINVAL, result);
result = APerformanceHint_reportActualWorkDuration(session, -1L);
@@ -228,33 +289,53 @@ TEST_F(PerformanceHintTest, TestSession) {
EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1));
result = APerformanceHint_sendHint(session, hintId);
EXPECT_EQ(0, result);
- usleep(110000); // Sleep for longer than the update timeout.
- EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1));
- result = APerformanceHint_sendHint(session, hintId);
+ EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_UP))).Times(Exactly(1));
+ result = APerformanceHint_notifyWorkloadIncrease(session, true, false, "Test hint");
EXPECT_EQ(0, result);
- // Expect to get rate limited if we try to send faster than the limiter allows
- EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(0));
- result = APerformanceHint_sendHint(session, hintId);
+ EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_RESET))).Times(Exactly(1));
+ EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::GPU_LOAD_RESET))).Times(Exactly(1));
+ result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint");
EXPECT_EQ(0, result);
result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1));
EXPECT_EQ(EINVAL, result);
+ Mock::VerifyAndClearExpectations(mMockSession.get());
+ for (int i = 0; i < mMaxLoadHintsPerInterval; ++i) {
+ APerformanceHint_sendHint(session, hintId);
+ }
+
+ // Expect to get rate limited if we try to send faster than the limiter allows
+ EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0));
+ result = APerformanceHint_notifyWorkloadIncrease(session, true, true, "Test hint");
+ EXPECT_EQ(result, EBUSY);
+ EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0));
+ result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint");
EXPECT_CALL(*mMockSession, close()).Times(Exactly(1));
APerformanceHint_closeSession(session);
}
TEST_F(PerformanceHintTest, TestUpdatedSessionCreation) {
- EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _)).Times(1);
APerformanceHintManager* manager = createManager();
APerformanceHintSession* session = createSession(manager);
ASSERT_TRUE(session);
APerformanceHint_closeSession(session);
}
+TEST_F(PerformanceHintTest, TestSessionCreationUsingConfig) {
+ EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _)).Times(1);
+ SessionCreationConfig config{.tids = std::vector<int32_t>(1, 2),
+ .targetWorkDurationNanos = 5678,
+ .modesToEnable = std::vector<hal::SessionMode>(0)};
+ APerformanceHintManager* manager = createManager();
+ APerformanceHintSession* session = createSessionUsingConfig(manager, config);
+ ASSERT_TRUE(session);
+ APerformanceHint_closeSession(session);
+}
+
TEST_F(PerformanceHintTest, TestHwuiSessionCreation) {
- EXPECT_CALL(*mMockIHintManager,
- createHintSessionWithConfig(_, _, _, hal::SessionTag::HWUI, _, _))
+ EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, hal::SessionTag::HWUI, _, _, _))
.Times(1);
APerformanceHintManager* manager = createManager();
APerformanceHintSession* session = createSession(manager, 56789L, true);
@@ -420,3 +501,16 @@ TEST_F(PerformanceHintTest, TestReportActualUsingFMQ) {
reinterpret_cast<AWorkDuration*>(&duration));
expectToReadFromFmq<HalChannelMessageContents::Tag::workDuration>(durationExpected);
}
+
+TEST_F(PerformanceHintTest, TestASessionCreationConfig) {
+ ASessionCreationConfig* config = ASessionCreationConfig_create();
+ ASSERT_NE(config, nullptr);
+
+ const int32_t testTids[2] = {1, 2};
+ const size_t size = 2;
+ EXPECT_EQ(ASessionCreationConfig_setTids(config, testTids, size), 0);
+ EXPECT_EQ(ASessionCreationConfig_setTargetWorkDurationNanos(config, 20), 0);
+ EXPECT_EQ(ASessionCreationConfig_setPreferPowerEfficiency(config, true), 0);
+ EXPECT_EQ(ASessionCreationConfig_setGraphicsPipeline(config, true), 0);
+ ASessionCreationConfig_release(config);
+}
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 23dd9b7aee37..4180710534c3 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -45,8 +45,10 @@ cc_library_shared {
header_libs: [
"jni_headers",
+ "native_headers",
"libhwui_internal_headers",
],
+ export_header_lib_headers: ["native_headers"],
static_libs: [
"libarect",
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 008120429c40..0ee81cbb7a73 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -81,11 +81,14 @@ package android.nfc {
method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
method public boolean isSecureNfcEnabled();
method public boolean isSecureNfcSupported();
+ method @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public boolean isTagIntentAllowed();
+ method @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public boolean isTagIntentAppPreferenceSupported();
method @FlaggedApi("android.nfc.enable_nfc_charging") public boolean isWlcEnabled();
method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void resetDiscoveryTechnology(@NonNull android.app.Activity);
method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void setDiscoveryTechnology(@NonNull android.app.Activity, int, int);
method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setObserveModeEnabled(boolean);
field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
+ field @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public static final String ACTION_CHANGE_TAG_INTENT_PREFERENCE = "android.nfc.action.CHANGE_TAG_INTENT_PREFERENCE";
field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
@@ -199,6 +202,7 @@ package android.nfc.cardemulation {
method public boolean categoryAllowsForegroundPreference(String);
method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService();
method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String);
+ method @FlaggedApi("android.nfc.enable_card_emulation_euicc") public int getDefaultNfcSubscriptionId();
method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public CharSequence getDescriptionForPreferredPaymentService();
method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService();
@@ -225,6 +229,11 @@ package android.nfc.cardemulation {
field public static final String CATEGORY_PAYMENT = "payment";
field public static final String EXTRA_CATEGORY = "category";
field public static final String EXTRA_SERVICE_COMPONENT = "component";
+ field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_COMMAND_TIMEOUT = 3; // 0x3
+ field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_CRASH_RESTART = 1; // 0x1
+ field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR = 2; // 0x2
+ field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_UNKNOWN = 0; // 0x0
+ field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY = "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3; // 0x3
field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DH = 0; // 0x0
field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE = 1; // 0x1
@@ -236,8 +245,13 @@ package android.nfc.cardemulation {
}
@FlaggedApi("android.nfc.nfc_event_listener") public static interface CardEmulation.NfcEventListener {
+ method @FlaggedApi("android.nfc.nfc_event_listener") public default void onAidConflictOccurred(@NonNull String);
+ method @FlaggedApi("android.nfc.nfc_event_listener") public default void onAidNotRouted(@NonNull String);
+ method @FlaggedApi("android.nfc.nfc_event_listener") public default void onInternalErrorReported(int);
+ method @FlaggedApi("android.nfc.nfc_event_listener") public default void onNfcStateChanged(int);
method @FlaggedApi("android.nfc.nfc_event_listener") public default void onObserveModeStateChanged(boolean);
method @FlaggedApi("android.nfc.nfc_event_listener") public default void onPreferredServiceChanged(boolean);
+ method @FlaggedApi("android.nfc.nfc_event_listener") public default void onRemoteFieldChanged(boolean);
}
public abstract class HostApduService extends android.app.Service {
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index a23845fa17e9..3ed9b7667be7 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -11,7 +11,6 @@ package android.nfc {
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerNfcVendorNciCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
method @FlaggedApi("android.nfc.enable_nfc_charging") public void registerWlcStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.WlcStateListener);
@@ -57,22 +56,28 @@ package android.nfc {
@FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int forceRoutingTableCommit();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getActiveNfceeList();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public long getMaxPausePollingTimeoutMills();
method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.nfc.RoutingStatus getRoutingStatus();
method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.List<android.nfc.NfcRoutingTableEntry> getRoutingTable();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public android.nfc.T4tNdefNfcee getT4tNdefNfcee();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean hasUserEnabledNfc();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAutoChangeEnabled();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagPresent();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overwriteRoutingTable(int, int, int, int);
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void pausePolling(int);
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int pausePolling(long);
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void resumePolling();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int resumePolling();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAutoChangeEnabled(boolean);
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOnMode(int);
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void triggerInitialization();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
+ field public static final int COMMIT_ROUTING_STATUS_FAILED = 3; // 0x3
+ field public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6; // 0x6
+ field public static final int COMMIT_ROUTING_STATUS_OK = 0; // 0x0
field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int DISABLE = 0; // 0x0
field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_DEFAULT = 1; // 0x1
field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_EE = 3; // 0x3
@@ -80,6 +85,8 @@ package android.nfc {
field public static final int HCE_ACTIVATE = 1; // 0x1
field public static final int HCE_DATA_TRANSFERRED = 2; // 0x2
field public static final int HCE_DEACTIVATE = 3; // 0x3
+ field public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2; // 0x2
+ field public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1; // 0x1
field public static final int STATUS_OK = 0; // 0x0
field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
}
@@ -89,13 +96,15 @@ package android.nfc {
method public void onBootFinished(int);
method public void onBootStarted();
method public void onCardEmulationActivated(boolean);
- method public void onDisable(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onDisableFinished(int);
+ method public void onDisableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onDisableStarted();
method public void onEeListenActivated(boolean);
- method public void onEnable(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method public void onEeUpdated();
method public void onEnableFinished(int);
+ method public void onEnableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onEnableStarted();
+ method public void onExtractOemPackages(@NonNull android.nfc.NdefMessage, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
method public void onGetOemAppSearchIntent(@NonNull java.util.List<java.lang.String>, @NonNull java.util.function.Consumer<android.content.Intent>);
method public void onHceEventReceived(int);
method public void onLaunchHceAppChooserActivity(@NonNull String, @NonNull java.util.List<android.nfc.cardemulation.ApduServiceInfo>, @NonNull android.content.ComponentName, @NonNull String);
@@ -106,7 +115,8 @@ package android.nfc {
method public void onReaderOptionChanged(boolean);
method public void onRfDiscoveryStarted(boolean);
method public void onRfFieldActivated(boolean);
- method public void onRoutingChanged();
+ method public void onRoutingChanged(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method public void onRoutingTableFull();
method public void onStateUpdated(int);
method public void onTagConnected(boolean);
method public void onTagDispatch(@NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -114,6 +124,11 @@ package android.nfc {
@FlaggedApi("android.nfc.nfc_oem_extension") public abstract class NfcRoutingTableEntry {
method public int getNfceeId();
+ method public int getType();
+ field public static final int TYPE_AID = 0; // 0x0
+ field public static final int TYPE_PROTOCOL = 1; // 0x1
+ field public static final int TYPE_SYSTEM_CODE = 3; // 0x3
+ field public static final int TYPE_TECHNOLOGY = 2; // 0x2
}
@FlaggedApi("android.nfc.nfc_oem_extension") public final class OemLogItems implements android.os.Parcelable {
@@ -173,6 +188,47 @@ package android.nfc {
field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_V = 3; // 0x3
}
+ @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfcee {
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int clearData();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isOperationOngoing();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isSupported();
+ method @Nullable @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public android.nfc.T4tNdefNfceeCcFileInfo readCcfile();
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public byte[] readData(@IntRange(from=0, to=65535) int);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int writeData(@IntRange(from=0, to=65535) int, @NonNull byte[]);
+ field public static final int CLEAR_DATA_FAILED_INTERNAL = 0; // 0x0
+ field public static final int CLEAR_DATA_SUCCESS = 1; // 0x1
+ field public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6; // 0xfffffffa
+ field public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7; // 0xfffffff9
+ field public static final int WRITE_DATA_ERROR_INTERNAL = -1; // 0xffffffff
+ field public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4; // 0xfffffffc
+ field public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5; // 0xfffffffb
+ field public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8; // 0xfffffff8
+ field public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3; // 0xfffffffd
+ field public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2; // 0xfffffffe
+ field public static final int WRITE_DATA_SUCCESS = 0; // 0x0
+ }
+
+ @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfceeCcFileInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=15, to=32767) public int getCcFileLength();
+ method @IntRange(from=0xffffffff, to=65535) public int getFileId();
+ method @IntRange(from=15, to=65535) public int getMaxReadLength();
+ method @IntRange(from=5, to=32767) public int getMaxSize();
+ method @IntRange(from=13, to=65535) public int getMaxWriteLength();
+ method public int getReadAccess();
+ method public int getVersion();
+ method public int getWriteAccess();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.T4tNdefNfceeCcFileInfo> CREATOR;
+ field public static final int READ_ACCESS_GRANTED_RESTRICTED = 128; // 0x80
+ field public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0
+ field public static final int VERSION_2_0 = 32; // 0x20
+ field public static final int VERSION_3_0 = 48; // 0x30
+ field public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 128; // 0x80
+ field public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0
+ field public static final int WRITE_ACCESS_NOT_GRANTED = 255; // 0xff
+ }
+
}
package android.nfc.cardemulation {
@@ -180,8 +236,19 @@ package android.nfc.cardemulation {
public final class CardEmulation {
method @FlaggedApi("android.permission.flags.wallet_role_enabled") @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static android.content.ComponentName getPreferredPaymentService(@NonNull android.content.Context);
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
- method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
- method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void recoverRoutingTable(@NonNull android.app.Activity);
+ method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
+ method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void recoverRoutingTable(@NonNull android.app.Activity);
+ method @FlaggedApi("android.nfc.enable_card_emulation_euicc") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setDefaultNfcSubscriptionId(int);
+ method @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setServiceEnabledForCategoryOther(@NonNull android.content.ComponentName, boolean);
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; // 0x3
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; // 0x1
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; // 0x2
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; // 0x4
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; // 0x0
+ field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR = 2; // 0x2
+ field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1; // 0x1
+ field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3; // 0x3
+ field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0; // 0x0
}
}
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 40fd0683f465..ac0a5aaaa195 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -31,6 +31,7 @@ import android.nfc.INfcCardEmulation;
import android.nfc.INfcFCardEmulation;
import android.nfc.INfcOemExtensionCallback;
import android.nfc.INfcUnlockHandler;
+import android.nfc.IT4tNdefNfcee;
import android.nfc.ITagRemovedCallback;
import android.nfc.INfcDta;
import android.nfc.INfcWlcStateListener;
@@ -52,8 +53,8 @@ interface INfcAdapter
int getState();
boolean disable(boolean saveState, in String pkg);
boolean enable(in String pkg);
- void pausePolling(int timeoutInMs);
- void resumePolling();
+ int pausePolling(long timeoutInMs);
+ int resumePolling();
void setForegroundDispatch(in PendingIntent intent,
in IntentFilter[] filters, in TechListParcel techLists);
@@ -114,10 +115,14 @@ interface INfcAdapter
void clearPreference();
void setScreenState();
void checkFirmware();
- List<String> fetchActiveNfceeList();
+ Map fetchActiveNfceeList();
void triggerInitialization();
boolean getSettingStatus();
boolean isTagPresent();
List<Entry> getRoutingTableEntryList();
void indicateDataMigration(boolean inProgress, String pkg);
+ int commitRouting();
+ boolean isTagIntentAllowed(in String pkg, in int Userid);
+ IT4tNdefNfcee getT4tNdefNfceeInterface();
+ long getMaxPausePollingTimeoutMs();
}
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 5e2e92d958a4..bb9fe959dc06 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -47,12 +47,14 @@ interface INfcCardEmulation
boolean unsetPreferredService();
boolean supportsAidPrefixRegistration();
ApduServiceInfo getPreferredPaymentService(int userHandle);
- boolean setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
+ int setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
boolean isDefaultPaymentRegistered();
void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg);
void recoverRoutingTable(int userHandle);
boolean isEuiccSupported();
+ int getDefaultNfcSubscriptionId(in String pkg);
+ int setDefaultNfcSubscriptionId(int subscriptionId, in String pkg);
void setAutoChangeStatus(boolean state);
boolean isAutoChangeEnabled();
List<String> getRoutingStatus();
diff --git a/nfc/java/android/nfc/INfcEventListener.aidl b/nfc/java/android/nfc/INfcEventListener.aidl
index 5162c26ac536..774d8f875192 100644
--- a/nfc/java/android/nfc/INfcEventListener.aidl
+++ b/nfc/java/android/nfc/INfcEventListener.aidl
@@ -8,4 +8,9 @@ import android.nfc.ComponentNameAndUser;
oneway interface INfcEventListener {
void onPreferredServiceChanged(in ComponentNameAndUser ComponentNameAndUser);
void onObserveModeStateChanged(boolean isEnabled);
+ void onAidConflictOccurred(in String aid);
+ void onAidNotRouted(in String aid);
+ void onNfcStateChanged(in int nfcState);
+ void onRemoteFieldChanged(boolean isDetected);
+ void onInternalErrorReported(in int errorType);
} \ No newline at end of file
diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
index b102e873d737..e5eac0b4d6fd 100644
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -41,16 +41,19 @@ interface INfcOemExtensionCallback {
void onEnableFinished(int status);
void onDisableFinished(int status);
void onTagDispatch(in ResultReceiver isSkipped);
- void onRoutingChanged();
+ void onRoutingChanged(in ResultReceiver isSkipped);
void onHceEventReceived(int action);
void onReaderOptionChanged(boolean enabled);
void onCardEmulationActivated(boolean isActivated);
void onRfFieldActivated(boolean isActivated);
void onRfDiscoveryStarted(boolean isDiscoveryStarted);
void onEeListenActivated(boolean isActivated);
+ void onEeUpdated();
void onGetOemAppSearchIntent(in List<String> firstPackage, in ResultReceiver intentConsumer);
void onNdefMessage(in Tag tag, in NdefMessage message, in ResultReceiver hasOemExecutableContent);
void onLaunchHceAppChooserActivity(in String selectedAid, in List<ApduServiceInfo> services, in ComponentName failedComponent, in String category);
void onLaunchHceTapAgainActivity(in ApduServiceInfo service, in String category);
+ void onRoutingTableFull();
void onLogEventNotified(in OemLogItems item);
+ void onExtractOemPackages(in NdefMessage message, in ResultReceiver packageReceiver);
}
diff --git a/nfc/java/android/nfc/IT4tNdefNfcee.aidl b/nfc/java/android/nfc/IT4tNdefNfcee.aidl
new file mode 100644
index 000000000000..b4cda5b022fb
--- /dev/null
+++ b/nfc/java/android/nfc/IT4tNdefNfcee.aidl
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2024 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.nfc;
+
+import android.nfc.T4tNdefNfceeCcFileInfo;
+
+/**
+ * @hide
+ */
+interface IT4tNdefNfcee {
+ int writeData(in int fileId, in byte[] data);
+ byte[] readData(in int fileId);
+ int clearNdefData();
+ boolean isNdefOperationOngoing();
+ boolean isNdefNfceeEmulationSupported();
+ T4tNdefNfceeCcFileInfo readCcfile();
+}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index c5d8191b22e6..89ce4239cd4d 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -49,6 +49,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.io.IOException;
@@ -588,6 +589,7 @@ public final class NfcAdapter {
static INfcTag sTagService;
static INfcCardEmulation sCardEmulationService;
static INfcFCardEmulation sNfcFCardEmulationService;
+ static IT4tNdefNfcee sNdefNfceeService;
/**
* The NfcAdapter object for each application context.
@@ -826,7 +828,13 @@ public final class NfcAdapter {
throw new UnsupportedOperationException();
}
}
-
+ try {
+ sNdefNfceeService = sService.getT4tNdefNfceeInterface();
+ } catch (RemoteException e) {
+ sNdefNfceeService = null;
+ Log.e(TAG, "could not retrieve NDEF NFCEE service");
+ throw new UnsupportedOperationException();
+ }
sIsInitialized = true;
}
NfcAdapter adapter = sNfcAdapters.get(context);
@@ -2505,22 +2513,22 @@ public final class NfcAdapter {
}
/**
- * Checks if the device supports Tag application preference.
+ * Checks if the device supports Tag Intent App Preference functionality.
+ *
+ * When supported, {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
+ * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if
+ * {@link isTagIntentAllowed} returns {@code false}.
*
* @return {@code true} if the device supports Tag application preference, {@code false}
* otherwise
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable
- *
- * @hide
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
public boolean isTagIntentAppPreferenceSupported() {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
return callServiceReturn(() -> sService.isTagIntentAppPreferenceSupported(), false);
-
}
/**
@@ -2895,4 +2903,42 @@ public final class NfcAdapter {
}
return mNfcOemExtension;
}
+
+ /**
+ * Activity action: Bring up the settings page that allows the user to enable or disable tag
+ * intent reception for apps.
+ *
+ * <p>This will direct user to the settings page shows a list that asks users whether
+ * they want to allow or disallow the package to start an activity when a tag is discovered.
+ *
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
+ public static final String ACTION_CHANGE_TAG_INTENT_PREFERENCE =
+ "android.nfc.action.CHANGE_TAG_INTENT_PREFERENCE";
+
+ /**
+ * Checks whether the user has disabled the calling app from receiving NFC tag intents.
+ *
+ * <p>This method checks whether the caller package name is either not present in the user
+ * disabled list or is explicitly allowed by the user.
+ *
+ * @return {@code true} if an app is either not present in the list or is added to the list
+ * with the flag set to {@code true}. Otherwise, it returns {@code false}.
+ * It also returns {@code true} if {@link isTagIntentAppPreferenceSupported} returns
+ * {@code false}.
+ *
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ */
+ @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
+ public boolean isTagIntentAllowed() {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ if (!isTagIntentAppPreferenceSupported()) {
+ return true;
+ }
+ return callServiceReturn(() -> sService.isTagIntentAllowed(mContext.getPackageName(),
+ UserHandle.myUserId()), false);
+ }
}
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index abd99bc02f55..f78161e7cad0 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -23,11 +23,11 @@ import static android.nfc.cardemulation.CardEmulation.routeIntToString;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.DurationMillisLong;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
@@ -39,6 +39,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.se.omapi.Reader;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -148,6 +149,48 @@ public final class NfcOemExtension {
public @interface ControllerMode{}
/**
+ * Technology Type for {@link #getActiveNfceeList()}.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int NFCEE_TECH_NONE = 0;
+
+ /**
+ * Technology Type for {@link #getActiveNfceeList()}.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int NFCEE_TECH_A = 1;
+
+ /**
+ * Technology Type for {@link #getActiveNfceeList()}.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int NFCEE_TECH_B = 1 << 1;
+
+ /**
+ * Technology Type for {@link #getActiveNfceeList()}.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int NFCEE_TECH_F = 1 << 2;
+
+ /**
+ * Nfc technology flags for {@link #getActiveNfceeList()}.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, value = {
+ NFCEE_TECH_NONE,
+ NFCEE_TECH_A,
+ NFCEE_TECH_B,
+ NFCEE_TECH_F,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NfceeTechnology {}
+
+ /**
* Event that Host Card Emulation is activated.
*/
public static final int HCE_ACTIVATE = 1;
@@ -173,6 +216,31 @@ public final class NfcOemExtension {
public @interface HostCardEmulationAction {}
/**
+ * Status code returned when the polling state change request succeeded.
+ * @see #pausePolling()
+ * @see #resumePolling()
+ */
+ public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1;
+ /**
+ * Status code returned when the polling state change request is already in
+ * required state.
+ * @see #pausePolling()
+ * @see #resumePolling()
+ */
+ public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2;
+ /**
+ * Possible status codes for {@link #pausePolling()} and
+ * {@link #resumePolling()}.
+ * @hide
+ */
+ @IntDef(value = {
+ POLLING_STATE_CHANGE_SUCCEEDED,
+ POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PollingStateChangeStatusCode {}
+
+ /**
* Status OK
*/
public static final int STATUS_OK = 0;
@@ -194,6 +262,30 @@ public final class NfcOemExtension {
public @interface StatusCode {}
/**
+ * Routing commit succeeded.
+ */
+ public static final int COMMIT_ROUTING_STATUS_OK = 0;
+ /**
+ * Routing commit failed.
+ */
+ public static final int COMMIT_ROUTING_STATUS_FAILED = 3;
+ /**
+ * Routing commit failed due to the update is in progress.
+ */
+ public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6;
+
+ /**
+ * Status codes returned when calling {@link #forceRoutingTableCommit()}
+ * @hide
+ */
+ @IntDef(prefix = "COMMIT_ROUTING_STATUS_", value = {
+ COMMIT_ROUTING_STATUS_OK,
+ COMMIT_ROUTING_STATUS_FAILED,
+ COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CommitRoutingStatusCode {}
+ /**
* Interface for Oem extensions for NFC.
*/
public interface Callback {
@@ -233,8 +325,7 @@ public final class NfcOemExtension {
* {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
* false if NFC cannot be enabled at this time.
*/
- @SuppressLint("MethodNameTense")
- void onEnable(@NonNull Consumer<Boolean> isAllowed);
+ void onEnableRequested(@NonNull Consumer<Boolean> isAllowed);
/**
* Method to check if Nfc is allowed to be disabled by OEMs.
* @param isAllowed The {@link Consumer} to be completed. If disabling NFC is allowed,
@@ -242,7 +333,7 @@ public final class NfcOemExtension {
* {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
* false if NFC cannot be disabled at this time.
*/
- void onDisable(@NonNull Consumer<Boolean> isAllowed);
+ void onDisableRequested(@NonNull Consumer<Boolean> isAllowed);
/**
* Callback to indicate that Nfc starts to boot.
@@ -255,7 +346,7 @@ public final class NfcOemExtension {
void onEnableStarted();
/**
- * Callback to indicate that Nfc starts to enable.
+ * Callback to indicate that Nfc starts to disable.
*/
void onDisableStarted();
@@ -287,8 +378,12 @@ public final class NfcOemExtension {
/**
* Notifies routing configuration is changed.
+ * @param isCommitRoutingSkipped The {@link Consumer} to be
+ * completed. If routing commit should be skipped,
+ * the {@link Consumer#accept(Object)} should be called with
+ * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
*/
- void onRoutingChanged();
+ void onRoutingChanged(@NonNull Consumer<Boolean> isCommitRoutingSkipped);
/**
* API to activate start stop cpu boost on hce event.
@@ -340,6 +435,15 @@ public final class NfcOemExtension {
void onEeListenActivated(boolean isActivated);
/**
+ * Notifies that some NFCEE (NFC Execution Environment) has been updated.
+ *
+ * <p> This indicates that some applet has been installed/updated/removed in
+ * one of the NFCEE's.
+ * </p>
+ */
+ void onEeUpdated();
+
+ /**
* Gets the intent to find the OEM package in the OEM App market. If the consumer returns
* {@code null} or a timeout occurs, the intent from the first available package will be
* used instead.
@@ -394,10 +498,30 @@ public final class NfcOemExtension {
void onLaunchHceTapAgainDialog(@NonNull ApduServiceInfo service, @NonNull String category);
/**
+ * Callback to indicate that routing table is full and the OEM can optionally launch a
+ * dialog to request the user to remove some Card Emulation apps from the device to free
+ * routing table space.
+ */
+ void onRoutingTableFull();
+
+ /**
* Callback when OEM specified log event are notified.
* @param item the log items that contains log information of NFC event.
*/
void onLogEventNotified(@NonNull OemLogItems item);
+
+ /**
+ * Callback to to extract OEM defined packages from given NDEF message when
+ * a NFC tag is detected. These are used to handle NFC tags encoded with a
+ * proprietary format for storing app name (Android native app format).
+ *
+ * @param message NDEF message containing OEM package names
+ * @param packageConsumer The {@link Consumer} to be completed.
+ * The {@link Consumer#accept(Object)} should be called with
+ * the list of package names.
+ */
+ void onExtractOemPackages(@NonNull NdefMessage message,
+ @NonNull Consumer<List<String>> packageConsumer);
}
@@ -411,6 +535,28 @@ public final class NfcOemExtension {
}
/**
+ * Get an instance of {@link T4tNdefNfcee} object for performing T4T (Type-4 Tag)
+ * NDEF (NFC Data Exchange Format) NFCEE (NFC Execution Environment) operations.
+ * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
+ * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
+ * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ *
+ * This is a singleton object which shall be used by OEM extension module to do NDEF-NFCEE
+ * read/write operations.
+ *
+ * <p>Returns {@link T4tNdefNfcee}
+ * <p>Does not cause any RF activity and does not block.
+ * @return NFC Data Exchange Format (NDEF) NFC Execution Environment (NFCEE) object
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public T4tNdefNfcee getT4tNdefNfcee() {
+ return T4tNdefNfcee.getInstance();
+ }
+
+ /**
* Register an {@link Callback} to listen for NFC oem extension callbacks
* Multiple clients can register and callbacks will be invoked asynchronously.
*
@@ -524,14 +670,18 @@ public final class NfcOemExtension {
/**
* Get the Active NFCEE (NFC Execution Environment) List
*
- * @return List of activated secure elements on success
- * which can contain "eSE" and "UICC", otherwise empty list.
+ * @see Reader#getName() for the list of possible NFCEE names.
+ *
+ * @return Map< String, @NfceeTechnology Integer >
+ * A HashMap where keys are activated secure elements and
+ * the values are bitmap of technologies supported by each secure element
+ * on success keys can contain "eSE" and "UICC", otherwise empty map.
*/
@NonNull
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public List<String> getActiveNfceeList() {
+ public Map<String, Integer> getActiveNfceeList() {
return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sService.fetchActiveNfceeList(), new ArrayList<String>());
+ NfcAdapter.sService.fetchActiveNfceeList(), new HashMap<String, Integer>());
}
/**
@@ -597,24 +747,45 @@ public final class NfcOemExtension {
/**
* Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
- * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely
- * use {@link #resumePolling() to resume the polling.
- * @param timeoutInMs the pause polling duration in millisecond
+ * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely.
+ * Use {@link #resumePolling()} to resume the polling.
+ * Use {@link #getMaxPausePollingTimeoutMs()} to check the max timeout value.
+ * @param timeoutInMs the pause polling duration in millisecond.
+ * @return status of the operation
+ * @throws IllegalArgumentException if timeoutInMs value is invalid
+ * (0 < timeoutInMs < max).
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void pausePolling(int timeoutInMs) {
- NfcAdapter.callService(() -> NfcAdapter.sService.pausePolling(timeoutInMs));
+ public @PollingStateChangeStatusCode int pausePolling(@DurationMillisLong long timeoutInMs) {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sService.pausePolling(timeoutInMs),
+ POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
}
/**
* Resumes default NFC tag reader mode polling for the current device state if polling is
* paused. Calling this while already in polling is a no-op.
+ * @return status of the operation
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void resumePolling() {
- NfcAdapter.callService(() -> NfcAdapter.sService.resumePolling());
+ public @PollingStateChangeStatusCode int resumePolling() {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sService.resumePolling(),
+ POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
+ }
+
+ /**
+ * Gets the max pause polling timeout value in millisecond.
+ * @return long integer representing the max timeout
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @DurationMillisLong
+ public long getMaxPausePollingTimeoutMills() {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sService.getMaxPausePollingTimeoutMs(), 0L);
}
/**
@@ -734,6 +905,18 @@ public final class NfcOemExtension {
return result;
}
+ /**
+ * API to force a routing table commit.
+ * @return a {@link StatusCode} to indicate if commit routing succeeded or not
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @CommitRoutingStatusCode
+ public int forceRoutingTableCommit() {
+ return NfcAdapter.callServiceReturn(
+ () -> NfcAdapter.sService.commitRouting(), COMMIT_ROUTING_STATUS_FAILED);
+ }
+
private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
@Override
@@ -771,6 +954,12 @@ public final class NfcOemExtension {
}
@Override
+ public void onEeUpdated() throws RemoteException {
+ mCallbackMap.forEach((cb, ex) ->
+ handleVoidCallback(null, (Object input) -> cb.onEeUpdated(), ex));
+ }
+
+ @Override
public void onStateUpdated(int state) throws RemoteException {
mCallbackMap.forEach((cb, ex) ->
handleVoidCallback(state, cb::onStateUpdated, ex));
@@ -792,13 +981,13 @@ public final class NfcOemExtension {
public void onEnable(ResultReceiver isAllowed) throws RemoteException {
mCallbackMap.forEach((cb, ex) ->
handleVoidCallback(
- new ReceiverWrapper<>(isAllowed), cb::onEnable, ex));
+ new ReceiverWrapper<>(isAllowed), cb::onEnableRequested, ex));
}
@Override
public void onDisable(ResultReceiver isAllowed) throws RemoteException {
mCallbackMap.forEach((cb, ex) ->
handleVoidCallback(
- new ReceiverWrapper<>(isAllowed), cb::onDisable, ex));
+ new ReceiverWrapper<>(isAllowed), cb::onDisableRequested, ex));
}
@Override
public void onBootStarted() throws RemoteException {
@@ -837,9 +1026,10 @@ public final class NfcOemExtension {
new ReceiverWrapper<>(isSkipped), cb::onTagDispatch, ex));
}
@Override
- public void onRoutingChanged() throws RemoteException {
+ public void onRoutingChanged(ResultReceiver isSkipped) throws RemoteException {
mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(null, (Object input) -> cb.onRoutingChanged(), ex));
+ handleVoidCallback(
+ new ReceiverWrapper<>(isSkipped), cb::onRoutingChanged, ex));
}
@Override
public void onHceEventReceived(int action) throws RemoteException {
@@ -853,6 +1043,12 @@ public final class NfcOemExtension {
handleVoidCallback(enabled, cb::onReaderOptionChanged, ex));
}
+ public void onRoutingTableFull() throws RemoteException {
+ mCallbackMap.forEach((cb, ex) ->
+ handleVoidCallback(null,
+ (Object input) -> cb.onRoutingTableFull(), ex));
+ }
+
@Override
public void onGetOemAppSearchIntent(List<String> packages, ResultReceiver intentConsumer)
throws RemoteException {
@@ -912,6 +1108,15 @@ public final class NfcOemExtension {
handleVoidCallback(item, cb::onLogEventNotified, ex));
}
+ @Override
+ public void onExtractOemPackages(NdefMessage message, ResultReceiver packageConsumer)
+ throws RemoteException {
+ mCallbackMap.forEach((cb, ex) ->
+ handleVoid2ArgCallback(message,
+ new ReceiverWrapper<>(packageConsumer),
+ cb::onExtractOemPackages, ex));
+ }
+
private <T> void handleVoidCallback(
T input, Consumer<T> callbackMethod, Executor executor) {
synchronized (mLock) {
@@ -1022,8 +1227,14 @@ public final class NfcOemExtension {
Bundle bundle = new Bundle();
bundle.putParcelable("intent", (Intent) result);
mResultReceiver.send(0, bundle);
+ } else if (result instanceof List<?> list) {
+ if (list.stream().allMatch(String.class::isInstance)) {
+ Bundle bundle = new Bundle();
+ bundle.putStringArray("packageNames",
+ list.stream().map(pkg -> (String) pkg).toArray(String[]::new));
+ mResultReceiver.send(0, bundle);
+ }
}
-
}
@Override
diff --git a/nfc/java/android/nfc/NfcRoutingTableEntry.java b/nfc/java/android/nfc/NfcRoutingTableEntry.java
index 4e913776a030..c2cbbede9b75 100644
--- a/nfc/java/android/nfc/NfcRoutingTableEntry.java
+++ b/nfc/java/android/nfc/NfcRoutingTableEntry.java
@@ -17,8 +17,12 @@ package android.nfc;
import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Class to represent an entry of routing table. This class is abstract and extended by
* {@link RoutingTableTechnologyEntry}, {@link RoutingTableProtocolEntry},
@@ -30,10 +34,42 @@ import android.annotation.SystemApi;
@SystemApi
public abstract class NfcRoutingTableEntry {
private final int mNfceeId;
+ private final int mType;
+
+ /**
+ * AID routing table type.
+ */
+ public static final int TYPE_AID = 0;
+ /**
+ * Protocol routing table type.
+ */
+ public static final int TYPE_PROTOCOL = 1;
+ /**
+ * Technology routing table type.
+ */
+ public static final int TYPE_TECHNOLOGY = 2;
+ /**
+ * System Code routing table type.
+ */
+ public static final int TYPE_SYSTEM_CODE = 3;
+
+ /**
+ * Possible type of this routing table entry.
+ * @hide
+ */
+ @IntDef(prefix = "TYPE_", value = {
+ TYPE_AID,
+ TYPE_PROTOCOL,
+ TYPE_TECHNOLOGY,
+ TYPE_SYSTEM_CODE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RoutingTableType {}
/** @hide */
- protected NfcRoutingTableEntry(int nfceeId) {
+ protected NfcRoutingTableEntry(int nfceeId, @RoutingTableType int type) {
mNfceeId = nfceeId;
+ mType = type;
}
/**
@@ -43,4 +79,13 @@ public abstract class NfcRoutingTableEntry {
public int getNfceeId() {
return mNfceeId;
}
+
+ /**
+ * Get the type of this entry.
+ * @return an integer defined in {@link RoutingTableType}
+ */
+ @RoutingTableType
+ public int getType() {
+ return mType;
+ }
}
diff --git a/nfc/java/android/nfc/OemLogItems.java b/nfc/java/android/nfc/OemLogItems.java
index 6671941c1cc9..4f3e1999f5d3 100644
--- a/nfc/java/android/nfc/OemLogItems.java
+++ b/nfc/java/android/nfc/OemLogItems.java
@@ -142,8 +142,11 @@ public final class OemLogItems implements Parcelable {
dest.writeByteArray(mCommandApdus);
dest.writeInt(mResponseApdus.length);
dest.writeByteArray(mResponseApdus);
- dest.writeLong(mRfFieldOnTime.getEpochSecond());
- dest.writeInt(mRfFieldOnTime.getNano());
+ dest.writeBoolean(mRfFieldOnTime != null);
+ if (mRfFieldOnTime != null) {
+ dest.writeLong(mRfFieldOnTime.getEpochSecond());
+ dest.writeInt(mRfFieldOnTime.getNano());
+ }
dest.writeParcelable(mTag, 0);
}
@@ -305,7 +308,12 @@ public final class OemLogItems implements Parcelable {
in.readByteArray(this.mCommandApdus);
this.mResponseApdus = new byte[in.readInt()];
in.readByteArray(this.mResponseApdus);
- this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());
+ boolean isRfFieldOnTimeSet = in.readBoolean();
+ if (isRfFieldOnTimeSet) {
+ this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());
+ } else {
+ this.mRfFieldOnTime = null;
+ }
this.mTag = in.readParcelable(Tag.class.getClassLoader(), Tag.class);
}
diff --git a/nfc/java/android/nfc/RoutingTableAidEntry.java b/nfc/java/android/nfc/RoutingTableAidEntry.java
index 7634fe342ab9..bf697d662bd6 100644
--- a/nfc/java/android/nfc/RoutingTableAidEntry.java
+++ b/nfc/java/android/nfc/RoutingTableAidEntry.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.SystemApi;
/**
- * Represents an AID entry in current routing table.
+ * Represents an Application ID (AID) entry in current routing table.
* @hide
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@@ -30,7 +30,7 @@ public class RoutingTableAidEntry extends NfcRoutingTableEntry {
/** @hide */
public RoutingTableAidEntry(int nfceeId, String value) {
- super(nfceeId);
+ super(nfceeId, TYPE_AID);
this.mValue = value;
}
diff --git a/nfc/java/android/nfc/RoutingTableProtocolEntry.java b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
index 0c5be7dd9d97..536de4d7430e 100644
--- a/nfc/java/android/nfc/RoutingTableProtocolEntry.java
+++ b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
@@ -97,7 +97,7 @@ public class RoutingTableProtocolEntry extends NfcRoutingTableEntry {
/** @hide */
public RoutingTableProtocolEntry(int nfceeId, @ProtocolValue int value) {
- super(nfceeId);
+ super(nfceeId, TYPE_PROTOCOL);
this.mValue = value;
}
diff --git a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
index f87ad5f95195..f61892d31668 100644
--- a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
+++ b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
@@ -20,7 +20,9 @@ import android.annotation.NonNull;
import android.annotation.SystemApi;
/**
- * Represents a system code entry in current routing table.
+ * Represents a system code entry in current routing table, where system codes are two-byte values
+ * used in NFC-F technology (a type of NFC communication) to identify specific
+ * device configurations.
* @hide
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@@ -30,7 +32,7 @@ public class RoutingTableSystemCodeEntry extends NfcRoutingTableEntry {
/** @hide */
public RoutingTableSystemCodeEntry(int nfceeId, byte[] value) {
- super(nfceeId);
+ super(nfceeId, TYPE_SYSTEM_CODE);
this.mValue = value;
}
diff --git a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
index f51a5299be11..2dbc94232b0b 100644
--- a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
+++ b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
@@ -30,22 +30,27 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
public class RoutingTableTechnologyEntry extends NfcRoutingTableEntry {
/**
- * Technology-A
+ * Technology-A.
+ * <p>Tech-A is mostly used for payment and ticketing applications. It supports various
+ * Tag platforms including Type 1, Type 2 and Type 4A tags. </p>
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
public static final int TECHNOLOGY_A = 0;
/**
- * Technology-B
+ * Technology-B which is based on ISO/IEC 14443-3 standard.
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
public static final int TECHNOLOGY_B = 1;
/**
- * Technology-F
+ * Technology-F.
+ * <p>Tech-F is a standard which supports Type 3 Tags and NFC-DEP protocol etc.</p>
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
public static final int TECHNOLOGY_F = 2;
/**
- * Technology-V
+ * Technology-V.
+ * <p>Tech-V is an NFC technology used for communication with passive tags that operate
+ * at a longer range than other NFC technologies. </p>
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
public static final int TECHNOLOGY_V = 3;
@@ -73,7 +78,7 @@ public class RoutingTableTechnologyEntry extends NfcRoutingTableEntry {
/** @hide */
public RoutingTableTechnologyEntry(int nfceeId, @TechnologyValue int value) {
- super(nfceeId);
+ super(nfceeId, TYPE_TECHNOLOGY);
this.mValue = value;
}
diff --git a/nfc/java/android/nfc/T4tNdefNfcee.java b/nfc/java/android/nfc/T4tNdefNfcee.java
new file mode 100644
index 000000000000..06d02c54eb2e
--- /dev/null
+++ b/nfc/java/android/nfc/T4tNdefNfcee.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2024 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.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class is used for performing T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
+ * NFCEE (NFC Execution Environment) operations.
+ * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
+ * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
+ * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class T4tNdefNfcee {
+ private static final String TAG = "NdefNfcee";
+ static T4tNdefNfcee sNdefNfcee;
+
+ private T4tNdefNfcee() {
+ }
+
+ /**
+ * Helper to get an instance of this class.
+ *
+ * @return
+ * @hide
+ */
+ @NonNull
+ public static T4tNdefNfcee getInstance() {
+ if (sNdefNfcee == null) {
+ sNdefNfcee = new T4tNdefNfcee();
+ }
+ return sNdefNfcee;
+ }
+
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data is successful.
+ */
+ public static final int WRITE_DATA_SUCCESS = 0;
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data fail due to unknown reasons.
+ */
+ public static final int WRITE_DATA_ERROR_INTERNAL = -1;
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data fail due to ongoing rf activity.
+ */
+ public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2;
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data fail due to Nfc off.
+ */
+ public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3;
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data fail due to invalid file id.
+ */
+ public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4;
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data fail due to invalid length.
+ */
+ public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5;
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data fail due to core connection create failure.
+ */
+ public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6;
+ /**
+ * Return flag for {@link #writeData(int, byte[])}.
+ * It indicates write data fail due to empty payload.
+ */
+ public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7;
+ /**
+ * Returns flag for {@link #writeData(int, byte[])}.
+ * It idicates write data fail due to invalid ndef format.
+ */
+ public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8;
+
+ /**
+ * Possible return values for {@link #writeData(int, byte[])}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "WRITE_DATA_" }, value = {
+ WRITE_DATA_SUCCESS,
+ WRITE_DATA_ERROR_INTERNAL,
+ WRITE_DATA_ERROR_RF_ACTIVATED,
+ WRITE_DATA_ERROR_NFC_NOT_ON,
+ WRITE_DATA_ERROR_INVALID_FILE_ID,
+ WRITE_DATA_ERROR_INVALID_LENGTH,
+ WRITE_DATA_ERROR_CONNECTION_FAILED,
+ WRITE_DATA_ERROR_EMPTY_PAYLOAD,
+ WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WriteDataStatus{}
+
+ /**
+ * This API performs writes of T4T data to NFCEE.
+ *
+ * <p>This is an I/O operation and will block until complete. It must
+ * not be called from the main application thread.</p>
+ *
+ * @param fileId File id (Refer NFC Forum Type 4 Tag Specification
+ * Section 4.2 File Identifiers and Access Conditions
+ * for more information) to which to write.
+ * @param data This should be valid Ndef Message format.
+ * Refer to Nfc forum NDEF specification NDEF Message section
+ * @return status of the operation.
+ * @hide
+ */
+ @SystemApi
+ @WorkerThread
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @WriteDataStatus int writeData(@IntRange(from = 0, to = 65535) int fileId,
+ @NonNull byte[] data) {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sNdefNfceeService.writeData(fileId, data), WRITE_DATA_ERROR_INTERNAL);
+ }
+
+ /**
+ * This API performs reading of T4T content of Nfcee.
+ *
+ * <p>This is an I/O operation and will block until complete. It must
+ * not be called from the main application thread.</p>
+ *
+ * @param fileId File Id (Refer
+ * Section 4.2 File Identifiers and Access Conditions
+ * for more information) from which to read.
+ * @return - Returns Ndef message if success
+ * Refer to Nfc forum NDEF specification NDEF Message section
+ * @throws IllegalStateException if read fails because the fileId is invalid.
+ * @hide
+ */
+ @SystemApi
+ @WorkerThread
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public byte[] readData(@IntRange(from = 0, to = 65535) int fileId) {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sNdefNfceeService.readData(fileId), null);
+ }
+
+ /**
+ * Return flag for {@link #clearNdefData()}.
+ * It indicates clear data is successful.
+ */
+ public static final int CLEAR_DATA_SUCCESS = 1;
+ /**
+ * Return flag for {@link #clearNdefData()}.
+ * It indicates clear data failed due to internal error while processing the clear.
+ */
+ public static final int CLEAR_DATA_FAILED_INTERNAL = 0;
+
+ /**
+ * Possible return values for {@link #clearNdefData()}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "CLEAR_DATA_" }, value = {
+ CLEAR_DATA_SUCCESS,
+ CLEAR_DATA_FAILED_INTERNAL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ClearDataStatus{}
+
+ /**
+ * This API will set all the T4T NDEF NFCEE data to zero.
+ *
+ * <p>This is an I/O operation and will block until complete. It must
+ * not be called from the main application thread.
+ *
+ * <p>This API can be called regardless of NDEF file lock state.
+ * </p>
+ * @return status of the operation
+ *
+ * @hide
+ */
+ @SystemApi
+ @WorkerThread
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @ClearDataStatus int clearData() {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sNdefNfceeService.clearNdefData(), CLEAR_DATA_FAILED_INTERNAL);
+ }
+
+ /**
+ * Returns whether NDEF NFCEE operation is ongoing or not.
+ *
+ * @return true if NDEF NFCEE operation is ongoing, else false.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public boolean isOperationOngoing() {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sNdefNfceeService.isNdefOperationOngoing(), false);
+ }
+
+ /**
+ * This Api is to check the status of NDEF NFCEE emulation feature is
+ * supported or not.
+ *
+ * @return true if NDEF NFCEE emulation feature is supported, else false.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public boolean isSupported() {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sNdefNfceeService.isNdefNfceeEmulationSupported(), false);
+ }
+
+ /**
+ * This API performs reading of T4T NDEF NFCEE CC file content.
+ *
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+ *
+ * @return Returns CC file content if success or null if failed to read.
+ * @hide
+ */
+ @SystemApi
+ @WorkerThread
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @Nullable
+ public T4tNdefNfceeCcFileInfo readCcfile() {
+ return NfcAdapter.callServiceReturn(() ->
+ NfcAdapter.sNdefNfceeService.readCcfile(), null);
+ }
+}
diff --git a/core/java/android/security/forensic/ForensicEvent.aidl b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
index a321fb0cb939..f72f74e8b3b9 100644
--- a/core/java/android/security/forensic/ForensicEvent.aidl
+++ b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.security.forensic;
+package android.nfc;
+
+parcelable T4tNdefNfceeCcFileInfo;
-/** {@hide} */
-parcelable ForensicEvent;
diff --git a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
new file mode 100644
index 000000000000..5fca0529124e
--- /dev/null
+++ b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2024 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.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class is used to represence T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
+ * NFCEE (NFC Execution Environment) CC (Capability Container) File data.
+ * The CC file stores metadata about the T4T tag being emulated.
+ *
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class T4tNdefNfceeCcFileInfo implements Parcelable {
+ /**
+ * Indicates the size of this capability container (called “CC File”)<p>
+ */
+ private int mCcLength;
+ /**
+ * Indicates the mapping specification version<p>
+ */
+ private int mVersion;
+ /**
+ * Indicates the max data size by a single ReadBinary<p>
+ */
+ private int mMaxReadLength;
+ /**
+ * Indicates the max data size by a single UpdateBinary<p>
+ */
+ private int mMaxWriteLength;
+ /**
+ * Indicates the NDEF File Identifier<p>
+ */
+ private int mFileId;
+ /**
+ * Indicates the maximum Max NDEF file size<p>
+ */
+ private int mMaxSize;
+ /**
+ * Indicates the read access condition<p>
+ */
+ private int mReadAccess;
+ /**
+ * Indicates the write access condition<p>
+ */
+ private int mWriteAccess;
+
+ /**
+ * Constructor to be used by NFC service and internal classes.
+ * @hide
+ */
+ public T4tNdefNfceeCcFileInfo(int cclen, int version, int maxLe, int maxLc,
+ int ndefFileId, int ndefMaxSize,
+ int ndefReadAccess, int ndefWriteAccess) {
+ mCcLength = cclen;
+ mVersion = version;
+ mMaxWriteLength = maxLc;
+ mMaxReadLength = maxLe;
+ mFileId = ndefFileId;
+ mMaxSize = ndefMaxSize;
+ mReadAccess = ndefReadAccess;
+ mWriteAccess = ndefWriteAccess;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+
+ dest.writeInt(mCcLength);
+ dest.writeInt(mVersion);
+ dest.writeInt(mMaxWriteLength);
+ dest.writeInt(mMaxReadLength);
+ dest.writeInt(mFileId);
+ dest.writeInt(mMaxSize);
+ dest.writeInt(mReadAccess);
+ dest.writeInt(mWriteAccess);
+ }
+
+ /**
+ * Indicates the size of this capability container (called “CC File”).
+ *
+ * @return length of the CC file.
+ */
+ @IntRange(from = 0xf, to = 0x7fff)
+ public int getCcFileLength() {
+ return mCcLength;
+ }
+
+ /**
+ * T4T tag mapping version 2.0.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+ */
+ public static final int VERSION_2_0 = 0x20;
+ /**
+ * T4T tag mapping version 2.0.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+ */
+ public static final int VERSION_3_0 = 0x30;
+
+ /**
+ * Possible return values for {@link #getVersion()}.
+ * @hide
+ */
+ @IntDef(prefix = { "VERSION_" }, value = {
+ VERSION_2_0,
+ VERSION_3_0,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Version{}
+
+ /**
+ * Indicates the mapping version of the T4T tag supported.
+ *
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.5" for more details.
+ *
+ * @return version of the specification
+ */
+ @Version
+ public int getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Indicates the max data size that can be read by a single invocation of
+ * {@link T4tNdefNfcee#readData(int)}.
+ *
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLe.
+ * @return max size of read (in bytes).
+ */
+ @IntRange(from = 0xf, to = 0xffff)
+ public int getMaxReadLength() {
+ return mMaxReadLength;
+ }
+
+ /**
+ * Indicates the max data size that can be written by a single invocation of
+ * {@link T4tNdefNfcee#writeData(int, byte[])}
+ *
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLc.
+ * @return max size of write (in bytes).
+ */
+ @IntRange(from = 0xd, to = 0xffff)
+ public int getMaxWriteLength() {
+ return mMaxWriteLength;
+ }
+
+ /**
+ * Indicates the NDEF File Identifier. This is the identifier used in the last invocation of
+ * {@link T4tNdefNfcee#writeData(int, byte[])}
+ *
+ * @return FileId of the data stored or -1 if no data is present.
+ */
+ @IntRange(from = -1, to = 65535)
+ public int getFileId() {
+ return mFileId;
+ }
+
+ /**
+ * Indicates the maximum size of T4T NDEF data that can be written to the NFCEE.
+ *
+ * @return max size of the contents.
+ */
+ @IntRange(from = 0x5, to = 0x7fff)
+ public int getMaxSize() {
+ return mMaxSize;
+ }
+
+ /**
+ * T4T tag read access granted without any security.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ */
+ public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0x0;
+ /**
+ * T4T tag read access granted with limited proprietary access only.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ */
+ public static final int READ_ACCESS_GRANTED_RESTRICTED = 0x80;
+
+ /**
+ * Possible return values for {@link #getVersion()}.
+ * @hide
+ */
+ @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = {
+ READ_ACCESS_GRANTED_RESTRICTED,
+ READ_ACCESS_GRANTED_UNRESTRICTED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReadAccess {}
+
+ /**
+ * Indicates the read access condition.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ * @return read access restriction
+ */
+ @ReadAccess
+ public int getReadAccess() {
+ return mReadAccess;
+ }
+
+ /**
+ * T4T tag write access granted without any security.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ */
+ public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0x0;
+ /**
+ * T4T tag write access granted with limited proprietary access only.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ */
+ public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 0x80;
+ /**
+ * T4T tag write access not granted.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ */
+ public static final int WRITE_ACCESS_NOT_GRANTED = 0xFF;
+
+ /**
+ * Possible return values for {@link #getVersion()}.
+ * @hide
+ */
+ @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = {
+ WRITE_ACCESS_GRANTED_RESTRICTED,
+ WRITE_ACCESS_GRANTED_UNRESTRICTED,
+ WRITE_ACCESS_NOT_GRANTED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WriteAccess {}
+
+ /**
+ * Indicates the write access condition.
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ * @return write access restriction
+ */
+ @WriteAccess
+ public int getWriteAccess() {
+ return mWriteAccess;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Parcelable.Creator<T4tNdefNfceeCcFileInfo> CREATOR =
+ new Parcelable.Creator<>() {
+ @Override
+ public T4tNdefNfceeCcFileInfo createFromParcel(Parcel in) {
+
+ // NdefNfceeCcFileInfo fields
+ int cclen = in.readInt();
+ int version = in.readInt();
+ int maxLe = in.readInt();
+ int maxLc = in.readInt();
+ int ndefFileId = in.readInt();
+ int ndefMaxSize = in.readInt();
+ int ndefReadAccess = in.readInt();
+ int ndefWriteAccess = in.readInt();
+
+ return new T4tNdefNfceeCcFileInfo(cclen, version, maxLe, maxLc,
+ ndefFileId, ndefMaxSize,
+ ndefReadAccess, ndefWriteAccess);
+ }
+
+ @Override
+ public T4tNdefNfceeCcFileInfo[] newArray(int size) {
+ return new T4tNdefNfceeCcFileInfo[size];
+ }
+ };
+}
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 9ff83fe77c9b..308b5d1831a6 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -171,6 +171,12 @@ public final class ApduServiceInfo implements Parcelable {
private boolean mShouldDefaultToObserveMode;
/**
+ * Whether or not this service wants to share the same routing priority as the
+ * Wallet role owner.
+ */
+ private boolean mShareRolePriority;
+
+ /**
* @hide
*/
@UnsupportedAppUsage
@@ -307,6 +313,12 @@ public final class ApduServiceInfo implements Parcelable {
mShouldDefaultToObserveMode = sa.getBoolean(
R.styleable.HostApduService_shouldDefaultToObserveMode,
false);
+ if (Flags.nfcAssociatedRoleServices()) {
+ mShareRolePriority = sa.getBoolean(
+ R.styleable.HostApduService_shareRolePriority,
+ false
+ );
+ }
sa.recycle();
} else {
TypedArray sa = res.obtainAttributes(attrs,
@@ -337,6 +349,12 @@ public final class ApduServiceInfo implements Parcelable {
}
}
mStaticOffHostName = mOffHostName;
+ if (Flags.nfcAssociatedRoleServices()) {
+ mShareRolePriority = sa.getBoolean(
+ R.styleable.OffHostApduService_shareRolePriority,
+ false
+ );
+ }
sa.recycle();
}
@@ -728,6 +746,17 @@ public final class ApduServiceInfo implements Parcelable {
}
/**
+ * Returns whether or not this service wants to share the Wallet role holder priority
+ * with other packages/services with the same signature.
+ *
+ * @return whether or not this service wants to share priority
+ */
+ @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES)
+ public boolean shareRolePriority() {
+ return mShareRolePriority;
+ }
+
+ /**
* Returns description of service.
* @return user readable description of service
*/
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index eb28c3b9c930..803770218299 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -22,6 +22,7 @@ import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -45,6 +46,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
import android.util.Log;
@@ -185,6 +187,84 @@ public final class CardEmulation {
@FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET = -1;
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * succeeded.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_OK = 0;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to the unsupported feature.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to the invalid service.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to the service is already set to the requested status.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to unknown error.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4;
+
+ /**
+ * Status code returned by {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * @hide
+ */
+ @IntDef(prefix = "SET_SERVICE_ENABLED_STATUS_", value = {
+ SET_SERVICE_ENABLED_STATUS_OK,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SetServiceEnabledStatusCode {}
+
+ /**
+ * Property name used to indicate that an application wants to allow associated services
+ * to share the same AID routing priority when this application is the role holder.
+ * <p>
+ * Example:
+ * <pre>
+ * {@code
+ * <application>
+ * ...
+ * <property android:name="android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY"
+ * android:value="true"/>
+ * </application>
+ * }
+ * </pre>
+ */
+ @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES)
+ public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY =
+ "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
+
static boolean sIsInitialized = false;
static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
static INfcCardEmulation sService;
@@ -883,22 +963,24 @@ public final class CardEmulation {
}
/**
- * Allows to set or unset preferred service (category other) to avoid AID Collision.
+ * Allows to set or unset preferred service (category other) to avoid AID Collision. The user
+ * should use corresponding context using {@link Context#createContextAsUser(UserHandle, int)}
*
* @param service The ComponentName of the service
* @param status true to enable, false to disable
- * @param userId the user handle of the user whose information is being requested.
- * @return set service for the category and true if service is already set return false.
+ * @return status code defined in {@link SetServiceEnabledStatusCode}
*
* @hide
*/
- public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status,
- int userId) {
- if (service == null) {
- throw new NullPointerException("activity or service or category is null");
- }
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @SetServiceEnabledStatusCode
+ public int setServiceEnabledForCategoryOther(@NonNull ComponentName service,
+ boolean status) {
return callServiceReturn(() ->
- sService.setServiceEnabledForCategoryOther(userId, service, status), false);
+ sService.setServiceEnabledForCategoryOther(mContext.getUser().getIdentifier(),
+ service, status), SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR);
}
/** @hide */
@@ -949,6 +1031,7 @@ public final class CardEmulation {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
@FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
public void overrideRoutingTable(
@NonNull Activity activity, @ProtocolAndTechnologyRoute int protocol,
@@ -976,6 +1059,7 @@ public final class CardEmulation {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
@FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
public void recoverRoutingTable(@NonNull Activity activity) {
if (!activity.isResumed()) {
@@ -997,6 +1081,97 @@ public final class CardEmulation {
}
/**
+ * Setting the default subscription ID succeeded.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+ public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0;
+
+ /**
+ * Setting the default subscription ID failed because the subscription ID is invalid.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+ public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1;
+
+ /**
+ * Setting the default subscription ID failed because there was an internal error processing
+ * the request. For ex: NFC service died in the middle of handling the API.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+ public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR = 2;
+
+ /**
+ * Setting the default subscription ID failed because this feature is not supported on the
+ * device.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+ public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3;
+
+ /** @hide */
+ @IntDef(prefix = "SET_SUBSCRIPTION_ID_STATUS_",
+ value = {
+ SET_SUBSCRIPTION_ID_STATUS_SUCCESS,
+ SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID,
+ SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR,
+ SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SetSubscriptionIdStatus {}
+
+ /**
+ * Sets the system's default NFC subscription id.
+ *
+ * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this sets the
+ * default UICC NFCEE that will handle NFC offhost CE transactoions </p>
+ *
+ * @param subscriptionId the default NFC subscription Id to set.
+ * @return status of the operation.
+ *
+ * @throws UnsupportedOperationException If the device does not have
+ * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+ public @SetSubscriptionIdStatus int setDefaultNfcSubscriptionId(int subscriptionId) {
+ return callServiceReturn(() ->
+ sService.setDefaultNfcSubscriptionId(
+ subscriptionId, mContext.getPackageName()),
+ SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR);
+ }
+
+ /**
+ * Returns the system's default NFC subscription id.
+ *
+ * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this returns the
+ * default UICC NFCEE that will handle NFC offhost CE transactoions </p>
+ * <p> If the device has no UICC that can serve as NFCEE, this will return
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.</p>
+ *
+ * @return the default NFC subscription Id if set,
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} otherwise.
+ *
+ * @throws UnsupportedOperationException If the device does not have
+ * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+ */
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+ @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+ public int getDefaultNfcSubscriptionId() {
+ return callServiceReturn(() ->
+ sService.getDefaultNfcSubscriptionId(mContext.getPackageName()),
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
+
+ /**
* Returns the value of {@link Settings.Secure#NFC_PAYMENT_DEFAULT_COMPONENT}.
*
* @param context A context
@@ -1083,6 +1258,40 @@ public final class CardEmulation {
};
}
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ public static final int NFC_INTERNAL_ERROR_UNKNOWN = 0;
+
+ /**
+ * This error is reported when the NFC command watchdog restarts the NFC stack.
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ public static final int NFC_INTERNAL_ERROR_NFC_CRASH_RESTART = 1;
+
+ /**
+ * This error is reported when the NFC controller does not respond or there's an NCI transport
+ * error.
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ public static final int NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR = 2;
+
+ /**
+ * This error is reported when the NFC stack times out while waiting for a response to a command
+ * sent to the NFC hardware.
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ public static final int NFC_INTERNAL_ERROR_COMMAND_TIMEOUT = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ @IntDef(prefix = "NFC_INTERNAL_ERROR_", value = {
+ NFC_INTERNAL_ERROR_UNKNOWN,
+ NFC_INTERNAL_ERROR_NFC_CRASH_RESTART,
+ NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR,
+ NFC_INTERNAL_ERROR_COMMAND_TIMEOUT,
+ })
+ public @interface NfcInternalErrorType {}
+
/** Listener for preferred service state changes. */
@FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
public interface NfcEventListener {
@@ -1105,6 +1314,57 @@ public final class CardEmulation {
*/
@FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
default void onObserveModeStateChanged(boolean isEnabled) {}
+
+ /**
+ * This method is called when an AID conflict is detected during an NFC transaction. This
+ * can happen when multiple services are registered for the same AID.
+ *
+ * @param aid The AID that is in conflict
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ default void onAidConflictOccurred(@NonNull String aid) {}
+
+ /**
+ * This method is called when an AID is not routed to any service during an NFC
+ * transaction. This can happen when no service is registered for the given AID.
+ *
+ * @param aid the AID that was not routed
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ default void onAidNotRouted(@NonNull String aid) {}
+
+ /**
+ * This method is called when the NFC state changes.
+ *
+ * @see NfcAdapter#getAdapterState()
+ *
+ * @param state The new NFC state
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ default void onNfcStateChanged(@NfcAdapter.AdapterState int state) {}
+ /**
+ * This method is called when the NFC controller is in card emulation mode and an NFC
+ * reader's field is either detected or lost.
+ *
+ * @param isDetected true if an NFC reader is detected, false if it is lost
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ default void onRemoteFieldChanged(boolean isDetected) {}
+
+ /**
+ * This method is called when an internal error is reported by the NFC stack.
+ *
+ * No action is required in response to these events as the NFC stack will automatically
+ * attempt to recover. These errors are reported for informational purposes only.
+ *
+ * Note that these errors can be reported when performing various internal NFC operations
+ * (such as during device shutdown) and cannot always be explicitly correlated with NFC
+ * transaction failures.
+ *
+ * @param errorType The type of the internal error
+ */
+ @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+ default void onInternalErrorReported(@NfcInternalErrorType int errorType) {}
}
private final ArrayMap<NfcEventListener, Executor> mNfcEventListeners = new ArrayMap<>();
@@ -1124,25 +1384,61 @@ public final class CardEmulation {
mContext.getPackageName(),
componentNameAndUser.getComponentName()
.getPackageName());
- synchronized (mNfcEventListeners) {
- mNfcEventListeners.forEach(
- (listener, executor) -> {
- executor.execute(
- () -> listener.onPreferredServiceChanged(isPreferred));
- });
- }
+ callListeners(listener -> listener.onPreferredServiceChanged(isPreferred));
}
public void onObserveModeStateChanged(boolean isEnabled) {
if (!android.nfc.Flags.nfcEventListener()) {
return;
}
+ callListeners(listener -> listener.onObserveModeStateChanged(isEnabled));
+ }
+
+ public void onAidConflictOccurred(String aid) {
+ if (!android.nfc.Flags.nfcEventListener()) {
+ return;
+ }
+ callListeners(listener -> listener.onAidConflictOccurred(aid));
+ }
+
+ public void onAidNotRouted(String aid) {
+ if (!android.nfc.Flags.nfcEventListener()) {
+ return;
+ }
+ callListeners(listener -> listener.onAidNotRouted(aid));
+ }
+
+ public void onNfcStateChanged(int state) {
+ if (!android.nfc.Flags.nfcEventListener()) {
+ return;
+ }
+ callListeners(listener -> listener.onNfcStateChanged(state));
+ }
+
+ public void onRemoteFieldChanged(boolean isDetected) {
+ if (!android.nfc.Flags.nfcEventListener()) {
+ return;
+ }
+ callListeners(listener -> listener.onRemoteFieldChanged(isDetected));
+ }
+
+ public void onInternalErrorReported(@NfcInternalErrorType int errorType) {
+ if (!android.nfc.Flags.nfcEventListener()) {
+ return;
+ }
+ callListeners(listener -> listener.onInternalErrorReported(errorType));
+ }
+
+ interface ListenerCall {
+ void invoke(NfcEventListener listener);
+ }
+
+ private void callListeners(ListenerCall listenerCall) {
synchronized (mNfcEventListeners) {
mNfcEventListeners.forEach(
- (listener, executor) -> {
- executor.execute(
- () -> listener.onObserveModeStateChanged(isEnabled));
- });
+ (listener, executor) -> {
+ executor.execute(() -> listenerCall.invoke(listener));
+ });
}
}
};
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 34f020012d3c..ee287aba709f 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -173,3 +173,19 @@ flag {
description: "Share wallet role routing priority with associated services"
bug: "366243361"
}
+
+flag {
+ name: "nfc_set_service_enabled_for_category_other"
+ is_exported: true
+ namespace: "nfc"
+ description: "Enable set service enabled for category other"
+ bug: "338157113"
+}
+
+flag {
+ name: "nfc_check_tag_intent_preference"
+ is_exported: true
+ namespace: "nfc"
+ description: "App can check its tag intent preference status"
+ bug: "335916336"
+}
diff --git a/packages/BackupRestoreConfirmation/Android.bp b/packages/BackupRestoreConfirmation/Android.bp
index ad3f4c12dfb1..a7d16a1cb0d0 100644
--- a/packages/BackupRestoreConfirmation/Android.bp
+++ b/packages/BackupRestoreConfirmation/Android.bp
@@ -27,6 +27,7 @@ android_app {
name: "BackupRestoreConfirmation",
defaults: ["platform_app_defaults"],
srcs: ["src/**/*.java"],
+ static_libs: ["androidx.core_core"],
platform_apis: true,
certificate: "platform",
privileged: true,
diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml
index 44aa1b1b8747..fee46576d588 100644
--- a/packages/BackupRestoreConfirmation/AndroidManifest.xml
+++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml
@@ -27,7 +27,6 @@
android:permission="android.permission.CONFIRM_FULL_BACKUP" >
<activity android:name=".BackupRestoreConfirmation"
- android:theme="@style/OptOutEdgeToEdgeEnforcement"
android:title=""
android:windowSoftInputMode="stateAlwaysHidden"
android:excludeFromRecents="true"
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
index 6504435fada3..16e4706e6bb0 100644
--- a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
@@ -24,6 +24,7 @@
android:orientation="vertical" >
<ScrollView
+ android:id="@+id/scroll_view"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
@@ -84,11 +85,11 @@
android:layout_width="match_parent" />
<!-- button bar -->
- <LinearLayout android:orientation="horizontal"
- style="?android:attr/buttonBarStyle"
+ <LinearLayout android:id="@+id/button_bar"
+ android:orientation="horizontal"
+ style="?android:attr/buttonBarStyle"
android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:layout_gravity="bottom">
+ android:layout_width="match_parent">
<Button android:id="@+id/button_deny"
style="?android:attr/buttonBarButtonStyle"
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
index 2ee74fe4519b..55efe4a44c19 100644
--- a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
@@ -23,11 +23,13 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <ScrollView
+ <ScrollView
+ android:id="@+id/scroll_view"
android:padding="16dp"
android:layout_height="0dp"
android:layout_weight="1"
- android:layout_width="match_parent">
+ android:layout_width="match_parent"
+ android:clipToPadding="false" >
<LinearLayout
android:orientation="vertical"
android:layout_height="wrap_content"
@@ -82,8 +84,9 @@
android:layout_width="match_parent" />
<!-- button bar -->
- <LinearLayout android:orientation="horizontal"
- style="?android:attr/buttonBarStyle"
+ <LinearLayout android:id="@+id/button_bar"
+ android:orientation="horizontal"
+ style="?android:attr/buttonBarStyle"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_gravity="bottom">
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index 3c790f0e24ee..bc06bdbd29af 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -31,10 +31,17 @@ import android.text.Editable;
import android.text.TextWatcher;
import android.util.Slog;
import android.view.View;
+import android.view.ViewGroup.MarginLayoutParams;
import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
/**
* Confirm with the user that a requested full backup/restore operation is legitimate.
* Any attempt to perform a full backup/restore will launch this UI and wait for a
@@ -208,6 +215,8 @@ public class BackupRestoreConfirmation extends Activity {
setTitle(titleId);
setContentView(layoutId);
+ handleInsets();
+
// Same resource IDs for each layout variant (backup / restore)
mStatusView = findViewById(R.id.package_name);
mAllowButton = findViewById(R.id.button_allow);
@@ -254,6 +263,31 @@ public class BackupRestoreConfirmation extends Activity {
}
}
+ // Handle insets so that UI components are not covered by navigation and status bars
+ private void handleInsets() {
+ LinearLayout buttonBar = findViewById(R.id.button_bar);
+ ViewCompat.setOnApplyWindowInsetsListener(buttonBar, (v, windowInsets) -> {
+ Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
+ MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
+ mlp.leftMargin = insets.left;
+ mlp.bottomMargin = insets.bottom;
+ mlp.rightMargin = insets.right;
+ v.setLayoutParams(mlp);
+ return WindowInsetsCompat.CONSUMED;
+ });
+
+ ScrollView scrollView = findViewById(R.id.scroll_view);
+ ViewCompat.setOnApplyWindowInsetsListener(scrollView, (v, windowInsets) -> {
+ Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
+ MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
+ mlp.leftMargin = insets.left;
+ mlp.topMargin = insets.top;
+ mlp.rightMargin = insets.right;
+ v.setLayoutParams(mlp);
+ return WindowInsetsCompat.CONSUMED;
+ });
+ }
+
private void monitorEncryptionPassword() {
mAllowButton.setEnabled(false);
mEncPassword.addTextChangedListener(new TextWatcher() {
diff --git a/packages/CarrierDefaultApp/res/values-ar/strings.xml b/packages/CarrierDefaultApp/res/values-ar/strings.xml
index 53a27332a2d1..fe746f24912b 100644
--- a/packages/CarrierDefaultApp/res/values-ar/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ar/strings.xml
@@ -8,7 +8,7 @@
<string name="portal_notification_detail" msgid="2295729385924660881">"‏النقر للانتقال إلى موقع %s الإلكتروني"</string>
<string name="no_data_notification_detail" msgid="3112125343857014825">"‏يُرجى الاتصال بمقدم الخدمة %s"</string>
<string name="no_mobile_data_connection_title" msgid="7449525772416200578">"لا يوجد اتصال بيانات الجوال"</string>
- <string name="no_mobile_data_connection" msgid="544980465184147010">"‏إضافة بيانات أو خطة تجوال خلال %%s"</string>
+ <string name="no_mobile_data_connection" msgid="544980465184147010">"‏إضافة بيانات أو خطة تجوال خلال %s"</string>
<string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"حالة بيانات الجوّال"</string>
<string name="action_bar_label" msgid="4290345990334377177">"تسجيل الدخول إلى شبكة الجوّال"</string>
<string name="ssl_error_warning" msgid="3127935140338254180">"الشبكة التي تحاول الانضمام إليها بها مشاكل أمنية."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml
index 20d1300d89a9..d6225c2dd16e 100644
--- a/packages/CarrierDefaultApp/res/values-ur/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml
@@ -16,7 +16,7 @@
<string name="ssl_error_continue" msgid="1138548463994095584">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"پرفارمینس بوسٹ"</string>
<string name="performance_boost_notification_title" msgid="3126203390685781861">"‏آپ کے کیریئر سے 5G کے اختیارات"</string>
- <string name="performance_boost_notification_detail" msgid="216569851036236346">"‏اپنی ایپ کے تجربے کے اختیارات دیکھنے کے لیے %%s کی ویب سائٹ ملاحظہ کریں"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"‏اپنی ایپ کے تجربے کے اختیارات دیکھنے کے لیے %s کی ویب سائٹ ملاحظہ کریں"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ابھی نہیں"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"نظم کریں"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"پرفارمینس بوسٹ خریدیں۔"</string>
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index 2beffda34b05..43d8a628837b 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -14,6 +14,7 @@ java_sdk_library {
name: "framework-platformcrashrecovery",
srcs: [":framework-crashrecovery-sources"],
defaults: ["framework-non-updatable-unbundled-defaults"],
+ permitted_packages: ["android.service.watchdog"],
aidl: {
include_dirs: [
"frameworks/base/core/java",
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
index fbf51fd7cca7..2ba93f15f7fc 100644
--- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
@@ -218,7 +218,7 @@ public class PackageWatchdog {
@GuardedBy("sPackageWatchdogLock")
private static PackageWatchdog sPackageWatchdog;
- private final Object mLock = new Object();
+ private static final Object sLock = new Object();
// System server context
private final Context mContext;
// Handler to run short running tasks
@@ -228,7 +228,7 @@ public class PackageWatchdog {
// Contains (observer-name -> observer-handle) that have ever been registered from
// previous boots. Observers with all packages expired are periodically pruned.
// It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
// File containing the XML data of monitored packages /data/system/package-watchdog.xml
private final AtomicFile mPolicyFile;
@@ -244,26 +244,26 @@ public class PackageWatchdog {
private final Set<String> mPackagesExemptFromImpactLevelThreshold = new ArraySet<>();
// The set of packages that have been synced with the ExplicitHealthCheckController
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private boolean mIsPackagesReady;
// Flag to control whether explicit health checks are supported or not
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private boolean mIsHealthCheckEnabled = DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED;
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private int mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS;
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private int mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
// SystemClock#uptimeMillis when we last executed #syncState
// 0 if no prune is scheduled.
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private long mUptimeAtLastStateSync;
// If true, sync explicit health check packages with the ExplicitHealthCheckController.
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private boolean mSyncRequired = false;
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private long mLastMitigation = -1000000;
@FunctionalInterface
@@ -303,7 +303,11 @@ public class PackageWatchdog {
sPackageWatchdog = this;
}
- /** Creates or gets singleton instance of PackageWatchdog. */
+ /**
+ * Creates or gets singleton instance of PackageWatchdog.
+ *
+ * @param context The system server context.
+ */
public static @NonNull PackageWatchdog getInstance(@NonNull Context context) {
synchronized (sPackageWatchdogLock) {
if (sPackageWatchdog == null) {
@@ -319,7 +323,7 @@ public class PackageWatchdog {
* @hide
*/
public void onPackagesReady() {
- synchronized (mLock) {
+ synchronized (sLock) {
mIsPackagesReady = true;
mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
packages -> onSupportedPackages(packages),
@@ -338,7 +342,7 @@ public class PackageWatchdog {
* @hide
*/
public void registerHealthObserver(PackageHealthObserver observer) {
- synchronized (mLock) {
+ synchronized (sLock) {
ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier());
if (internalObserver != null) {
internalObserver.registeredObserver = observer;
@@ -405,7 +409,7 @@ public class PackageWatchdog {
mLongTaskHandler.post(() -> {
syncState("observing new packages");
- synchronized (mLock) {
+ synchronized (sLock) {
ObserverInternal oldObserver = mAllObservers.get(observer.getUniqueIdentifier());
if (oldObserver == null) {
Slog.d(TAG, observer.getUniqueIdentifier() + " started monitoring health "
@@ -437,7 +441,7 @@ public class PackageWatchdog {
*/
public void unregisterHealthObserver(PackageHealthObserver observer) {
mLongTaskHandler.post(() -> {
- synchronized (mLock) {
+ synchronized (sLock) {
mAllObservers.remove(observer.getUniqueIdentifier());
}
syncState("unregistering observer: " + observer.getUniqueIdentifier());
@@ -452,24 +456,24 @@ public class PackageWatchdog {
*
* <p>This method could be called frequently if there is a severe problem on the device.
*/
- public void onPackageFailure(@NonNull List<VersionedPackage> packages,
+ public void notifyPackageFailure(@NonNull List<VersionedPackage> packages,
@FailureReasons int failureReason) {
if (packages == null) {
Slog.w(TAG, "Could not resolve a list of failing packages");
return;
}
- synchronized (mLock) {
+ synchronized (sLock) {
final long now = mSystemClock.uptimeMillis();
if (Flags.recoverabilityDetection()) {
if (now >= mLastMitigation
&& (now - mLastMitigation) < getMitigationWindowMs()) {
- Slog.i(TAG, "Skipping onPackageFailure mitigation");
+ Slog.i(TAG, "Skipping notifyPackageFailure mitigation");
return;
}
}
}
mLongTaskHandler.post(() -> {
- synchronized (mLock) {
+ synchronized (sLock) {
if (mAllObservers.isEmpty()) {
return;
}
@@ -490,7 +494,7 @@ public class PackageWatchdog {
ObserverInternal observer = mAllObservers.valueAt(oIndex);
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null
- && observer.onPackageFailureLocked(
+ && observer.notifyPackageFailureLocked(
versionedPackage.getPackageName())) {
MonitoredPackage p = observer.getMonitoredPackage(
versionedPackage.getPackageName());
@@ -569,7 +573,7 @@ public class PackageWatchdog {
int currentObserverImpact,
int mitigationCount) {
if (allowMitigations(currentObserverImpact, versionedPackage)) {
- synchronized (mLock) {
+ synchronized (sLock) {
mLastMitigation = mSystemClock.uptimeMillis();
}
currentObserverToNotify.onExecuteHealthCheckMitigation(versionedPackage, failureReason,
@@ -599,7 +603,7 @@ public class PackageWatchdog {
*/
@SuppressWarnings("GuardedBy")
public void noteBoot() {
- synchronized (mLock) {
+ synchronized (sLock) {
// if boot count has reached threshold, start mitigation.
// We wait until threshold number of restarts only for the first time. Perform
// mitigations for every restart after that.
@@ -652,7 +656,7 @@ public class PackageWatchdog {
// This currently adds about 7ms extra to shutdown thread
/** @hide Writes the package information to file during shutdown. */
public void writeNow() {
- synchronized (mLock) {
+ synchronized (sLock) {
// Must only run synchronous tasks as this runs on the ShutdownThread and no other
// thread is guaranteed to run during shutdown.
if (!mAllObservers.isEmpty()) {
@@ -671,7 +675,7 @@ public class PackageWatchdog {
* passed and the health check service is stopped.
*/
private void setExplicitHealthCheckEnabled(boolean enabled) {
- synchronized (mLock) {
+ synchronized (sLock) {
mIsHealthCheckEnabled = enabled;
mHealthCheckController.setEnabled(enabled);
mSyncRequired = true;
@@ -689,7 +693,7 @@ public class PackageWatchdog {
// Check if native watchdog reported a crash
if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
// We rollback all available low impact rollbacks when crash is unattributable
- onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
+ notifyPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
// we stop polling after an attempt to execute rollback, regardless of whether the
// attempt succeeds or not
} else {
@@ -727,6 +731,25 @@ public class PackageWatchdog {
}
/**
+ * The minimum value that can be returned by any observer.
+ * It represents that no mitigations were available.
+ */
+ public static final int LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT =
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+
+ /**
+ * The mitigation impact beyond which the user will start noticing the mitigations.
+ */
+ public static final int MEDIUM_USER_IMPACT_THRESHOLD =
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20;
+
+ /**
+ * The mitigation impact beyond which the user impact is severely high.
+ */
+ public static final int HIGH_USER_IMPACT_THRESHOLD =
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
+
+ /**
* Possible severity values of the user impact of a
* {@link PackageHealthObserver#onExecuteHealthCheckMitigation}.
* @hide
@@ -769,6 +792,11 @@ public class PackageWatchdog {
/**
* Called when health check fails for the {@code versionedPackage}.
*
+ * Note: if the returned user impact is higher than
+ * {@link #DEFAULT_HIGH_USER_IMPACT_THRESHOLD}, then
+ * {@link #onExecuteHealthCheckMitigation} would be called only in severe device conditions
+ * like boot-loop or network failure.
+ *
* @param versionedPackage the package that is failing. This may be null if a native
* service is crashing.
* @param failureReason the type of failure that is occurring.
@@ -776,8 +804,8 @@ public class PackageWatchdog {
* (including this time).
*
*
- * @return any one of {@link PackageHealthObserverImpact} to express the impact
- * to the user on {@link #onExecuteHealthCheckMitigation}
+ * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express
+ * the impact of mitigation on the user in {@link #onExecuteHealthCheckMitigation}
*/
@PackageHealthObserverImpact int onHealthCheckFailed(
@Nullable VersionedPackage versionedPackage,
@@ -786,9 +814,8 @@ public class PackageWatchdog {
/**
* This would be called after {@link #onHealthCheckFailed}.
- * This is called only if current observer returned least
- * {@link PackageHealthObserverImpact} mitigation for failed health
- * check.
+ * This is called only if current observer returned least impact mitigation for failed
+ * health check.
*
* @param versionedPackage the package that is failing. This may be null if a native
* service is crashing.
@@ -807,6 +834,9 @@ public class PackageWatchdog {
*
* @param mitigationCount the number of times mitigation has been attempted for this
* boot loop (including this time).
+ *
+ * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express
+ * the impact of mitigation on the user in {@link #onExecuteBootLoopMitigation}
*/
default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) {
return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
@@ -814,11 +844,13 @@ public class PackageWatchdog {
/**
* This would be called after {@link #onBootLoop}.
- * This is called only if current observer returned least
- * {@link PackageHealthObserverImpact} mitigation for fixing boot loop
+ * This is called only if current observer returned least impact mitigation for fixing
+ * boot loop.
*
* @param mitigationCount the number of times mitigation has been attempted for this
* boot loop (including this time).
+ *
+ * @return {@code true} if action was executed successfully, {@code false} otherwise
*/
default boolean onExecuteBootLoopMitigation(int mitigationCount) {
return false;
@@ -841,7 +873,10 @@ public class PackageWatchdog {
/**
* Returns {@code true} if this observer wishes to observe the given package, {@code false}
- * otherwise
+ * otherwise.
+ * Any failing package can be passed on to the observer. Currently the packages that have
+ * ANRs and perform {@link android.service.watchdog.ExplicitHealthCheckService} are being
+ * passed to observers in these API.
*
* <p> A persistent observer may choose to start observing certain failing packages, even if
* it has not explicitly asked to watch the package with {@link #startObservingHealth}.
@@ -853,14 +888,14 @@ public class PackageWatchdog {
@VisibleForTesting
long getTriggerFailureCount() {
- synchronized (mLock) {
+ synchronized (sLock) {
return mTriggerFailureCount;
}
}
@VisibleForTesting
long getTriggerFailureDurationMs() {
- synchronized (mLock) {
+ synchronized (sLock) {
return mTriggerFailureDurationMs;
}
}
@@ -881,7 +916,7 @@ public class PackageWatchdog {
*/
private void syncRequests() {
boolean syncRequired = false;
- synchronized (mLock) {
+ synchronized (sLock) {
if (mIsPackagesReady) {
Set<String> packages = getPackagesPendingHealthChecksLocked();
if (mSyncRequired || !packages.equals(mRequestedHealthCheckPackages)
@@ -909,7 +944,7 @@ public class PackageWatchdog {
* effectively behave as if the explicit health check hasn't passed for {@code packageName}.
*
* <p> {@code packageName} can still be considered failed if reported by
- * {@link #onPackageFailureLocked} before the package expires.
+ * {@link #notifyPackageFailureLocked} before the package expires.
*
* <p> Triggered by components outside the system server when they are fully functional after an
* update.
@@ -918,7 +953,7 @@ public class PackageWatchdog {
Slog.i(TAG, "Health check passed for package: " + packageName);
boolean isStateChanged = false;
- synchronized (mLock) {
+ synchronized (sLock) {
for (int observerIdx = 0; observerIdx < mAllObservers.size(); observerIdx++) {
ObserverInternal observer = mAllObservers.valueAt(observerIdx);
MonitoredPackage monitoredPackage = observer.getMonitoredPackage(packageName);
@@ -946,7 +981,7 @@ public class PackageWatchdog {
supportedPackageTimeouts.put(info.getPackageName(), info.getHealthCheckTimeoutMillis());
}
- synchronized (mLock) {
+ synchronized (sLock) {
Slog.d(TAG, "Received supported packages " + supportedPackages);
Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
while (oit.hasNext()) {
@@ -977,13 +1012,13 @@ public class PackageWatchdog {
}
private void onSyncRequestNotified() {
- synchronized (mLock) {
+ synchronized (sLock) {
mSyncRequired = true;
syncRequestsAsync();
}
}
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private Set<String> getPackagesPendingHealthChecksLocked() {
Set<String> packages = new ArraySet<>();
Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
@@ -1009,7 +1044,7 @@ public class PackageWatchdog {
* health check service and schedules the next state sync.
*/
private void syncState(String reason) {
- synchronized (mLock) {
+ synchronized (sLock) {
Slog.i(TAG, "Syncing state, reason: " + reason);
pruneObserversLocked();
@@ -1025,7 +1060,7 @@ public class PackageWatchdog {
syncState("scheduled");
}
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private void scheduleNextSyncStateLocked() {
long durationMs = getNextStateSyncMillisLocked();
mShortTaskHandler.removeCallbacks(mSyncStateWithScheduledReason);
@@ -1043,7 +1078,7 @@ public class PackageWatchdog {
*
* @returns Long#MAX_VALUE if there are no observed packages.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private long getNextStateSyncMillisLocked() {
long shortestDurationMs = Long.MAX_VALUE;
for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
@@ -1064,7 +1099,7 @@ public class PackageWatchdog {
* Removes {@code elapsedMs} milliseconds from all durations on monitored packages
* and updates other internal state.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private void pruneObserversLocked() {
long elapsedMs = mUptimeAtLastStateSync == 0
? 0 : mSystemClock.uptimeMillis() - mUptimeAtLastStateSync;
@@ -1092,7 +1127,7 @@ public class PackageWatchdog {
private void onHealthCheckFailed(ObserverInternal observer,
Set<MonitoredPackage> failedPackages) {
mLongTaskHandler.post(() -> {
- synchronized (mLock) {
+ synchronized (sLock) {
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null) {
Iterator<MonitoredPackage> it = failedPackages.iterator();
@@ -1201,7 +1236,7 @@ public class PackageWatchdog {
*/
@VisibleForTesting
void updateConfigs() {
- synchronized (mLock) {
+ synchronized (sLock) {
mTriggerFailureCount = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
@@ -1230,7 +1265,7 @@ public class PackageWatchdog {
*/
private boolean saveToFile() {
Slog.i(TAG, "Saving observer state to file");
- synchronized (mLock) {
+ synchronized (sLock) {
FileOutputStream stream;
try {
stream = mPolicyFile.startWrite();
@@ -1297,20 +1332,37 @@ public class PackageWatchdog {
/** Dump status of every observer in mAllObservers. */
public void dump(@NonNull PrintWriter pw) {
- if (Flags.synchronousRebootInRescueParty() && RescueParty.isRecoveryTriggeredReboot()) {
+ if (Flags.synchronousRebootInRescueParty() && isRecoveryTriggeredReboot()) {
dumpInternal(pw);
} else {
- synchronized (mLock) {
+ synchronized (sLock) {
dumpInternal(pw);
}
}
}
+ /**
+ * Check if we're currently attempting to reboot during mitigation. This method must return
+ * true if triggered reboot early during a boot loop, since the device will not be fully booted
+ * at this time.
+ */
+ public static boolean isRecoveryTriggeredReboot() {
+ return isFactoryResetPropertySet() || isRebootPropertySet();
+ }
+
+ private static boolean isFactoryResetPropertySet() {
+ return CrashRecoveryProperties.attemptingFactoryReset().orElse(false);
+ }
+
+ private static boolean isRebootPropertySet() {
+ return CrashRecoveryProperties.attemptingReboot().orElse(false);
+ }
+
private void dumpInternal(@NonNull PrintWriter pw) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.println("Package Watchdog status");
ipw.increaseIndent();
- synchronized (mLock) {
+ synchronized (sLock) {
for (String observerName : mAllObservers.keySet()) {
ipw.println("Observer name: " + observerName);
ipw.increaseIndent();
@@ -1324,7 +1376,7 @@ public class PackageWatchdog {
}
@VisibleForTesting
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
void registerObserverInternal(ObserverInternal observerInternal) {
mAllObservers.put(observerInternal.name, observerInternal);
}
@@ -1333,15 +1385,15 @@ public class PackageWatchdog {
* Represents an observer monitoring a set of packages along with the failure thresholds for
* each package.
*
- * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
+ * <p> Note, the PackageWatchdog#sLock must always be held when reading or writing
* instances of this class.
*/
static class ObserverInternal {
public final String name;
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private final ArrayMap<String, MonitoredPackage> mPackages = new ArrayMap<>();
@Nullable
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public PackageHealthObserver registeredObserver;
private int mMitigationCount;
@@ -1359,7 +1411,7 @@ public class PackageWatchdog {
* Writes important {@link MonitoredPackage} details for this observer to file.
* Does not persist any package failure thresholds.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public boolean writeLocked(XmlSerializer out) {
try {
out.startTag(null, TAG_OBSERVER);
@@ -1387,7 +1439,7 @@ public class PackageWatchdog {
mMitigationCount = mitigationCount;
}
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public void updatePackagesLocked(List<MonitoredPackage> packages) {
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
MonitoredPackage p = packages.get(pIndex);
@@ -1410,7 +1462,7 @@ public class PackageWatchdog {
* health check passing, or an empty list if no package expired for which an explicit health
* check was still pending
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private Set<MonitoredPackage> prunePackagesLocked(long elapsedMs) {
Set<MonitoredPackage> failedPackages = new ArraySet<>();
Iterator<MonitoredPackage> it = mPackages.values().iterator();
@@ -1435,8 +1487,8 @@ public class PackageWatchdog {
* @returns {@code true} if failure threshold is exceeded, {@code false} otherwise
* @hide
*/
- @GuardedBy("mLock")
- public boolean onPackageFailureLocked(String packageName) {
+ @GuardedBy("sLock")
+ public boolean notifyPackageFailureLocked(String packageName) {
if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent()
&& registeredObserver.mayObservePackage(packageName)) {
putMonitoredPackage(sPackageWatchdog.newMonitoredPackage(
@@ -1454,7 +1506,7 @@ public class PackageWatchdog {
*
* @return a mapping of package names to {@link MonitoredPackage} objects.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public ArrayMap<String, MonitoredPackage> getMonitoredPackages() {
return mPackages;
}
@@ -1467,7 +1519,7 @@ public class PackageWatchdog {
* @return the {@link MonitoredPackage} object associated with the package name if one
* exists, {@code null} otherwise.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
@Nullable
public MonitoredPackage getMonitoredPackage(String packageName) {
return mPackages.get(packageName);
@@ -1478,7 +1530,7 @@ public class PackageWatchdog {
*
* @param p: the {@link MonitoredPackage} to store.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public void putMonitoredPackage(MonitoredPackage p) {
mPackages.put(p.getName(), p);
}
@@ -1601,17 +1653,17 @@ public class PackageWatchdog {
* Represents a package and its health check state along with the time
* it should be monitored for.
*
- * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
+ * <p> Note, the PackageWatchdog#sLock must always be held when reading or writing
* instances of this class.
*/
class MonitoredPackage {
private final String mPackageName;
// Times when package failures happen sorted in ascending order
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private final LongArrayQueue mFailureHistory = new LongArrayQueue();
// Times when an observer was called to mitigate this package's failure. Sorted in
// ascending order.
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private final LongArrayQueue mMitigationCalls;
// One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
// methods that could change the health check state: handleElapsedTimeLocked and
@@ -1620,17 +1672,17 @@ public class PackageWatchdog {
// Whether an explicit health check has passed.
// This value in addition with mHealthCheckDurationMs determines the health check state
// of the package, see #getHealthCheckStateLocked
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private boolean mHasPassedHealthCheck;
// System uptime duration to monitor package.
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private long mDurationMs;
// System uptime duration to check the result of an explicit health check
// Initially, MAX_VALUE until we get a value from the health check service
// and request health checks.
// This value in addition with mHasPassedHealthCheck determines the health check state
// of the package, see #getHealthCheckStateLocked
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private long mHealthCheckDurationMs = Long.MAX_VALUE;
MonitoredPackage(String packageName, long durationMs,
@@ -1647,7 +1699,7 @@ public class PackageWatchdog {
/** Writes the salient fields to disk using {@code out}.
* @hide
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public void writeLocked(XmlSerializer out) throws IOException {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATTR_NAME, getName());
@@ -1665,7 +1717,7 @@ public class PackageWatchdog {
*
* @return {@code true} if failure count exceeds a threshold, {@code false} otherwise
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public boolean onFailureLocked() {
// Sliding window algorithm: find out if there exists a window containing failures >=
// mTriggerFailureCount.
@@ -1685,7 +1737,7 @@ public class PackageWatchdog {
/**
* Notes the timestamp of a mitigation call into the observer.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public void noteMitigationCallLocked() {
mMitigationCalls.addLast(mSystemClock.uptimeMillis());
}
@@ -1696,7 +1748,7 @@ public class PackageWatchdog {
*
* @return the number of mitigation calls made in the de-escalation window.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public int getMitigationCountLocked() {
try {
final long now = mSystemClock.uptimeMillis();
@@ -1716,7 +1768,7 @@ public class PackageWatchdog {
*
* @return a LongArrayQueue of the mitigation calls relative to the current system uptime.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public LongArrayQueue normalizeMitigationCalls() {
LongArrayQueue normalized = new LongArrayQueue();
final long now = mSystemClock.uptimeMillis();
@@ -1731,7 +1783,7 @@ public class PackageWatchdog {
*
* @return the new health check state
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public int setHealthCheckActiveLocked(long initialHealthCheckDurationMs) {
if (initialHealthCheckDurationMs <= 0) {
Slog.wtf(TAG, "Cannot set non-positive health check duration "
@@ -1751,7 +1803,7 @@ public class PackageWatchdog {
*
* @return the new health check state
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public int handleElapsedTimeLocked(long elapsedMs) {
if (elapsedMs <= 0) {
Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + getName());
@@ -1769,7 +1821,7 @@ public class PackageWatchdog {
}
/** Explicitly update the monitoring duration of the package. */
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public void updateHealthCheckDuration(long newDurationMs) {
mDurationMs = newDurationMs;
}
@@ -1780,7 +1832,7 @@ public class PackageWatchdog {
*
* @return the new {@link HealthCheckState health check state}
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
@HealthCheckState
public int tryPassHealthCheckLocked() {
if (mHealthCheckState != HealthCheckState.FAILED) {
@@ -1799,7 +1851,7 @@ public class PackageWatchdog {
/**
* Returns the current {@link HealthCheckState health check state}.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
@HealthCheckState
public int getHealthCheckStateLocked() {
return mHealthCheckState;
@@ -1810,7 +1862,7 @@ public class PackageWatchdog {
*
* @return the duration or {@link Long#MAX_VALUE} if the package should not be scheduled
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public long getShortestScheduleDurationMsLocked() {
// Consider health check duration only if #isPendingHealthChecksLocked is true
return Math.min(toPositive(mDurationMs),
@@ -1822,7 +1874,7 @@ public class PackageWatchdog {
* Returns {@code true} if the total duration left to monitor the package is less than or
* equal to 0 {@code false} otherwise.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public boolean isExpiredLocked() {
return mDurationMs <= 0;
}
@@ -1831,7 +1883,7 @@ public class PackageWatchdog {
* Returns {@code true} if the package, {@link #getName} is expecting health check results
* {@code false} otherwise.
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public boolean isPendingHealthChecksLocked() {
return mHealthCheckState == HealthCheckState.ACTIVE
|| mHealthCheckState == HealthCheckState.INACTIVE;
@@ -1843,7 +1895,7 @@ public class PackageWatchdog {
*
* @return the new {@link HealthCheckState health check state}
*/
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
@HealthCheckState
private int updateHealthCheckStateLocked() {
int oldState = mHealthCheckState;
@@ -1898,7 +1950,7 @@ public class PackageWatchdog {
}
}
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
@SuppressWarnings("GuardedBy")
void saveAllObserversBootMitigationCountToMetadata(String filePath) {
HashMap<String, Integer> bootMitigationCounts = new HashMap<>();
@@ -2001,7 +2053,7 @@ public class PackageWatchdog {
/** Increments the boot counter, and returns whether the device is bootlooping. */
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
public boolean incrementAndTest() {
if (Flags.recoverabilityDetection()) {
readAllObserversBootMitigationCountIfNecessary(METADATA_FILE);
@@ -2042,7 +2094,7 @@ public class PackageWatchdog {
}
}
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private boolean performedMitigationsDuringWindow() {
for (ObserverInternal observerInternal: mAllObservers.values()) {
if (observerInternal.getBootMitigationCount() > 0) {
@@ -2052,7 +2104,7 @@ public class PackageWatchdog {
return false;
}
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
private void resetAllObserversBootMitigationCount() {
for (int i = 0; i < mAllObservers.size(); i++) {
final ObserverInternal observer = mAllObservers.valueAt(i);
@@ -2061,7 +2113,7 @@ public class PackageWatchdog {
saveAllObserversBootMitigationCountToMetadata(METADATA_FILE);
}
- @GuardedBy("mLock")
+ @GuardedBy("sLock")
@SuppressWarnings("GuardedBy")
void readAllObserversBootMitigationCountIfNecessary(String filePath) {
File metadataFile = new File(filePath);
diff --git a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
index 129e47f22f38..88fe36cda395 100644
--- a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
@@ -477,7 +477,7 @@ public class PackageWatchdog {
*
* <p>This method could be called frequently if there is a severe problem on the device.
*/
- public void onPackageFailure(@NonNull List<VersionedPackage> packages,
+ public void notifyPackageFailure(@NonNull List<VersionedPackage> packages,
@FailureReasons int failureReason) {
if (packages == null) {
Slog.w(TAG, "Could not resolve a list of failing packages");
@@ -488,7 +488,7 @@ public class PackageWatchdog {
if (Flags.recoverabilityDetection()) {
if (now >= mLastMitigation
&& (now - mLastMitigation) < getMitigationWindowMs()) {
- Slog.i(TAG, "Skipping onPackageFailure mitigation");
+ Slog.i(TAG, "Skipping notifyPackageFailure mitigation");
return;
}
}
@@ -515,7 +515,7 @@ public class PackageWatchdog {
ObserverInternal observer = mAllObservers.valueAt(oIndex);
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null
- && observer.onPackageFailureLocked(
+ && observer.notifyPackageFailureLocked(
versionedPackage.getPackageName())) {
MonitoredPackage p = observer.getMonitoredPackage(
versionedPackage.getPackageName());
@@ -714,7 +714,7 @@ public class PackageWatchdog {
// Check if native watchdog reported a crash
if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
// We rollback all available low impact rollbacks when crash is unattributable
- onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
+ notifyPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
// we stop polling after an attempt to execute rollback, regardless of whether the
// attempt succeeds or not
} else {
@@ -926,7 +926,7 @@ public class PackageWatchdog {
* effectively behave as if the explicit health check hasn't passed for {@code packageName}.
*
* <p> {@code packageName} can still be considered failed if reported by
- * {@link #onPackageFailureLocked} before the package expires.
+ * {@link #notifyPackageFailureLocked} before the package expires.
*
* <p> Triggered by components outside the system server when they are fully functional after an
* update.
@@ -1253,7 +1253,7 @@ public class PackageWatchdog {
return;
}
final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
- onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+ notifyPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
});
}
@@ -1467,7 +1467,7 @@ public class PackageWatchdog {
* @hide
*/
@GuardedBy("mLock")
- public boolean onPackageFailureLocked(String packageName) {
+ public boolean notifyPackageFailureLocked(String packageName) {
if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent()
&& registeredObserver.mayObservePackage(packageName)) {
putMonitoredPackage(sPackageWatchdog.newMonitoredPackage(
diff --git a/packages/NeuralNetworks/OWNERS b/packages/NeuralNetworks/OWNERS
new file mode 100644
index 000000000000..6b391503b5c4
--- /dev/null
+++ b/packages/NeuralNetworks/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 195575
+
+sandeepbandaru@google.com
+shivanker@google.com
+shiqing@google.com \ No newline at end of file
diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml
index 5147c52d4acc..ca0ca9c1bfd2 100644
--- a/packages/PackageInstaller/res/values-cs/strings.xml
+++ b/packages/PackageInstaller/res/values-cs/strings.xml
@@ -21,7 +21,7 @@
<string name="update" msgid="3932142540719227615">"Aktualizovat"</string>
<string name="done" msgid="6632441120016885253">"Hotovo"</string>
<string name="cancel" msgid="1018267193425558088">"Zrušit"</string>
- <string name="installing" msgid="4921993079741206516">"Instalace…"</string>
+ <string name="installing" msgid="4921993079741206516">"Probíhá instalace…"</string>
<string name="installing_app" msgid="1165095864863849422">"Instalace balíčku <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
<string name="install_done" msgid="5987363587661783896">"Aplikace je nainstalována."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Chcete tuto aplikaci nainstalovat?"</string>
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 003420829c8a..f97b75884a8a 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -65,6 +65,7 @@
android:configChanges="mnc|mnc|touchscreen|navigation|screenLayout|screenSize|smallestScreenSize|orientation|locale|keyboard|keyboardHidden|fontScale|uiMode|layoutDirection|density"
android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
android:theme="@style/Theme.PrintActivity"
+ android:enableOnBackInvokedCallback="true"
android:exported="true">
<intent-filter>
<action android:name="android.print.PRINT_DIALOG" />
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index bd2b5ec8436e..4a3a6d248254 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -84,6 +84,7 @@ import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
+import android.window.OnBackInvokedDispatcher;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -323,6 +324,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
});
getLoaderManager().initLoader(LOADER_ID_ENABLED_PRINT_SERVICES, null, this);
+ getWindow().getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, this::onBackInvoked);
}
private void onConnectedToPrintSpooler(final IBinder documentAdapter) {
@@ -481,17 +484,21 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
&& event.isTracking() && !event.isCanceled()) {
- if (mPrintPreviewController != null && mPrintPreviewController.isOptionsOpened()
- && !hasErrors()) {
- mPrintPreviewController.closeOptions();
- } else {
- cancelPrint();
- }
+ onBackInvoked();
return true;
}
return super.onKeyUp(keyCode, event);
}
+ private void onBackInvoked() {
+ if (mPrintPreviewController != null && mPrintPreviewController.isOptionsOpened()
+ && !hasErrors()) {
+ mPrintPreviewController.closeOptions();
+ } else {
+ cancelPrint();
+ }
+ }
+
@Override
public void onRequestContentUpdate() {
if (canUpdateDocument()) {
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index b2dcb7fa4f53..a3da93da31ae 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -61,9 +61,11 @@ android_library {
"SettingsLibUtils",
"SettingsLibZeroStatePreference",
"settingslib_media_flags_lib",
+ ],
+ libs:[
+ // This flag library has been added in frameworks jar
"aconfig_settingslib_flags_java_lib",
],
-
plugins: ["androidx.room_room-compiler-plugin"],
use_resource_processor: true,
resource_dirs: ["res"],
diff --git a/packages/SettingsLib/AvatarPicker/res/values-af/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-af/strings.xml
new file mode 100644
index 000000000000..38cae307f5dc
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-af/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Kies \'n prent"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Neem \'n foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Verstekgebruikerikoon"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-am/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-am/strings.xml
new file mode 100644
index 000000000000..917a2fdc6a61
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-am/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ምስል ይምረጡ"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ፎቶ ያንሱ"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ነባሪ የተጠቃሚ አዶ"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml
new file mode 100644
index 000000000000..8e5231ba1e77
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"اختيار صورة"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"التقاط صورة"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"رمز المستخدم التلقائي"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-as/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-as/strings.xml
new file mode 100644
index 000000000000..c77b573b26c6
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-as/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"এখন ফট’ তোলক"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ডিফ’ল্ট ব্যৱহাৰকাৰীৰ চিহ্ন"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-az/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-az/strings.xml
new file mode 100644
index 000000000000..6871473a82a3
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-az/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Şəkil seçin"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Foto çəkin"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Defolt istifadəçi ikonası"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 000000000000..42fb478f5ca0
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Odaberite sliku"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Slikajte"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Podrazumevana ikona korisnika"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-be/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-be/strings.xml
new file mode 100644
index 000000000000..c2ef4db67c5d
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-be/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Выбраць відарыс"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Зрабіць фота"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Стандартны карыстальніцкі значок"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml
new file mode 100644
index 000000000000..eeca7d8d5c9e
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Избиране на изображение"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Правене на снимка"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Икона за основния потребител"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml
new file mode 100644
index 000000000000..6d4d29f47ac6
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"একটি ছবি বেছে নিন"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ফটো তুলুন"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ডিফল্ট ব্যবহারকারীর আইকন"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml
new file mode 100644
index 000000000000..def1b4525c40
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Odaberite sliku"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Snimite fotografiju"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Zadana ikona korisnika"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml
new file mode 100644
index 000000000000..1b613cafa4df
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Tria una imatge"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Fes una foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Icona d\'usuari predeterminat"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml
new file mode 100644
index 000000000000..ffe2f47df489
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Zvolit obrázek"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Vyfotit"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Výchozí uživatelská ikona"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-da/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-da/strings.xml
new file mode 100644
index 000000000000..ab01eef4ab6e
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-da/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Vælg et billede"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Tag et billede"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon for standardbruger"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-de/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-de/strings.xml
new file mode 100644
index 000000000000..4d6c651adabd
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-de/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Bild auswählen"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Foto aufnehmen"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Standardmäßiges Nutzersymbol"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-el/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-el/strings.xml
new file mode 100644
index 000000000000..9e6813fff4d0
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-el/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Επιλέξτε μια εικόνα"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Λήψη φωτογραφίας"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Προεπιλεγμένο εικονίδιο χρήστη"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml
new file mode 100644
index 000000000000..d0aae7917ffd
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Choose an image"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Take a photo"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Default user icon"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-en-rCA/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-en-rCA/strings.xml
new file mode 100644
index 000000000000..f9905d0eb796
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-en-rCA/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Choose an image"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Take a photo"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"Choose a profile picture"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Default user icon"</string>
+ <string name="done" msgid="3587741621903511576">"Done"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000000..d0aae7917ffd
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Choose an image"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Take a photo"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Default user icon"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000000..d0aae7917ffd
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Choose an image"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Take a photo"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Default user icon"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000000..296dcc8603e6
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Elegir una imagen"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Tomar una foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ícono de usuario predeterminado"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-es/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-es/strings.xml
new file mode 100644
index 000000000000..5d4a8d280796
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-es/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Seleccionar una imagen"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Hacer una foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Icono de usuario predeterminado"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-et/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-et/strings.xml
new file mode 100644
index 000000000000..ecd3a83ea2b2
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-et/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Vali pilt"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Pildista"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Vaikekasutajaikoon"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml
new file mode 100644
index 000000000000..e29bc114b5ec
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Aukeratu irudi bat"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Atera argazki bat"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Erabiltzaile lehenetsiaren ikonoa"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml
new file mode 100644
index 000000000000..25efac4ba93d
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"انتخاب تصویر"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"عکس گرفتن"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"نماد کاربر پیش‌فرض"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml
new file mode 100644
index 000000000000..4d805ed242cb
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Valitse kuva"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Ota kuva"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Oletuskäyttäjäkuvake"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000000..fb32c5b118fb
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Sélectionner une image"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Prendre une photo"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Icône d\'utilisateur par défaut"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml
new file mode 100644
index 000000000000..79620e96bcac
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Choisir une image"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Prendre une photo"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Icône de l\'utilisateur par défaut"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml
new file mode 100644
index 000000000000..bbfa18bf0080
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Escoller unha imaxe"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Tirar unha foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Icona do usuario predeterminado"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml
new file mode 100644
index 000000000000..247afe13d0fb
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"છબી પસંદ કરો"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ફોટો લો"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ડિફૉલ્ટ વપરાશકર્તાનું આઇકન"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml
new file mode 100644
index 000000000000..3c515769630e
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"इमेज चुनें"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"फ़ोटो खींचें"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"उपयोगकर्ता के लिए डिफ़ॉल्ट आइकॉन"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml
new file mode 100644
index 000000000000..e9a56bdc839e
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Odaberite sliku"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Snimi fotografiju"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ikona zadanog korisnika"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml
new file mode 100644
index 000000000000..f3d53cd57d53
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Kép kiválasztása"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Fotó készítése"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Alapértelmezett felhasználó ikonja"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-hy/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-hy/strings.xml
new file mode 100644
index 000000000000..d897cd264c8d
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-hy/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Ընտրել պատկեր"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Լուսանկարել"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"Ընտրեք պրոֆիլի նկար"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Օգտատիրոջ կանխադրված պատկերակ"</string>
+ <string name="done" msgid="3587741621903511576">"Պատրաստ է"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-in/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-in/strings.xml
new file mode 100644
index 000000000000..bfa0d935c6e7
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-in/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Pilih gambar"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Ambil foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon pengguna default"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-is/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-is/strings.xml
new file mode 100644
index 000000000000..d49652480db5
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-is/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Velja mynd"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Taka mynd"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Tákn sjálfgefins notanda"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-it/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-it/strings.xml
new file mode 100644
index 000000000000..3ba0a01cbed2
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-it/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Scegli un\'immagine"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Scatta una foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Icona dell\'utente predefinito"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml
new file mode 100644
index 000000000000..903989d999e0
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"לבחירת תמונה"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"צילום תמונה"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"סמל המשתמש שמוגדר כברירת מחדל"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ja/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ja/strings.xml
new file mode 100644
index 000000000000..15a4cdc974a1
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ja/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"画像を選択"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"写真を撮る"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"プロフィール写真の選択"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"デフォルト ユーザー アイコン"</string>
+ <string name="done" msgid="3587741621903511576">"完了"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml
new file mode 100644
index 000000000000..817180bb6493
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"სურათის არჩევა"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ფოტოს გადაღება"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"მომხმარებლის ნაგულისხმევი ხატულა"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml
new file mode 100644
index 000000000000..ec01801bace9
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Кескін таңдау"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Суретке түсіру"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Әдепкі пайдаланушы белгішесі"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-km/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-km/strings.xml
new file mode 100644
index 000000000000..7a311224646e
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-km/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ជ្រើសរើស​រូបភាព"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ថតរូប"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"រូបអ្នកប្រើប្រាស់លំនាំដើម"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-kn/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-kn/strings.xml
new file mode 100644
index 000000000000..67f889980bd8
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-kn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ಚಿತ್ರವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ಫೋಟೋವನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"ಪ್ರೊಫೈಲ್‌ ಚಿತ್ರವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ಡೀಫಾಲ್ಟ್ ಬಳಕೆದಾರರ ಐಕಾನ್"</string>
+ <string name="done" msgid="3587741621903511576">"ಮುಗಿದಿದೆ"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml
new file mode 100644
index 000000000000..45bfb532e6e1
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"이미지 선택"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"사진 찍기"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"기본 사용자 아이콘"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml
new file mode 100644
index 000000000000..b3d39de49bda
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Сүрөт тандоо"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Сүрөткө тартуу"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Демейки колдонуучунун сүрөтчөсү"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml
new file mode 100644
index 000000000000..3ba6709d04a4
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ເລືອກຮູບ"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ຖ່າຍຮູບ"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ໄອຄອນຜູ້ໃຊ້ເລີ່ມຕົ້ນ"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml
new file mode 100644
index 000000000000..b0c0c39495f5
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Pasirinkti vaizdą"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Fotografuoti"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Numatytojo naudotojo piktograma"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml
new file mode 100644
index 000000000000..e664c80b5e7c
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Izvēlēties attēlu"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Uzņemt fotoattēlu"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Noklusējuma lietotāja ikona"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml
new file mode 100644
index 000000000000..bb0e2476bdc2
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Изберете слика"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Фотографирај"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Икона за стандарден корисник"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml
new file mode 100644
index 000000000000..674b4f5d8fb5
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ഡിഫോൾട്ട് ഉപയോക്തൃ ഐക്കൺ"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml
new file mode 100644
index 000000000000..61553b54d745
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Зураг сонгох"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Зураг авах"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Өгөгдмөл хэрэглэгчийн дүрс тэмдэг"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-mr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-mr/strings.xml
new file mode 100644
index 000000000000..acc2c460a891
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-mr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"इमेज निवडा"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"फोटो काढा"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"प्रोफाइल फोटो निवडा"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"डीफॉल्ट वापरकर्ता आयकन"</string>
+ <string name="done" msgid="3587741621903511576">"पूर्ण झाले"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml
new file mode 100644
index 000000000000..25996969e61e
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Pilih imej"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Ambil foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon pengguna lalai"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-my/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-my/strings.xml
new file mode 100644
index 000000000000..f9f697b3c200
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-my/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ပုံရွေးရန်"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ဓာတ်ပုံရိုက်ရန်"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"မူရင်းအသုံးပြုသူ သင်္ကေတ"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml
new file mode 100644
index 000000000000..c1b7631fa8b2
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Velg et bilde"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Ta et bilde"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Standard brukerikon"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml
new file mode 100644
index 000000000000..a8c02b97cac8
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"कुनै फोटो छनौट गर्नुहोस्"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"फोटो खिच्नुहोस्"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"प्रयोगकर्ताको डिफल्ट आइकन"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml
new file mode 100644
index 000000000000..47352bc12100
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Een afbeelding kiezen"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Een foto maken"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Standaard gebruikersicoon"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-or/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-or/strings.xml
new file mode 100644
index 000000000000..132b97a6f46c
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-or/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ଗୋଟିଏ ଛବି ବାଛନ୍ତୁ"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ଗୋଟିଏ ଫଟୋ ଉଠାନ୍ତୁ"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ଡିଫଲ୍ଟ ୟୁଜର ଆଇକନ"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pa/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pa/strings.xml
new file mode 100644
index 000000000000..a336226b5182
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-pa/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ਚਿੱਤਰ ਚੁਣੋ"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ਫ਼ੋਟੋ ਖਿੱਚੋ"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"ਕੋਈ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਚੁਣੋ"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਰਤੋਂਕਾਰ ਪ੍ਰਤੀਕ"</string>
+ <string name="done" msgid="3587741621903511576">"ਹੋ ਗਿਆ"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml
new file mode 100644
index 000000000000..7db79047047b
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Wybierz obraz"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Zrób zdjęcie"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ikona domyślnego użytkownika"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000000..ae3e6e508c8b
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Escolher uma imagem"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Tirar uma foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ícone de usuário padrão"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pt-rPT/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000000..18f36c39bfa1
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-pt-rPT/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Escolher uma imagem"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Tirar uma foto"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"Escolha uma imagem do perfil"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ícone do utilizador predefinido"</string>
+ <string name="done" msgid="3587741621903511576">"Concluído"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml
new file mode 100644
index 000000000000..ae3e6e508c8b
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Escolher uma imagem"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Tirar uma foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ícone de usuário padrão"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml
new file mode 100644
index 000000000000..ce662d41a113
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Alege o imagine"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Fă o fotografie"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Pictograma prestabilită a utilizatorului"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml
new file mode 100644
index 000000000000..47f8a839beb4
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Выбрать фото"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Сделать снимок"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Значок пользователя по умолчанию"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-si/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-si/strings.xml
new file mode 100644
index 000000000000..aaba44266bb1
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-si/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"රූපයක් තෝරන්න"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ඡායාරූපයක් ගන්න"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"පෙරනිමි පරිශීලක නිරූපකය"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml
new file mode 100644
index 000000000000..3f801a36843d
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Vybrať obrázok"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Odfotiť"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Predvolená ikona používateľa"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sl/strings.xml
new file mode 100644
index 000000000000..7d0bf10cc564
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-sl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Izbira slike"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Fotografiranje"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"Izbira profilne slike"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Privzeta ikona uporabnika"</string>
+ <string name="done" msgid="3587741621903511576">"Končano"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml
new file mode 100644
index 000000000000..0b8a58d0d5d5
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Zgjidh një imazh"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Bëj një fotografi"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ikona e parazgjedhur e përdoruesit"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml
new file mode 100644
index 000000000000..1014df4f3b95
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Одаберите слику"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Сликајте"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Подразумевана икона корисника"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml
new file mode 100644
index 000000000000..82034092288a
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Välj en bild"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Ta ett foto"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon för standardanvändare"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml
new file mode 100644
index 000000000000..b0e8c44d5e8a
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Chagua picha"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Piga picha"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Aikoni chaguomsingi ya mtumiaji"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ta/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ta/strings.xml
new file mode 100644
index 000000000000..13c7b5b13a54
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ta/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"படத்தைத் தேர்வுசெய்க"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"படமெடு"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"சுயவிவரப் படத்தைத் தேர்வுசெய்யுங்கள்"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"இயல்புநிலைப் பயனர் ஐகான்"</string>
+ <string name="done" msgid="3587741621903511576">"முடிந்தது"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-te/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-te/strings.xml
new file mode 100644
index 000000000000..b7318486f10f
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-te/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"చిత్రాన్ని ఎంచుకోండి"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ఫోటోను తీయి"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"ప్రొఫైల్ ఫోటోను ఎంచుకోండి"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ఆటోమేటిక్ సెట్టింగ్ యూజర్ చిహ్నం"</string>
+ <string name="done" msgid="3587741621903511576">"పూర్తయింది"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-th/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-th/strings.xml
new file mode 100644
index 000000000000..31e753e04cc1
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-th/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"เลือกรูปภาพ"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ถ่ายรูป"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ไอคอนผู้ใช้เริ่มต้น"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-tl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-tl/strings.xml
new file mode 100644
index 000000000000..77b28cd5e7b6
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-tl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Pumili ng larawan"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Kumuha ng larawan"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"Pumili ng larawan sa profile"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Icon ng default na user"</string>
+ <string name="done" msgid="3587741621903511576">"Tapos na"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml
new file mode 100644
index 000000000000..26d96c22c7f2
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Resim seç"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Fotoğraf çek"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Varsayılan kullanıcı simgesi"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml
new file mode 100644
index 000000000000..1fbe5fb1076a
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Вибрати зображення"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Зробити фото"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Значок користувача за умовчанням"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ur/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ur/strings.xml
new file mode 100644
index 000000000000..7972ee125c9e
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-ur/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"ایک تصویر منتخب کریں"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"ایک تصویر لیں"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"پروفائل کی تصویر منتخب کریں"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"ڈیفالٹ صارف کا آئیکن"</string>
+ <string name="done" msgid="3587741621903511576">"ہو گیا"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-uz/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-uz/strings.xml
new file mode 100644
index 000000000000..208be10481ee
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-uz/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Rasm tanlash"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Suratga olish"</string>
+ <string name="avatar_picker_title" msgid="7478146965334560463">"Profil rasmini tanlash"</string>
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Foydalanuvchining standart belgisi"</string>
+ <string name="done" msgid="3587741621903511576">"Tayyor"</string>
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml
new file mode 100644
index 000000000000..036c0065ebd7
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Chọn hình ảnh"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Chụp ảnh"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Biểu tượng người dùng mặc định"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000000..58488b35b0a6
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"选择图片"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"拍照"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"默认用户图标"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000000..e5f375205844
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"選擇圖片"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"拍攝相片"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"預設使用者圖示"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000000..4a58180ba15f
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"選擇圖片"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"拍照"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"預設使用者圖示"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml
new file mode 100644
index 000000000000..ad15f890cd05
--- /dev/null
+++ b/packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="user_image_choose_photo" msgid="5630717762469961028">"Khetha isithombe"</string>
+ <string name="user_image_take_photo" msgid="3147097821937166738">"Thatha isithombe"</string>
+ <!-- no translation found for avatar_picker_title (7478146965334560463) -->
+ <skip />
+ <string name="default_user_icon_description" msgid="6018582161341388812">"Isithonjana somsebenzisi sokuzenzakalelayo"</string>
+ <!-- no translation found for done (3587741621903511576) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml
index fadcf7ba8699..e68253e2200d 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml
@@ -18,7 +18,7 @@
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
- <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item>
+ <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item>
<item name="colorAccent">@color/settingslib_materialColorPrimaryFixed</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml
index 7c9d1a47b7ef..f7c9aac68629 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml
@@ -18,7 +18,7 @@
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
- <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item>
+ <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item>
<item name="colorAccent">@color/settingslib_materialColorPrimary</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesObservable.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesObservable.kt
deleted file mode 100644
index e70ec5b2e38e..000000000000
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesObservable.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2024 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.datastore
-
-import android.content.SharedPreferences
-
-/** [SharedPreferences] based [KeyedDataObservable]. */
-class SharedPreferencesObservable(private val sharedPreferences: SharedPreferences) :
- KeyedDataObservable<String>(), AutoCloseable {
-
- private val listener = createSharedPreferenceListener()
-
- init {
- sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
- }
-
- override fun close() {
- sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener)
- }
-}
-
-/** Creates [SharedPreferences.OnSharedPreferenceChangeListener] for [KeyedObservable]. */
-internal fun KeyedObservable<String>.createSharedPreferenceListener() =
- SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
- if (key != null) {
- notifyChange(key, DataChangeReason.UPDATE)
- } else {
- // On Android >= R, SharedPreferences.Editor.clear() will trigger this case
- notifyChange(DataChangeReason.DELETE)
- }
- }
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
index 5ceee6d09978..7aece5185800 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
@@ -22,11 +22,13 @@ import com.android.settingslib.graph.proto.PreferenceGraphProto
import com.android.settingslib.ipc.ApiHandler
import com.android.settingslib.ipc.MessageCodec
import com.android.settingslib.metadata.PreferenceScreenRegistry
+import com.android.settingslib.preference.PreferenceScreenProvider
import java.util.Locale
/** API to get preference graph. */
-abstract class GetPreferenceGraphApiHandler :
- ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
+abstract class GetPreferenceGraphApiHandler(
+ private val preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>>
+) : ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
override val requestCodec: MessageCodec<GetPreferenceGraphRequest>
get() = GetPreferenceGraphRequestCodec
@@ -40,14 +42,16 @@ abstract class GetPreferenceGraphApiHandler :
callingUid: Int,
request: GetPreferenceGraphRequest,
): PreferenceGraphProto {
- val builderRequest =
- if (request.screenKeys.isEmpty()) {
- val keys = PreferenceScreenRegistry.preferenceScreens.keys
- GetPreferenceGraphRequest(keys, request.visitedScreens, request.locale)
- } else {
- request
+ val builder = PreferenceGraphBuilder.of(application, myUid, callingUid, request)
+ if (request.screenKeys.isEmpty()) {
+ for (key in PreferenceScreenRegistry.preferenceScreens.keys) {
+ builder.addPreferenceScreenFromRegistry(key)
}
- return PreferenceGraphBuilder.of(application, builderRequest).build()
+ for (provider in preferenceScreenProviders) {
+ builder.addPreferenceScreenProvider(provider)
+ }
+ }
+ return builder.build()
}
}
@@ -64,16 +68,18 @@ constructor(
val screenKeys: Set<String> = setOf(),
val visitedScreens: Set<String> = setOf(),
val locale: Locale? = null,
- val includeValue: Boolean = true,
+ val flags: Int = PreferenceGetterFlags.ALL,
+ val includeValue: Boolean = true, // TODO: clean up
val includeValueDescriptor: Boolean = true,
)
object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest> {
override fun encode(data: GetPreferenceGraphRequest): Bundle =
- Bundle(3).apply {
+ Bundle(4).apply {
putStringArray(KEY_SCREEN_KEYS, data.screenKeys.toTypedArray())
putStringArray(KEY_VISITED_KEYS, data.visitedScreens.toTypedArray())
putString(KEY_LOCALE, data.locale?.toLanguageTag())
+ putInt(KEY_FLAGS, data.flags)
}
override fun decode(data: Bundle): GetPreferenceGraphRequest {
@@ -84,12 +90,14 @@ object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest>
screenKeys.toSet(),
visitedScreens.toSet(),
data.getString(KEY_LOCALE).toLocale(),
+ data.getInt(KEY_FLAGS),
)
}
private const val KEY_SCREEN_KEYS = "k"
private const val KEY_VISITED_KEYS = "v"
private const val KEY_LOCALE = "l"
+ private const val KEY_FLAGS = "f"
}
object PreferenceGraphProtoCodec : MessageCodec<PreferenceGraphProto> {
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceCoordinate.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceCoordinate.kt
new file mode 100644
index 000000000000..68aa2d258295
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceCoordinate.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Coordinate to locate a preference.
+ *
+ * Within an app, the preference screen key (unique among screens) plus preference key (unique on
+ * the screen) is used to locate a preference.
+ */
+data class PreferenceCoordinate(val screenKey: String, val key: String) : Parcelable {
+
+ constructor(parcel: Parcel) : this(parcel.readString()!!, parcel.readString()!!)
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeString(screenKey)
+ parcel.writeString(key)
+ }
+
+ override fun describeContents() = 0
+
+ companion object CREATOR : Parcelable.Creator<PreferenceCoordinate> {
+
+ override fun createFromParcel(parcel: Parcel) = PreferenceCoordinate(parcel)
+
+ override fun newArray(size: Int) = arrayOfNulls<PreferenceCoordinate>(size)
+ }
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt
new file mode 100644
index 000000000000..c8453efb9161
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+import android.app.Application
+import androidx.annotation.IntDef
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.ipc.ApiDescriptor
+import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.ApiPermissionChecker
+import com.android.settingslib.metadata.PreferenceHierarchyNode
+import com.android.settingslib.metadata.PreferenceScreenRegistry
+
+/**
+ * Request to get preference information.
+ *
+ * @param preferences coordinate of preferences
+ * @param flags a combination of constants in [PreferenceGetterFlags]
+ */
+class PreferenceGetterRequest(val preferences: Array<PreferenceCoordinate>, val flags: Int)
+
+/** Error code of preference getter request. */
+@Target(AnnotationTarget.TYPE)
+@IntDef(
+ PreferenceGetterErrorCode.NOT_FOUND,
+ PreferenceGetterErrorCode.DISALLOW,
+ PreferenceGetterErrorCode.INTERNAL_ERROR,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class PreferenceGetterErrorCode {
+ companion object {
+ /** Preference is not found. */
+ const val NOT_FOUND = 1
+ /** Disallow to get preference value (e.g. uid not allowed). */
+ const val DISALLOW = 2
+ /** Internal error happened when get preference information. */
+ const val INTERNAL_ERROR = 3
+
+ fun getMessage(code: Int) =
+ when (code) {
+ NOT_FOUND -> "Preference not found"
+ DISALLOW -> "Disallow to get preference value"
+ INTERNAL_ERROR -> "Internal error"
+ else -> "Unknown error"
+ }
+ }
+}
+
+/** Response of the getter API. */
+class PreferenceGetterResponse(
+ val errors: Map<PreferenceCoordinate, @PreferenceGetterErrorCode Int>,
+ val preferences: Map<PreferenceCoordinate, PreferenceProto>,
+)
+
+/** Preference getter API descriptor. */
+class PreferenceGetterApiDescriptor(override val id: Int) :
+ ApiDescriptor<PreferenceGetterRequest, PreferenceGetterResponse> {
+
+ override val requestCodec = PreferenceGetterRequestCodec()
+
+ override val responseCodec = PreferenceGetterResponseCodec()
+}
+
+/** Preference getter API implementation. */
+class PreferenceGetterApiHandler(
+ override val id: Int,
+ private val permissionChecker: ApiPermissionChecker<PreferenceGetterRequest>,
+) : ApiHandler<PreferenceGetterRequest, PreferenceGetterResponse> {
+
+ override fun hasPermission(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: PreferenceGetterRequest,
+ ) = permissionChecker.hasPermission(application, myUid, callingUid, request)
+
+ override suspend fun invoke(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: PreferenceGetterRequest,
+ ): PreferenceGetterResponse {
+ val errors = mutableMapOf<PreferenceCoordinate, Int>()
+ val preferences = mutableMapOf<PreferenceCoordinate, PreferenceProto>()
+ val flags = request.flags
+ for ((screenKey, coordinates) in request.preferences.groupBy { it.screenKey }) {
+ val screenMetadata = PreferenceScreenRegistry[screenKey]
+ if (screenMetadata == null) {
+ for (coordinate in coordinates) {
+ errors[coordinate] = PreferenceGetterErrorCode.NOT_FOUND
+ }
+ continue
+ }
+ val nodes = mutableMapOf<String, PreferenceHierarchyNode?>()
+ for (coordinate in coordinates) nodes[coordinate.key] = null
+ screenMetadata.getPreferenceHierarchy(application).forEachRecursively {
+ val metadata = it.metadata
+ val key = metadata.key
+ if (nodes.containsKey(key)) nodes[key] = it
+ }
+ for (coordinate in coordinates) {
+ val node = nodes[coordinate.key]
+ if (node == null) {
+ errors[coordinate] = PreferenceGetterErrorCode.NOT_FOUND
+ continue
+ }
+ val metadata = node.metadata
+ try {
+ val preferenceProto =
+ metadata.toProto(
+ application,
+ myUid,
+ callingUid,
+ screenMetadata,
+ metadata.key == screenMetadata.key,
+ flags,
+ )
+ if (flags == PreferenceGetterFlags.VALUE && !preferenceProto.hasValue()) {
+ errors[coordinate] = PreferenceGetterErrorCode.DISALLOW
+ } else {
+ preferences[coordinate] = preferenceProto
+ }
+ } catch (e: Exception) {
+ errors[coordinate] = PreferenceGetterErrorCode.INTERNAL_ERROR
+ }
+ }
+ }
+ return PreferenceGetterResponse(errors, preferences)
+ }
+
+ override val requestCodec = PreferenceGetterRequestCodec()
+
+ override val responseCodec = PreferenceGetterResponseCodec()
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterCodecs.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterCodecs.kt
new file mode 100644
index 000000000000..ff14eb5aae55
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterCodecs.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+import android.os.Bundle
+import android.os.Parcel
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.ipc.MessageCodec
+import java.util.Arrays
+
+/** Message codec for [PreferenceGetterRequest]. */
+class PreferenceGetterRequestCodec : MessageCodec<PreferenceGetterRequest> {
+ override fun encode(data: PreferenceGetterRequest) =
+ Bundle(2).apply {
+ putParcelableArray(null, data.preferences)
+ putInt(FLAGS, data.flags)
+ }
+
+ @Suppress("DEPRECATION")
+ override fun decode(data: Bundle): PreferenceGetterRequest {
+ data.classLoader = PreferenceCoordinate::class.java.classLoader
+ val array = data.getParcelableArray(null)!!
+
+ return PreferenceGetterRequest(
+ Arrays.copyOf(array, array.size, Array<PreferenceCoordinate>::class.java),
+ data.getInt(FLAGS),
+ )
+ }
+
+ companion object {
+ private const val FLAGS = "f"
+ }
+}
+
+/** Message codec for [PreferenceGetterResponse]. */
+class PreferenceGetterResponseCodec : MessageCodec<PreferenceGetterResponse> {
+ override fun encode(data: PreferenceGetterResponse) =
+ Bundle(2).apply {
+ data.errors.toErrorsByteArray()?.let { putByteArray(ERRORS, it) }
+ data.preferences.toPreferencesByteArray()?.let { putByteArray(null, it) }
+ }
+
+ private fun Map<PreferenceCoordinate, Int>.toErrorsByteArray(): ByteArray? {
+ if (isEmpty()) return null
+ val parcel = Parcel.obtain()
+ parcel.writeInt(size)
+ for ((coordinate, code) in this) {
+ coordinate.writeToParcel(parcel, 0)
+ parcel.writeInt(code)
+ }
+ val bytes = parcel.marshall()
+ parcel.recycle()
+ return bytes
+ }
+
+ private fun Map<PreferenceCoordinate, PreferenceProto>.toPreferencesByteArray(): ByteArray? {
+ if (isEmpty()) return null
+ val parcel = Parcel.obtain()
+ parcel.writeInt(size)
+ for ((coordinate, preferenceProto) in this) {
+ coordinate.writeToParcel(parcel, 0)
+ val data = preferenceProto.toByteArray()
+ parcel.writeInt(data.size)
+ parcel.writeByteArray(data)
+ }
+ val bytes = parcel.marshall()
+ parcel.recycle()
+ return bytes
+ }
+
+ override fun decode(data: Bundle) =
+ PreferenceGetterResponse(
+ data.getByteArray(ERRORS).toErrors(),
+ data.getByteArray(null).toPreferences(),
+ )
+
+ private fun ByteArray?.toErrors(): Map<PreferenceCoordinate, Int> {
+ if (this == null) return emptyMap()
+ val parcel = Parcel.obtain()
+ parcel.unmarshall(this, 0, size)
+ parcel.setDataPosition(0)
+ val count = parcel.readInt()
+ val errors = mutableMapOf<PreferenceCoordinate, Int>()
+ repeat(count) {
+ val coordinate = PreferenceCoordinate(parcel)
+ errors[coordinate] = parcel.readInt()
+ }
+ parcel.recycle()
+ return errors
+ }
+
+ private fun ByteArray?.toPreferences(): Map<PreferenceCoordinate, PreferenceProto> {
+ if (this == null) return emptyMap()
+ val parcel = Parcel.obtain()
+ parcel.unmarshall(this, 0, size)
+ parcel.setDataPosition(0)
+ val count = parcel.readInt()
+ val preferences = mutableMapOf<PreferenceCoordinate, PreferenceProto>()
+ repeat(count) {
+ val coordinate = PreferenceCoordinate(parcel)
+ val bytes = parcel.readInt()
+ val array = ByteArray(bytes).also { parcel.readByteArray(it) }
+ preferences[coordinate] = PreferenceProto.parseFrom(array)
+ }
+ parcel.recycle()
+ return preferences
+ }
+
+ companion object {
+ private const val ERRORS = "e"
+ }
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterFlags.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterFlags.kt
new file mode 100644
index 000000000000..632f154b72ab
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterFlags.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+/** Flags for preference getter operation. */
+object PreferenceGetterFlags {
+ const val VALUE = 1 shl 0
+ const val VALUE_DESCRIPTOR = 1 shl 1
+ const val METADATA = 1 shl 2
+ const val ALL = (1 shl 3) - 1
+
+ fun Int.includeValue() = (this and VALUE) != 0
+
+ fun Int.includeValueDescriptor() = (this and VALUE_DESCRIPTOR) != 0
+
+ fun Int.includeMetadata() = (this and METADATA) != 0
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
index 2256bb38dd2c..a65d24cf3d6f 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -31,6 +31,9 @@ import androidx.preference.Preference
import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceScreen
import androidx.preference.TwoStatePreference
+import com.android.settingslib.graph.PreferenceGetterFlags.includeMetadata
+import com.android.settingslib.graph.PreferenceGetterFlags.includeValue
+import com.android.settingslib.graph.PreferenceGetterFlags.includeValueDescriptor
import com.android.settingslib.graph.proto.PreferenceGraphProto
import com.android.settingslib.graph.proto.PreferenceGroupProto
import com.android.settingslib.graph.proto.PreferenceProto
@@ -41,7 +44,6 @@ import com.android.settingslib.metadata.BooleanValue
import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceHierarchy
-import com.android.settingslib.metadata.PreferenceHierarchyNode
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.PreferenceRestrictionProvider
import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider
@@ -50,6 +52,7 @@ import com.android.settingslib.metadata.PreferenceScreenRegistry
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.PreferenceTitleProvider
import com.android.settingslib.metadata.RangeValue
+import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.preference.PreferenceScreenFactory
import com.android.settingslib.preference.PreferenceScreenProvider
import java.util.Locale
@@ -60,14 +63,17 @@ private const val TAG = "PreferenceGraphBuilder"
/** Builder of preference graph. */
class PreferenceGraphBuilder
-private constructor(private val context: Context, private val request: GetPreferenceGraphRequest) {
+private constructor(
+ private val context: Context,
+ private val myUid: Int,
+ private val callingUid: Int,
+ private val request: GetPreferenceGraphRequest,
+) {
private val preferenceScreenFactory by lazy {
PreferenceScreenFactory(context.ofLocale(request.locale))
}
private val builder by lazy { PreferenceGraphProto.newBuilder() }
private val visitedScreens = mutableSetOf<String>().apply { addAll(request.visitedScreens) }
- private val includeValue = request.includeValue
- private val includeValueDescriptor = request.includeValueDescriptor
private suspend fun init() {
for (key in request.screenKeys) {
@@ -133,7 +139,7 @@ private constructor(private val context: Context, private val request: GetPrefer
null
}
- private suspend fun addPreferenceScreenFromRegistry(key: String): Boolean {
+ suspend fun addPreferenceScreenFromRegistry(key: String): Boolean {
val metadata = PreferenceScreenRegistry[key] ?: return false
return addPreferenceScreenMetadata(metadata)
}
@@ -146,7 +152,7 @@ private constructor(private val context: Context, private val request: GetPrefer
}
}
- private suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
+ suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
Log.d(TAG, "add $activityClass")
createPreferenceScreen { activityClass.newInstance() }
?.let {
@@ -229,7 +235,7 @@ private constructor(private val context: Context, private val request: GetPrefer
enabled = isEnabled
available = isVisible
persistent = isPersistent
- if (includeValue && isPersistent && this@toProto is TwoStatePreference) {
+ if (request.flags.includeValue() && isPersistent && this@toProto is TwoStatePreference) {
value = preferenceValueProto { booleanValue = this@toProto.isChecked }
}
this@toProto.fragment.toActionTarget(preferenceExtras)?.let {
@@ -243,14 +249,14 @@ private constructor(private val context: Context, private val request: GetPrefer
screenMetadata: PreferenceScreenMetadata,
isRoot: Boolean,
): PreferenceGroupProto = preferenceGroupProto {
- preference = toProto(screenMetadata, this@toProto, isRoot)
+ preference = toProto(screenMetadata, this@toProto.metadata, isRoot)
forEachAsync {
addPreferences(
preferenceOrGroupProto {
if (it is PreferenceHierarchy) {
group = it.toProto(screenMetadata, false)
} else {
- preference = toProto(screenMetadata, it, false)
+ preference = toProto(screenMetadata, it.metadata, false)
}
}
)
@@ -259,93 +265,19 @@ private constructor(private val context: Context, private val request: GetPrefer
private suspend fun toProto(
screenMetadata: PreferenceScreenMetadata,
- node: PreferenceHierarchyNode,
+ metadata: PreferenceMetadata,
isRoot: Boolean,
- ) = preferenceProto {
- val metadata = node.metadata
- key = metadata.key
- metadata.getTitleTextProto(isRoot)?.let { title = it }
- if (metadata.summary != 0) {
- summary = textProto { resourceId = metadata.summary }
- } else {
- (metadata as? PreferenceSummaryProvider)?.getSummary(context)?.let {
- summary = textProto { string = it.toString() }
- }
- }
- val metadataIcon = metadata.getPreferenceIcon(context)
- if (metadataIcon != 0) icon = metadataIcon
- if (metadata.keywords != 0) keywords = metadata.keywords
- val preferenceExtras = metadata.extras(context)
- preferenceExtras?.let { extras = it.toProto() }
- indexable = metadata.isIndexable(context)
- enabled = metadata.isEnabled(context)
- if (metadata is PreferenceAvailabilityProvider) {
- available = metadata.isAvailable(context)
- }
- if (metadata is PreferenceRestrictionProvider) {
- restricted = metadata.isRestricted(context)
- }
- persistent = metadata.isPersistent(context)
- if (persistent) {
- if (includeValue && metadata is PersistentPreference<*>) {
- value = preferenceValueProto {
- when (metadata) {
- is BooleanValue ->
- metadata
- .storage(context)
- .getValue(metadata.key, Boolean::class.javaObjectType)
- ?.let { booleanValue = it }
- is RangeValue -> {
- metadata
- .storage(context)
- .getValue(metadata.key, Int::class.javaObjectType)
- ?.let { intValue = it }
- }
- else -> {}
- }
- }
+ ) =
+ metadata.toProto(context, myUid, callingUid, screenMetadata, isRoot, request.flags).also {
+ if (metadata is PreferenceScreenMetadata) {
+ @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata)
}
- if (includeValueDescriptor) {
- valueDescriptor = preferenceValueDescriptorProto {
- when (metadata) {
- is BooleanValue -> booleanType = true
- is RangeValue -> rangeValue = rangeValueProto {
- min = metadata.getMinValue(context)
- max = metadata.getMaxValue(context)
- step = metadata.getIncrementStep(context)
- }
- else -> {}
- }
+ metadata.intent(context)?.resolveActivity(context.packageManager)?.let {
+ if (it.packageName == context.packageName) {
+ add(it.className)
}
}
}
- if (metadata is PreferenceScreenMetadata) {
- @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata)
- }
- metadata.intent(context)?.let { actionTarget = it.toActionTarget() }
- screenMetadata.getLaunchIntent(context, metadata)?.let { launchIntent = it.toProto() }
- }
-
- private fun PreferenceMetadata.getTitleTextProto(isRoot: Boolean): TextProto? {
- if (isRoot && this is PreferenceScreenMetadata) {
- val titleRes = screenTitle
- if (titleRes != 0) {
- return textProto { resourceId = titleRes }
- } else {
- getScreenTitle(context)?.let {
- return textProto { string = it.toString() }
- }
- }
- } else {
- val titleRes = title
- if (titleRes != 0) {
- return textProto { resourceId = titleRes }
- }
- }
- return (this as? PreferenceTitleProvider)?.getTitle(context)?.let {
- textProto { string = it.toString() }
- }
- }
private suspend fun String?.toActionTarget(extras: Bundle?): ActionTarget? {
if (this.isNullOrEmpty()) return null
@@ -399,22 +331,129 @@ private constructor(private val context: Context, private val request: GetPrefer
return null
}
- private suspend fun Intent.toActionTarget(): ActionTarget {
- if (component?.packageName == "") {
- setClassName(context, component!!.className)
+ private suspend fun Intent.toActionTarget() =
+ toActionTarget(context).also {
+ resolveActivity(context.packageManager)?.let {
+ if (it.packageName == context.packageName) {
+ add(it.className)
+ }
+ }
}
- resolveActivity(context.packageManager)?.let {
- if (it.packageName == context.packageName) {
- add(it.className)
+
+ companion object {
+ suspend fun of(
+ context: Context,
+ myUid: Int,
+ callingUid: Int,
+ request: GetPreferenceGraphRequest,
+ ) = PreferenceGraphBuilder(context, myUid, callingUid, request).also { it.init() }
+ }
+}
+
+fun PreferenceMetadata.toProto(
+ context: Context,
+ myUid: Int,
+ callingUid: Int,
+ screenMetadata: PreferenceScreenMetadata,
+ isRoot: Boolean,
+ flags: Int,
+) = preferenceProto {
+ val metadata = this@toProto
+ key = metadata.key
+ if (flags.includeMetadata()) {
+ metadata.getTitleTextProto(context, isRoot)?.let { title = it }
+ if (metadata.summary != 0) {
+ summary = textProto { resourceId = metadata.summary }
+ } else {
+ (metadata as? PreferenceSummaryProvider)?.getSummary(context)?.let {
+ summary = textProto { string = it.toString() }
}
}
- return actionTargetProto { intent = toProto() }
+ val metadataIcon = metadata.getPreferenceIcon(context)
+ if (metadataIcon != 0) icon = metadataIcon
+ if (metadata.keywords != 0) keywords = metadata.keywords
+ val preferenceExtras = metadata.extras(context)
+ preferenceExtras?.let { extras = it.toProto() }
+ indexable = metadata.isIndexable(context)
+ enabled = metadata.isEnabled(context)
+ if (metadata is PreferenceAvailabilityProvider) {
+ available = metadata.isAvailable(context)
+ }
+ if (metadata is PreferenceRestrictionProvider) {
+ restricted = metadata.isRestricted(context)
+ }
+ metadata.intent(context)?.let { actionTarget = it.toActionTarget(context) }
+ screenMetadata.getLaunchIntent(context, metadata)?.let { launchIntent = it.toProto() }
}
+ persistent = metadata.isPersistent(context)
+ if (persistent) {
+ if (
+ flags.includeValue() &&
+ enabled &&
+ (!hasAvailable() || available) &&
+ (!hasRestricted() || !restricted) &&
+ metadata is PersistentPreference<*> &&
+ metadata.getReadPermit(context, myUid, callingUid) == ReadWritePermit.ALLOW
+ ) {
+ value = preferenceValueProto {
+ when (metadata) {
+ is BooleanValue ->
+ metadata
+ .storage(context)
+ .getValue(metadata.key, Boolean::class.javaObjectType)
+ ?.let { booleanValue = it }
+ is RangeValue -> {
+ metadata
+ .storage(context)
+ .getValue(metadata.key, Int::class.javaObjectType)
+ ?.let { intValue = it }
+ }
+ else -> {}
+ }
+ }
+ }
+ if (flags.includeValueDescriptor()) {
+ valueDescriptor = preferenceValueDescriptorProto {
+ when (metadata) {
+ is BooleanValue -> booleanType = true
+ is RangeValue -> rangeValue = rangeValueProto {
+ min = metadata.getMinValue(context)
+ max = metadata.getMaxValue(context)
+ step = metadata.getIncrementStep(context)
+ }
+ else -> {}
+ }
+ }
+ }
+ }
+}
- companion object {
- suspend fun of(context: Context, request: GetPreferenceGraphRequest) =
- PreferenceGraphBuilder(context, request).also { it.init() }
+private fun PreferenceMetadata.getTitleTextProto(context: Context, isRoot: Boolean): TextProto? {
+ if (isRoot && this is PreferenceScreenMetadata) {
+ val titleRes = screenTitle
+ if (titleRes != 0) {
+ return textProto { resourceId = titleRes }
+ } else {
+ getScreenTitle(context)?.let {
+ return textProto { string = it.toString() }
+ }
+ }
+ } else {
+ val titleRes = title
+ if (titleRes != 0) {
+ return textProto { resourceId = titleRes }
+ }
+ }
+ return (this as? PreferenceTitleProvider)?.getTitle(context)?.let {
+ textProto { string = it.toString() }
+ }
+}
+
+private fun Intent.toActionTarget(context: Context): ActionTarget {
+ if (component?.packageName == "") {
+ setClassName(context, component!!.className)
}
+ return actionTargetProto { intent = toProto() }
}
@SuppressLint("AppBundleLocaleChanges")
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
index 6e4db1d90484..7cfce0d85cd4 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
@@ -22,6 +22,7 @@ import androidx.annotation.IntDef
import com.android.settingslib.graph.proto.PreferenceValueProto
import com.android.settingslib.ipc.ApiDescriptor
import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.ApiPermissionChecker
import com.android.settingslib.ipc.IntMessageCodec
import com.android.settingslib.ipc.MessageCodec
import com.android.settingslib.metadata.BooleanValue
@@ -45,7 +46,11 @@ data class PreferenceSetterRequest(
PreferenceSetterResult.OK,
PreferenceSetterResult.UNSUPPORTED,
PreferenceSetterResult.DISABLED,
+ PreferenceSetterResult.RESTRICTED,
PreferenceSetterResult.UNAVAILABLE,
+ PreferenceSetterResult.REQUIRE_APP_PERMISSION,
+ PreferenceSetterResult.REQUIRE_USER_AGREEMENT,
+ PreferenceSetterResult.DISALLOW,
PreferenceSetterResult.INVALID_REQUEST,
PreferenceSetterResult.INTERNAL_ERROR,
)
@@ -87,14 +92,17 @@ class PreferenceSetterApiDescriptor(override val id: Int) :
}
/** Preference setter API implementation. */
-class PreferenceSetterApiHandler(override val id: Int) : ApiHandler<PreferenceSetterRequest, Int> {
+class PreferenceSetterApiHandler(
+ override val id: Int,
+ private val permissionChecker: ApiPermissionChecker<PreferenceSetterRequest>,
+) : ApiHandler<PreferenceSetterRequest, Int> {
override fun hasPermission(
application: Application,
myUid: Int,
callingUid: Int,
request: PreferenceSetterRequest,
- ): Boolean = true
+ ) = permissionChecker.hasPermission(application, myUid, callingUid, request)
override suspend fun invoke(
application: Application,
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
index d9b9590f60e2..1bda277f2018 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
@@ -16,8 +16,10 @@
package com.android.settingslib.graph
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.net.Uri
import android.os.Bundle
import com.android.settingslib.graph.proto.BundleProto
import com.android.settingslib.graph.proto.BundleProto.BundleValue
@@ -42,6 +44,20 @@ fun Intent.toProto(): IntentProto = intentProto {
this@toProto.type?.let { mimeType = it }
}
+fun IntentProto.toIntent(): Intent? {
+ if (!hasComponent()) return null
+ val componentName = ComponentName.unflattenFromString(component) ?: return null
+ val intent = Intent()
+ intent.component = componentName
+ if (hasAction()) intent.action = action
+ if (hasData()) intent.data = Uri.parse(data)
+ if (hasPkg()) intent.`package` = pkg
+ if (hasFlags()) intent.flags = flags
+ if (hasExtras()) intent.putExtras(extras.toBundle())
+ if (hasMimeType()) intent.setType(mimeType)
+ return intent
+}
+
fun Bundle.toProto(): BundleProto = bundleProto {
fun toProto(value: Any): BundleValue = bundleValueProto {
when (value) {
@@ -61,14 +77,18 @@ fun Bundle.toProto(): BundleProto = bundleProto {
}
}
-fun BundleValue.stringify(): String =
- when {
- hasBooleanValue() -> "$valueCase"
- hasBytesValue() -> "$bytesValue"
- hasIntValue() -> "$intValue"
- hasLongValue() -> "$longValue"
- hasStringValue() -> stringValue
- hasDoubleValue() -> "$doubleValue"
- hasBundleValue() -> "$bundleValue"
- else -> "Unknown"
+fun BundleProto.toBundle(): Bundle =
+ Bundle().apply {
+ for ((key, value) in valuesMap) {
+ when {
+ value.hasBooleanValue() -> putBoolean(key, value.booleanValue)
+ value.hasBytesValue() -> putByteArray(key, value.bytesValue.toByteArray())
+ value.hasIntValue() -> putInt(key, value.intValue)
+ value.hasLongValue() -> putLong(key, value.longValue)
+ value.hasStringValue() -> putString(key, value.stringValue)
+ value.hasDoubleValue() -> putDouble(key, value.doubleValue)
+ value.hasBundleValue() -> putBundle(key, value.bundleValue.toBundle())
+ else -> throw IllegalArgumentException("Unknown type: ${value.javaClass} $value")
+ }
+ }
}
diff --git a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
index 0cdfc6610bbd..81337612e59a 100644
--- a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
+++ b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
@@ -31,7 +31,7 @@ class IntroPreference @JvmOverloads constructor(
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0
-) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin {
private var isCollapsable: Boolean = false
private var minLines: Int = 2
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
index 802141dae7ec..4febd89a7da4 100644
--- a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
@@ -56,6 +56,27 @@ interface ApiDescriptor<Request, Response> {
val responseCodec: MessageCodec<Response>
}
+/** Permission checker for api. */
+fun interface ApiPermissionChecker<R> {
+ /**
+ * Returns if the request is permitted.
+ *
+ * @param application application context
+ * @param myUid uid of current process
+ * @param callingUid uid of peer process
+ * @param request API request
+ * @return `false` if permission is denied, otherwise `true`
+ */
+ fun hasPermission(application: Application, myUid: Int, callingUid: Int, request: R): Boolean
+
+ companion object {
+ private val ALWAYS_ALLOW = ApiPermissionChecker<Any> { _, _, _, _ -> true }
+
+ @Suppress("UNCHECKED_CAST")
+ fun <T> alwaysAllow(): ApiPermissionChecker<T> = ALWAYS_ALLOW as ApiPermissionChecker<T>
+ }
+}
+
/**
* Handler of API.
*
@@ -64,18 +85,8 @@ interface ApiDescriptor<Request, Response> {
*
* The implementation must be threadsafe.
*/
-interface ApiHandler<Request, Response> : ApiDescriptor<Request, Response> {
- /**
- * Returns if the request is permitted.
- *
- * @return `false` if permission is denied, otherwise `true`
- */
- fun hasPermission(
- application: Application,
- myUid: Int,
- callingUid: Int,
- request: Request,
- ): Boolean
+interface ApiHandler<Request, Response> :
+ ApiDescriptor<Request, Response>, ApiPermissionChecker<Request> {
/**
* Invokes the API.
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
index 7ffefed239a4..ef907e17d824 100644
--- a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
@@ -320,6 +320,11 @@ constructor(
}
}
+ override fun onNullBinding(name: ComponentName) {
+ Log.i(TAG, "onNullBinding $name")
+ close(ClientBindServiceException(null))
+ }
+
internal open fun drainPendingRequests() {
disposableHandle = null
if (pendingRequests.isEmpty()) {
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt
index bde4217b3962..9179f8ffc082 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt
@@ -58,6 +58,9 @@ class PreferenceHierarchy internal constructor(metadata: PreferenceMetadata) :
/** Specifies preference order in the hierarchy. */
infix fun PreferenceHierarchyNode.order(order: Int) = apply { this.order = order }
+ /** Specifies preference order in the hierarchy for group. */
+ infix fun PreferenceHierarchy.order(order: Int) = apply { this.order = order }
+
/** Adds a preference to the hierarchy. */
@JvmOverloads
fun add(metadata: PreferenceMetadata, order: Int? = null) {
@@ -166,10 +169,6 @@ class PreferenceHierarchy internal constructor(metadata: PreferenceMetadata) :
}
return null
}
-
- /** Returns all the [PreferenceHierarchyNode]s appear in the hierarchy. */
- fun getAllPreferences(): List<PreferenceHierarchyNode> =
- mutableListOf<PreferenceHierarchyNode>().apply { forEachRecursively { add(it) } }
}
/**
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
index 43d7dfa4a158..a3709c109111 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
@@ -133,8 +133,11 @@ interface PreferenceLifecycleProvider {
*/
abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(context) {
- /** Notifies that preference state is changed and update preference widget UI. */
- abstract fun notifyPreferenceChange(preference: PreferenceMetadata)
+ /** Returns the preference widget object associated with given key. */
+ abstract fun <T> findPreference(key: String): T?
+
+ /** Notifies that preference state of given key is changed and updates preference widget UI. */
+ abstract fun notifyPreferenceChange(key: String)
/**
* Starts activity for result, see [android.app.Activity.startActivityForResult].
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
index 49acc1d44144..6b7be91c1903 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
@@ -108,6 +108,9 @@ interface PreferenceBinding {
}
}
+/** Interface indicates that a virtual [Preference] should be created for binding. */
+interface PreferenceBindingPlaceholder
+
/** Abstract preference screen to provide preference hierarchy and binding factory. */
interface PreferenceScreenCreator : PreferenceScreenMetadata, PreferenceScreenProvider {
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
index fbe892710d40..62ac3ade62a4 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
@@ -57,8 +57,11 @@ class PreferenceScreenBindingHelper(
private val preferenceLifecycleContext =
object : PreferenceLifecycleContext(context) {
- override fun notifyPreferenceChange(preference: PreferenceMetadata) =
- notifyChange(preference.key, CHANGE_REASON_STATE)
+ override fun <T> findPreference(key: String) =
+ preferenceScreen.findPreference(key) as T?
+
+ override fun notifyPreferenceChange(key: String) =
+ notifyChange(key, CHANGE_REASON_STATE)
@Suppress("DEPRECATION")
override fun startActivityForResult(
@@ -218,34 +221,47 @@ class PreferenceScreenBindingHelper(
preferenceScreen: PreferenceScreen,
preferenceBindingFactory: PreferenceBindingFactory,
preferenceHierarchy: PreferenceHierarchy,
- ) =
- preferenceScreen.bindRecursively(
- preferenceBindingFactory,
- preferenceHierarchy.getAllPreferences().associateBy { it.metadata.key },
- )
-
- private fun PreferenceGroup.bindRecursively(
- preferenceBindingFactory: PreferenceBindingFactory,
- preferences: Map<String, PreferenceHierarchyNode>,
- storages: MutableMap<KeyValueStore, PreferenceDataStore> = mutableMapOf(),
) {
- preferences[key]?.let { preferenceBindingFactory.bind(this, it) }
- val count = preferenceCount
- for (index in 0 until count) {
- val preference = getPreference(index)
- if (preference is PreferenceGroup) {
- preference.bindRecursively(preferenceBindingFactory, preferences, storages)
- } else {
- preferences[preference.key]?.let {
- val metadata = it.metadata
- (metadata as? PersistentPreference<*>)?.storage(context)?.let { storage ->
- preference.preferenceDataStore =
- storages.getOrPut(storage) { PreferenceDataStoreAdapter(storage) }
+ val preferences = mutableMapOf<String, PreferenceHierarchyNode>()
+ preferenceHierarchy.forEachRecursively {
+ val metadata = it.metadata
+ preferences[metadata.key] = it
+ }
+ val storages = mutableMapOf<KeyValueStore, PreferenceDataStore>()
+
+ fun Preference.setPreferenceDataStore(metadata: PreferenceMetadata) {
+ (metadata as? PersistentPreference<*>)?.storage(context)?.let { storage ->
+ preferenceDataStore =
+ storages.getOrPut(storage) { PreferenceDataStoreAdapter(storage) }
+ }
+ }
+
+ fun PreferenceGroup.bindRecursively() {
+ preferences.remove(key)?.let { preferenceBindingFactory.bind(this, it) }
+ val count = preferenceCount
+ for (index in 0 until count) {
+ val preference = getPreference(index)
+ if (preference is PreferenceGroup) {
+ preference.bindRecursively()
+ } else {
+ preferences.remove(preference.key)?.let {
+ preference.setPreferenceDataStore(it.metadata)
+ preferenceBindingFactory.bind(preference, it)
}
- preferenceBindingFactory.bind(preference, it)
}
}
}
+
+ preferenceScreen.bindRecursively()
+ for (node in preferences.values) {
+ val metadata = node.metadata
+ val binding = preferenceBindingFactory.getPreferenceBinding(metadata)
+ if (binding !is PreferenceBindingPlaceholder) continue
+ val preference = binding.createWidget(preferenceScreen.context)
+ preference.setPreferenceDataStore(metadata)
+ preferenceBindingFactory.bind(preference, node, binding)
+ preferenceScreen.addPreference(preference)
+ }
}
}
}
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml
index ca17836f6cf4..db7f687f23b5 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml
@@ -19,5 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"व्यक्तिगत"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"कामसम्बन्धी"</string>
- <string name="settingslib_category_private" msgid="5039276873477591386">"निजी"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"निजी स्पेस"</string>
</resources>
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
index 6e38df11156f..1823ba641775 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
@@ -19,9 +19,14 @@ package com.android.settingslib.service
import android.app.Application
import com.android.settingslib.graph.GetPreferenceGraphApiHandler
import com.android.settingslib.graph.GetPreferenceGraphRequest
+import com.android.settingslib.ipc.ApiPermissionChecker
+import com.android.settingslib.preference.PreferenceScreenProvider
/** Api to get preference graph. */
-internal class PreferenceGraphApi : GetPreferenceGraphApiHandler() {
+internal class PreferenceGraphApi(
+ preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>>,
+ private val permissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>,
+) : GetPreferenceGraphApiHandler(preferenceScreenProviders) {
override val id: Int
get() = API_GET_PREFERENCE_GRAPH
@@ -31,5 +36,5 @@ internal class PreferenceGraphApi : GetPreferenceGraphApiHandler() {
myUid: Int,
callingUid: Int,
request: GetPreferenceGraphRequest,
- ) = true
+ ) = permissionChecker.hasPermission(application, myUid, callingUid, request)
}
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
index 8ebb14522c3d..7cb36db856eb 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
@@ -16,10 +16,16 @@
package com.android.settingslib.service
+import com.android.settingslib.graph.GetPreferenceGraphRequest
+import com.android.settingslib.graph.PreferenceGetterApiHandler
+import com.android.settingslib.graph.PreferenceGetterRequest
import com.android.settingslib.graph.PreferenceSetterApiHandler
+import com.android.settingslib.graph.PreferenceSetterRequest
import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.ApiPermissionChecker
import com.android.settingslib.ipc.MessengerService
import com.android.settingslib.ipc.PermissionChecker
+import com.android.settingslib.preference.PreferenceScreenProvider
/**
* Preference service providing a bunch of APIs.
@@ -28,14 +34,25 @@ import com.android.settingslib.ipc.PermissionChecker
* [PREFERENCE_SERVICE_ACTION].
*/
open class PreferenceService(
- permissionChecker: PermissionChecker,
name: String = "PreferenceService",
+ permissionChecker: PermissionChecker = PermissionChecker { _, _, _ -> true },
+ preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>> = setOf(),
+ graphPermissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>? = null,
+ setterPermissionChecker: ApiPermissionChecker<PreferenceSetterRequest>? = null,
+ getterPermissionChecker: ApiPermissionChecker<PreferenceGetterRequest>? = null,
+ vararg apiHandlers: ApiHandler<*, *>,
) :
MessengerService(
- listOf<ApiHandler<*, *>>(
- PreferenceGraphApi(),
- PreferenceSetterApiHandler(API_PREFERENCE_SETTER),
- ),
+ mutableListOf<ApiHandler<*, *>>().apply {
+ graphPermissionChecker?.let { add(PreferenceGraphApi(preferenceScreenProviders, it)) }
+ setterPermissionChecker?.let {
+ add(PreferenceSetterApiHandler(API_PREFERENCE_SETTER, it))
+ }
+ getterPermissionChecker?.let {
+ add(PreferenceGetterApiHandler(API_PREFERENCE_GETTER, it))
+ }
+ addAll(apiHandlers)
+ },
permissionChecker,
name,
)
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
index 1f38a6678eae..d71405e126ce 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
@@ -18,5 +18,17 @@ package com.android.settingslib.service
const val PREFERENCE_SERVICE_ACTION = "com.android.settingslib.PREFERENCE_SERVICE"
+/** API id for retrieving preference graph. */
internal const val API_GET_PREFERENCE_GRAPH = 1
+
+/** API id for preference value setter. */
internal const val API_PREFERENCE_SETTER = 2
+
+/** API id for preference getter. */
+internal const val API_PREFERENCE_GETTER = 3
+
+/**
+ * The max API id reserved for internal preference service usages. Custom API id should start with
+ * **1000** to avoid conflict.
+ */
+internal const val API_MAX_RESERVED = 999
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
index b46181e20eaa..8b574aa95176 100644
--- a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!--Deprecated. After sdk 35, don't use it, using materialColorOnSurfaceInverse in light theme -->
+<!--Deprecated. After sdk 35, don't use it, using materialColorInverseOnSurface in light theme -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/system_neutral1_500" android:lStar="98" />
</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml
new file mode 100644
index 000000000000..2539aa040a60
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml
new file mode 100644
index 000000000000..2fc65f0cb149
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Ծավալել"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ծալել"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml
new file mode 100644
index 000000000000..4e7287c4eedd
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"開く"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"閉じる"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml
new file mode 100644
index 000000000000..3fc1fcc728a7
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ಕುಗ್ಗಿಸಿ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml
new file mode 100644
index 000000000000..db9d42280528
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"विस्तार करा"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"कोलॅप्स करा"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 313748d8f091..46ec62e7a5ef 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -51,7 +51,7 @@
<color name="settingslib_text_color_preference_category_title">@android:color/system_accent1_100</color>
- <!--Deprecated. After sdk 35, don't use it, using materialColorOnSurfaceInverse in dark theme -->
+ <!--Deprecated. After sdk 35, don't use it, using materialColorInverseOnSurface in dark theme -->
<color name="settingslib_surface_dark">@android:color/system_neutral1_800</color>
<!--Deprecated. After sdk 35, don't use it-->
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
index 94ff02d898db..84a3ed68af01 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
@@ -53,11 +53,11 @@
<color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_dark</color>
<color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_dark</color>
<color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_dark</color>
- <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_light</color>
+ <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_light</color>
<color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_dark</color>
<color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_dark</color>
- <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_light</color>
- <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_light</color>
+ <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_light</color>
+ <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_light</color>
<color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_dark</color>
<color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_dark</color>
<color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_dark</color>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml
new file mode 100644
index 000000000000..48a756b81c9c
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ਸਮੇਟੋ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000000..58bd936a8bae
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expandir"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Reduzir"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml
new file mode 100644
index 000000000000..6fd67c59ff3d
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Razširi"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Strni"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml
new file mode 100644
index 000000000000..4a0fb4d96e03
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"விரிவாக்கும்"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"சுருக்கும்"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-te/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-te/strings.xml
new file mode 100644
index 000000000000..706e225560c1
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-te/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"విస్తరించండి"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"కుదించండి"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml
new file mode 100644
index 000000000000..ef5825ff1c3e
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"I-expand"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"I-collapse"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml
new file mode 100644
index 000000000000..2e020b4e0676
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"پھیلائیں"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"سکیڑیں"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml
new file mode 100644
index 000000000000..16e389b88405
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Yoyish"</string>
+ <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Yopish"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index b99ee5123491..fef92b792bec 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -67,9 +67,9 @@
<color name="settingslib_accent_primary_variant">@android:color/system_accent1_600</color>
<!--Deprecated. After sdk 35 don't use it.-->
<color name="settingslib_accent_secondary_device_default">@android:color/system_accent2_100</color>
- <!--Deprecated. After sdk 35 don't use it.using materialColorOnSurfaceInverse in dark theme-->
+ <!--Deprecated. After sdk 35 don't use it.using materialColorInverseOnSurface in dark theme-->
<color name="settingslib_background_device_default_dark">@android:color/system_neutral1_900</color>
- <!--Deprecated. After sdk 35 don't use it. using materialColorOnSurfaceInverse in light theme-->
+ <!--Deprecated. After sdk 35 don't use it. using materialColorInverseOnSurface in light theme-->
<color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color>
<!--Deprecated. After sdk 35 don't use it. using materialColorOnSurface-->
<color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_900</color>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
index 8b9501608000..90c19e1aa676 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
@@ -66,16 +66,16 @@
<color name="settingslib_materialColorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</color>
<color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_light</color>
<color name="settingslib_materialColorOnSecondaryFixed">@android:color/system_on_secondary_fixed</color>
- <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_dark</color>
+ <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_dark</color>
<color name="settingslib_materialColorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</color>
<color name="settingslib_materialColorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</color>
<color name="settingslib_materialColorPrimaryFixedDim">@android:color/system_primary_fixed_dim</color>
<color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_light</color>
<color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_light</color>
<color name="settingslib_materialColorOnPrimaryFixed">@android:color/system_on_primary_fixed</color>
- <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_dark</color>
+ <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_dark</color>
<color name="settingslib_materialColorSecondaryFixed">@android:color/system_secondary_fixed</color>
- <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_dark</color>
+ <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_dark</color>
<color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_light</color>
<color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_light</color>
<color name="settingslib_materialColorTertiaryFixed">@android:color/system_tertiary_fixed</color>
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt
index 4d3a78a583fc..f2bc380a93de 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt
@@ -17,8 +17,12 @@
package com.android.settingslib.spa.gallery.ui
import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -30,6 +34,7 @@ import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SimplePreferenceMacro
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Category
+import com.android.settingslib.spa.widget.ui.LazyCategory
private const val TITLE = "Sample Category"
@@ -65,7 +70,7 @@ object CategoryPageProvider : SettingsPageProvider {
)
entryList.add(
SettingsEntryBuilder.create("Preference 3", owner)
- .setMacro { SimplePreferenceMacro(title = "Preference 2", summary = "Summary 3") }
+ .setMacro { SimplePreferenceMacro(title = "Preference 3", summary = "Summary 3") }
.build()
)
entryList.add(
@@ -88,6 +93,13 @@ object CategoryPageProvider : SettingsPageProvider {
entries[2].UiLayout()
entries[3].UiLayout()
}
+ Column(Modifier.height(200.dp)) {
+ LazyCategory(
+ list = entries,
+ entry = { index: Int -> @Composable { entries[index].UiLayout() } },
+ title = { index: Int -> if (index == 0 || index == 2) "LazyCategory" else null },
+ ) {}
+ }
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt
index e883a4a55af9..25bb46c837f6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt
@@ -25,3 +25,36 @@ fun Modifier.contentDescription(contentDescription: String?) =
if (contentDescription != null) this.semantics {
this.contentDescription = contentDescription
} else this
+
+/**
+ * Concatenates this modifier with another if `condition` is true.
+ *
+ * This method allows inline conditional addition of modifiers to a modifier chain. Instead of
+ * writing
+ *
+ * ```
+ * val aModifier = Modifier.a()
+ * val bModifier = if(condition) aModifier.b() else aModifier
+ * Composable(modifier = bModifier)
+ * ```
+ *
+ * You can instead write
+ *
+ * ```
+ * Composable(modifier = Modifier.a().thenIf(condition){
+ * Modifier.b()
+ * }
+ * ```
+ *
+ * This makes the modifier chain easier to read.
+ *
+ * Note that unlike the non-factory version, the conditional modifier is recreated each time, and
+ * may never be created at all.
+ *
+ * @param condition Whether or not to apply the modifiers.
+ * @param factory Creates the modifier to concatenate with the current one.
+ * @return a Modifier representing this modifier followed by other in sequence.
+ * @see Modifier.then
+ */
+inline fun Modifier.thenIf(condition: Boolean, crossinline factory: () -> Modifier): Modifier =
+ if (condition) this.then(factory()) else this
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
index acb96be64a34..b1bb79d61b03 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
@@ -36,12 +36,13 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.min
+import com.android.settingslib.spa.framework.compose.thenIf
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsOpacity.alphaForEnabled
import com.android.settingslib.spa.framework.theme.SettingsShape
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
+import com.android.settingslib.spa.widget.ui.LocalIsInCategory
import com.android.settingslib.spa.widget.ui.SettingsTitle
@Composable
@@ -57,18 +58,18 @@ internal fun BaseLayout(
paddingVertical: Dp = SettingsDimension.itemPaddingVertical,
widget: @Composable () -> Unit = {},
) {
+ val surfaceBright = MaterialTheme.colorScheme.surfaceBright
Row(
modifier =
modifier
.fillMaxWidth()
.semantics(mergeDescendants = true) {}
- .then(
- if (isSpaExpressiveEnabled)
- Modifier.heightIn(min = SettingsDimension.preferenceMinHeight)
- .clip(SettingsShape.CornerExtraSmall)
- .background(MaterialTheme.colorScheme.surfaceBright)
- else Modifier
- )
+ .thenIf(isSpaExpressiveEnabled) {
+ Modifier.heightIn(min = SettingsDimension.preferenceMinHeight)
+ }
+ .thenIf(isSpaExpressiveEnabled && LocalIsInCategory.current) {
+ Modifier.clip(SettingsShape.CornerExtraSmall).background(surfaceBright)
+ }
.padding(end = paddingEnd),
verticalAlignment = Alignment.CenterVertically,
) {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
index 66680fa547b1..96d2abb70391 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
@@ -19,13 +19,20 @@ package com.android.settingslib.spa.widget.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.TouchApp
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -34,6 +41,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsShape
@@ -93,11 +101,63 @@ fun Category(title: String? = null, content: @Composable ColumnScope.() -> Unit)
verticalArrangement =
if (isSpaExpressiveEnabled) Arrangement.spacedBy(SettingsDimension.paddingTiny)
else Arrangement.Top,
- content = content,
+ content = { CompositionLocalProvider(LocalIsInCategory provides true) { content() } },
)
}
}
+/**
+ * A container that is used to group items with lazy loading.
+ *
+ * @param list The list of items to display.
+ * @param entry The entry for each list item according to its index in list.
+ * @param key Optional. The key for each item in list to provide unique item identifiers, making the
+ * list more efficient.
+ * @param title Optional. Category title for each item or each group of items in the list. It should
+ * be decided by the index.
+ * @param bottomPadding Optional. Bottom outside padding of the category.
+ * @param state Optional. State of LazyList.
+ * @param content Optional. Content to be shown at the top of the category.
+ */
+@Composable
+fun LazyCategory(
+ list: List<Any>,
+ entry: (Int) -> @Composable () -> Unit,
+ key: ((Int) -> Any)? = null,
+ title: ((Int) -> String?)? = null,
+ bottomPadding: Dp = SettingsDimension.paddingSmall,
+ state: LazyListState = rememberLazyListState(),
+ content: @Composable () -> Unit,
+) {
+ Column(
+ Modifier.padding(
+ PaddingValues(
+ start = SettingsDimension.paddingLarge,
+ end = SettingsDimension.paddingLarge,
+ top = SettingsDimension.paddingSmall,
+ bottom = bottomPadding,
+ )
+ )
+ .clip(SettingsShape.CornerMedium2)
+ ) {
+ LazyColumn(
+ modifier = Modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.spacedBy(SettingsDimension.paddingTiny),
+ state = state,
+ ) {
+ item { CompositionLocalProvider(LocalIsInCategory provides true) { content() } }
+
+ items(count = list.size, key = key) {
+ title?.invoke(it)?.let { title -> CategoryTitle(title) }
+ CompositionLocalProvider(LocalIsInCategory provides true) { entry(it)() }
+ }
+ }
+ }
+}
+
+/** LocalIsInCategory containing the if the current composable is in a category. */
+internal val LocalIsInCategory = compositionLocalOf { false }
+
@Preview
@Composable
private fun CategoryPreview() {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt
index 09a6e6ddc7f0..4b4a8c20b39e 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt
@@ -16,10 +16,16 @@
package com.android.settingslib.spa.widget.ui
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.height
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -30,14 +36,11 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class CategoryTest {
- @get:Rule
- val composeTestRule = createComposeRule()
+ @get:Rule val composeTestRule = createComposeRule()
@Test
fun categoryTitle() {
- composeTestRule.setContent {
- CategoryTitle(title = "CategoryTitle")
- }
+ composeTestRule.setContent { CategoryTitle(title = "CategoryTitle") }
composeTestRule.onNodeWithText("CategoryTitle").assertIsDisplayed()
}
@@ -46,12 +49,14 @@ class CategoryTest {
fun category_hasContent_titleDisplayed() {
composeTestRule.setContent {
Category(title = "CategoryTitle") {
- Preference(remember {
- object : PreferenceModel {
- override val title = "Some Preference"
- override val summary = { "Some summary" }
+ Preference(
+ remember {
+ object : PreferenceModel {
+ override val title = "Some Preference"
+ override val summary = { "Some summary" }
+ }
}
- })
+ )
}
}
@@ -60,10 +65,45 @@ class CategoryTest {
@Test
fun category_noContent_titleNotDisplayed() {
- composeTestRule.setContent {
- Category(title = "CategoryTitle") {}
- }
+ composeTestRule.setContent { Category(title = "CategoryTitle") {} }
composeTestRule.onNodeWithText("CategoryTitle").assertDoesNotExist()
}
+
+ @Test
+ fun lazyCategory_content_displayed() {
+ composeTestRule.setContent { TestLazyCategory() }
+
+ composeTestRule.onNodeWithText("text").assertExists()
+ }
+
+ @Test
+ fun lazyCategory_title_displayed() {
+ composeTestRule.setContent { TestLazyCategory() }
+
+ composeTestRule.onNodeWithText("LazyCategory 0").assertExists()
+ composeTestRule.onNodeWithText("LazyCategory 1").assertDoesNotExist()
+ }
+}
+
+@Composable
+private fun TestLazyCategory() {
+ val list: List<PreferenceModel> =
+ listOf(
+ object : PreferenceModel {
+ override val title = "title"
+ },
+ object : PreferenceModel {
+ override val title = "title"
+ },
+ )
+ Column(Modifier.height(200.dp)) {
+ LazyCategory(
+ list = list,
+ entry = { index: Int -> @Composable { Preference(list[index]) } },
+ title = { index: Int -> if (index == 0) "LazyCategory $index" else null },
+ ) {
+ Text("text")
+ }
+ }
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
index bededf03a0f4..2a214b6f74a6 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
@@ -37,7 +37,9 @@ import com.android.settingslib.spa.framework.compose.LifecycleEffect
import com.android.settingslib.spa.framework.compose.LogCompositions
import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer
import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
import com.android.settingslib.spa.widget.ui.CategoryTitle
+import com.android.settingslib.spa.widget.ui.LazyCategory
import com.android.settingslib.spa.widget.ui.PlaceholderTitle
import com.android.settingslib.spa.widget.ui.Spinner
import com.android.settingslib.spa.widget.ui.SpinnerOption
@@ -55,19 +57,14 @@ import kotlinx.coroutines.flow.MutableStateFlow
private const val TAG = "AppList"
private const val CONTENT_TYPE_HEADER = "header"
-/**
- * The config used to load the App List.
- */
+/** The config used to load the App List. */
data class AppListConfig(
val userIds: List<Int>,
val showInstantApps: Boolean,
val matchAnyUserForAdmin: Boolean,
)
-data class AppListState(
- val showSystem: () -> Boolean,
- val searchQuery: () -> String,
-)
+data class AppListState(val showSystem: () -> Boolean, val searchQuery: () -> String)
data class AppListInput<T : AppRecord>(
val config: AppListConfig,
@@ -90,7 +87,7 @@ fun <T : AppRecord> AppListInput<T>.AppList() {
@Composable
internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
- viewModelSupplier: @Composable () -> IAppListViewModel<T>,
+ viewModelSupplier: @Composable () -> IAppListViewModel<T>
) {
LogCompositions(TAG, config.userIds.toString())
val viewModel = viewModelSupplier()
@@ -125,7 +122,7 @@ private fun <T : AppRecord> AppListModel<T>.AppListWidget(
appListData: State<AppListData<T>?>,
header: @Composable () -> Unit,
bottomPadding: Dp,
- noItemMessage: String?
+ noItemMessage: String?,
) {
val timeMeasurer = rememberTimeMeasurer(TAG)
appListData.value?.let { (list, option) ->
@@ -135,40 +132,61 @@ private fun <T : AppRecord> AppListModel<T>.AppListWidget(
PlaceholderTitle(noItemMessage ?: stringResource(R.string.no_applications))
return
}
- LazyColumn(
- modifier = Modifier.fillMaxSize(),
- state = rememberLazyListStateAndHideKeyboardWhenStartScroll(),
- contentPadding = PaddingValues(bottom = bottomPadding),
- ) {
- item(contentType = CONTENT_TYPE_HEADER) {
+ if (isSpaExpressiveEnabled) {
+ LazyCategory(
+ list = list,
+ entry = { index: Int ->
+ @Composable {
+ val appEntry = list[index]
+ val summary = getSummary(option, appEntry.record) ?: { "" }
+ remember(appEntry) {
+ AppListItemModel(appEntry.record, appEntry.label, summary)
+ }
+ .AppItem()
+ }
+ },
+ key = { index: Int -> list[index].record.itemKey(option) },
+ title = { index: Int -> getGroupTitle(option, list[index].record) },
+ bottomPadding = bottomPadding,
+ state = rememberLazyListStateAndHideKeyboardWhenStartScroll(),
+ ) {
header()
}
-
- items(count = list.size, key = { list[it].record.itemKey(option) }) {
- remember(list) { getGroupTitleIfFirst(option, list, it) }
- ?.let { group -> CategoryTitle(title = group) }
-
- val appEntry = list[it]
- val summary = getSummary(option, appEntry.record) ?: { "" }
- remember(appEntry) {
- AppListItemModel(appEntry.record, appEntry.label, summary)
- }.AppItem()
+ } else {
+ LazyColumn(
+ modifier = Modifier.fillMaxSize(),
+ state = rememberLazyListStateAndHideKeyboardWhenStartScroll(),
+ contentPadding = PaddingValues(bottom = bottomPadding),
+ ) {
+ item(contentType = CONTENT_TYPE_HEADER) { header() }
+
+ items(count = list.size, key = { list[it].record.itemKey(option) }) {
+ remember(list) { getGroupTitleIfFirst(option, list, it) }
+ ?.let { group -> CategoryTitle(title = group) }
+
+ val appEntry = list[it]
+ val summary = getSummary(option, appEntry.record) ?: { "" }
+ remember(appEntry) {
+ AppListItemModel(appEntry.record, appEntry.label, summary)
+ }
+ .AppItem()
+ }
}
}
}
}
-private fun <T : AppRecord> T.itemKey(option: Int) =
- listOf(option, app.packageName, app.userId)
+private fun <T : AppRecord> T.itemKey(option: Int) = listOf(option, app.packageName, app.userId)
/** Returns group title if this is the first item of the group. */
private fun <T : AppRecord> AppListModel<T>.getGroupTitleIfFirst(
option: Int,
list: List<AppEntry<T>>,
index: Int,
-): String? = getGroupTitle(option, list[index].record)?.takeIf {
- index == 0 || it != getGroupTitle(option, list[index - 1].record)
-}
+): String? =
+ getGroupTitle(option, list[index].record)?.takeIf {
+ index == 0 || it != getGroupTitle(option, list[index - 1].record)
+ }
@Composable
private fun <T : AppRecord> rememberViewModel(
@@ -183,16 +201,19 @@ private fun <T : AppRecord> rememberViewModel(
viewModel.searchQuery.Sync(state.searchQuery)
LifecycleEffect(onStart = { viewModel.reloadApps() })
- val intentFilter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
- addAction(Intent.ACTION_PACKAGE_REMOVED)
- addAction(Intent.ACTION_PACKAGE_CHANGED)
- addDataScheme("package")
- }
+ val intentFilter =
+ IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
+ addAction(Intent.ACTION_PACKAGE_REMOVED)
+ addAction(Intent.ACTION_PACKAGE_CHANGED)
+ addDataScheme("package")
+ }
for (userId in config.userIds) {
DisposableBroadcastReceiverAsUser(
intentFilter = intentFilter,
userHandle = UserHandle.of(userId),
- ) { viewModel.reloadApps() }
+ ) {
+ viewModel.reloadApps()
+ }
}
return viewModel
}
diff --git a/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
index ea033a39f766..7d366f3091bc 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
+++ b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
@@ -22,9 +22,9 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical"
- android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
- android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingBottom="16dp">
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingBottom="@dimen/settingslib_expressive_space_small1">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index bf419cc46aeb..076f82acce09 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -171,3 +171,10 @@ flag {
description: "Enable the user consent prompt before writing sensitive preferences via service"
bug: "378552675"
}
+
+flag {
+ name: "hearing_devices_input_routing_control"
+ namespace: "accessibility"
+ description: "Enable the input routing control in device details and hearing devices dialog."
+ bug: "349255906"
+}
diff --git a/packages/SettingsLib/res/drawable/ic_bt_le_audio_sharing.xml b/packages/SettingsLib/res/drawable/ic_bt_le_audio_sharing.xml
index 618677389ce1..91275707ac02 100644
--- a/packages/SettingsLib/res/drawable/ic_bt_le_audio_sharing.xml
+++ b/packages/SettingsLib/res/drawable/ic_bt_le_audio_sharing.xml
@@ -15,73 +15,12 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:height="24dp"
- android:width="24dp"
- android:viewportHeight="24"
- android:viewportWidth="24"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#000000"
- android:pathData="M16.984,24H7.279L12.131,15.508L16.984,24ZM10.481,22.144H13.781L12.131,19.257L10.481,22.144Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M12.131,14.295C13.471,14.295 14.558,13.209 14.558,11.869C14.558,10.529 13.471,9.442 12.131,9.442C10.791,9.442 9.705,10.529 9.705,11.869C9.705,13.209 10.791,14.295 12.131,14.295Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M4.573,21.368C4.052,20.943 3.967,20.179 4.379,19.657C4.804,19.136 5.568,19.051 6.09,19.463C6.611,19.876 6.696,20.64 6.284,21.174C6.041,21.465 5.689,21.623 5.338,21.623C5.071,21.623 4.804,21.538 4.573,21.368Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M17.991,21.162C17.579,20.628 17.663,19.876 18.185,19.451C18.707,19.039 19.471,19.124 19.896,19.646C20.308,20.167 20.223,20.931 19.702,21.344C19.471,21.526 19.204,21.611 18.949,21.611C18.586,21.611 18.234,21.453 17.991,21.162Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M1.213,17.145C0.91,16.551 1.165,15.823 1.771,15.532C2.378,15.241 3.093,15.495 3.397,16.09C3.688,16.697 3.433,17.424 2.827,17.715C2.657,17.8 2.475,17.837 2.305,17.837C1.844,17.837 1.419,17.582 1.213,17.145Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M21.449,17.691C20.842,17.4 20.588,16.684 20.879,16.077C21.17,15.471 21.898,15.216 22.504,15.507C23.099,15.798 23.354,16.526 23.062,17.133C22.856,17.557 22.419,17.812 21.971,17.812C21.789,17.812 21.619,17.776 21.449,17.691Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M0,11.892C0,11.225 0.546,10.679 1.213,10.679C1.88,10.679 2.426,11.212 2.426,11.892C2.426,12.559 1.88,13.105 1.213,13.105C0.546,13.105 0,12.559 0,11.892Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M21.837,11.869C21.837,11.857 21.837,11.845 21.837,11.833C21.824,11.153 22.37,10.62 23.05,10.607C23.717,10.607 24.251,11.153 24.263,11.821C24.263,11.833 24.263,11.845 24.263,11.845C24.263,11.857 24.263,11.869 24.263,11.869C24.263,12.536 23.717,13.082 23.05,13.082C22.382,13.082 21.837,12.536 21.837,11.869Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M1.759,8.242C1.152,7.963 0.898,7.235 1.189,6.628C1.48,6.022 2.196,5.767 2.802,6.058C3.409,6.349 3.664,7.077 3.372,7.684C3.166,8.108 2.729,8.363 2.281,8.363C2.099,8.363 1.929,8.327 1.759,8.242Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M20.866,7.622C20.563,7.028 20.818,6.3 21.424,6.009C22.019,5.706 22.747,5.96 23.038,6.567C23.038,6.567 23.038,6.567 23.05,6.567C23.341,7.161 23.087,7.889 22.48,8.181C22.31,8.265 22.128,8.302 21.958,8.302C21.509,8.302 21.073,8.059 20.866,7.622Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M4.355,4.104C3.931,3.582 4.016,2.818 4.537,2.406C5.071,1.981 5.823,2.066 6.248,2.588C6.672,3.109 6.588,3.874 6.066,4.298C5.835,4.48 5.569,4.565 5.302,4.565C4.95,4.565 4.598,4.407 4.355,4.104Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M18.161,4.262C17.627,3.838 17.542,3.073 17.955,2.552C18.379,2.03 19.132,1.945 19.666,2.358C20.187,2.77 20.272,3.534 19.86,4.068C19.617,4.359 19.265,4.517 18.913,4.517C18.646,4.517 18.379,4.432 18.161,4.262Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M8.492,1.497C8.334,0.854 8.747,0.199 9.402,0.041C10.057,-0.105 10.7,0.308 10.858,0.963C11.003,1.606 10.591,2.261 9.948,2.407C9.851,2.431 9.754,2.443 9.669,2.443C9.123,2.443 8.613,2.067 8.492,1.497Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M14.267,2.395C13.599,2.249 13.199,1.606 13.345,0.951C13.49,0.296 14.133,-0.116 14.788,0.029C15.443,0.175 15.856,0.83 15.71,1.485C15.589,2.043 15.08,2.431 14.534,2.431C14.437,2.431 14.352,2.419 14.267,2.395Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M7,17.037C6.527,16.564 6.527,15.8 7,15.326C7.473,14.841 8.237,14.841 8.71,15.314C9.196,15.787 9.196,16.552 8.723,17.025C8.48,17.267 8.177,17.389 7.861,17.389C7.546,17.389 7.242,17.267 7,17.037Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M15.565,17.012C15.092,16.539 15.092,15.762 15.565,15.289C16.038,14.816 16.814,14.816 17.288,15.289C17.761,15.762 17.761,16.539 17.288,17.012C17.045,17.243 16.742,17.364 16.426,17.364C16.111,17.364 15.807,17.243 15.565,17.012Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M4.853,11.917C4.853,11.237 5.386,10.691 6.054,10.691C6.721,10.691 7.279,11.225 7.279,11.892C7.279,12.56 6.745,13.106 6.078,13.118C5.398,13.118 4.853,12.584 4.853,11.917Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M16.984,11.868C16.984,11.856 16.984,11.844 16.984,11.832C16.984,11.832 16.984,11.82 16.984,11.807C16.972,11.14 17.506,10.582 18.185,10.582C18.852,10.57 19.398,11.116 19.41,11.783C19.41,11.795 19.41,11.82 19.41,11.832C19.41,11.844 19.41,11.856 19.41,11.868C19.41,12.535 18.865,13.081 18.197,13.081C17.53,13.081 16.984,12.535 16.984,11.868Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M6.952,8.471C6.478,7.997 6.478,7.233 6.952,6.76C6.952,6.76 6.952,6.76 6.939,6.76C7.413,6.275 8.189,6.275 8.662,6.748C9.135,7.221 9.147,7.985 8.674,8.458C8.432,8.701 8.116,8.822 7.813,8.822C7.497,8.822 7.194,8.701 6.952,8.471Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M15.529,8.399C15.043,7.938 15.043,7.161 15.504,6.688C15.977,6.203 16.742,6.203 17.227,6.664C17.7,7.137 17.712,7.901 17.239,8.387C17.009,8.629 16.693,8.751 16.378,8.751C16.075,8.751 15.759,8.629 15.529,8.399Z"/>
- <path
- android:fillColor="#000000"
- android:pathData="M10.87,5.815C10.858,5.148 11.392,4.59 12.071,4.59C12.738,4.578 13.284,5.124 13.284,5.791C13.296,6.458 12.762,7.016 12.083,7.016C11.416,7.016 10.87,6.483 10.87,5.815Z"/>
-</vector>
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="?android:attr/colorControlNormal"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M320,880L480,596L640,880L320,880ZM480,560Q447,560 423.5,536.5Q400,513 400,480Q400,447 423.5,423.5Q447,400 480,400Q513,400 536.5,423.5Q560,447 560,480Q560,513 536.5,536.5Q513,560 480,560ZM339,661Q322,661 310.5,649.5Q299,638 299,621Q299,604 310.5,592.5Q322,581 339,581Q356,581 367.5,592.5Q379,604 379,621Q379,638 367.5,649.5Q356,661 339,661ZM280,520Q263,520 251.5,508.5Q240,497 240,480Q240,463 251.5,451.5Q263,440 280,440Q297,440 308.5,451.5Q320,463 320,480Q320,497 308.5,508.5Q297,520 280,520ZM339,379Q322,379 310.5,367.5Q299,356 299,339Q299,322 310.5,310.5Q322,299 339,299Q356,299 367.5,310.5Q379,322 379,339Q379,356 367.5,367.5Q356,379 339,379ZM480,320Q463,320 451.5,308.5Q440,297 440,280Q440,263 451.5,251.5Q463,240 480,240Q497,240 508.5,251.5Q520,263 520,280Q520,297 508.5,308.5Q497,320 480,320ZM621,379Q604,379 592.5,367.5Q581,356 581,339Q581,322 592.5,310.5Q604,299 621,299Q638,299 649.5,310.5Q661,322 661,339Q661,356 649.5,367.5Q638,379 621,379ZM680,520Q663,520 651.5,508.5Q640,497 640,480Q640,463 651.5,451.5Q663,440 680,440Q697,440 708.5,451.5Q720,463 720,480Q720,497 708.5,508.5Q697,520 680,520ZM621,661Q604,661 592.5,649.5Q581,638 581,621Q581,604 592.5,592.5Q604,581 621,581Q638,581 649.5,592.5Q661,604 661,621Q661,638 649.5,649.5Q638,661 621,661ZM255,801Q238,801 226,788.5Q214,776 214,759Q214,742 226,730Q238,718 255,718Q272,718 284.5,730Q297,742 297,759Q297,776 284.5,788.5Q272,801 255,801ZM156,676Q139,676 127.5,664Q116,652 116,635Q116,618 127.5,606.5Q139,595 156,595Q173,595 185,606.5Q197,618 197,635Q197,652 185,664Q173,676 156,676ZM120,520Q103,520 91.5,508.5Q80,497 80,480Q80,463 91.5,451.5Q103,440 120,440Q137,440 148.5,451.5Q160,463 160,480Q160,497 148.5,508.5Q137,520 120,520ZM156,363Q139,363 127.5,351.5Q116,340 116,323Q116,306 127.5,294.5Q139,283 156,283Q173,283 184.5,294.5Q196,306 196,323Q196,340 184.5,351.5Q173,363 156,363ZM256,239Q239,239 227.5,227.5Q216,216 216,199Q216,182 227.5,170.5Q239,159 256,159Q273,159 284.5,170.5Q296,182 296,199Q296,216 284.5,227.5Q273,239 256,239ZM400,169Q383,169 371.5,157.5Q360,146 360,129Q360,112 371.5,100.5Q383,89 400,89Q417,89 428.5,100.5Q440,112 440,129Q440,146 428.5,157.5Q417,169 400,169ZM560,169Q543,169 531.5,157.5Q520,146 520,129Q520,112 531.5,100.5Q543,89 560,89Q577,89 588.5,100.5Q600,112 600,129Q600,146 588.5,157.5Q577,169 560,169ZM705,239Q688,239 676.5,227.5Q665,216 665,199Q665,182 676.5,170.5Q688,159 705,159Q722,159 733.5,170.5Q745,182 745,199Q745,216 733.5,227.5Q722,239 705,239ZM805,364Q788,364 776.5,352.5Q765,341 765,324Q765,307 776.5,295.5Q788,284 805,284Q822,284 833.5,295.5Q845,307 845,324Q845,341 833.5,352.5Q822,364 805,364ZM840,520Q823,520 811.5,508.5Q800,497 800,480Q800,463 811.5,451.5Q823,440 840,440Q857,440 868.5,451.5Q880,463 880,480Q880,497 868.5,508.5Q857,520 840,520ZM805,676Q788,676 776.5,664.5Q765,653 765,636Q765,619 776.5,607.5Q788,596 805,596Q822,596 833.5,607.5Q845,619 845,636Q845,653 833.5,664.5Q822,676 805,676ZM705,801Q688,801 676.5,789.5Q665,778 665,761Q665,744 676.5,732.5Q688,721 705,721Q722,721 733.5,732.5Q745,744 745,761Q745,778 733.5,789.5Q722,801 705,801Z" />
+</vector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_tv_box_internal_speaker.xml b/packages/SettingsLib/res/drawable/ic_tv_box_internal_speaker.xml
new file mode 100644
index 000000000000..2a90e051b83b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_tv_box_internal_speaker.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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:attr/textColorPrimary"
+ android:autoMirrored="true">
+ <path android:fillColor="#FFFFFFFF"
+ android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 6f6a357a4a95..322598574f26 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Plaaslike terminaal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktiveer terminaalprogram wat plaaslike skermtoegang bied"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-ontwikkelingomgewing"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Laat loop Linux-terminaal op Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimenteel) Laat Linux-terminale op Android loop"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"As jy deaktiveer, sal Linux se terminale data uitgevee word"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-kontrolering"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Stel HDCP-kontrolering se gedrag"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Ontfouting"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Eksterne toestel"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Gekoppelde toestel"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Hierdie foon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analoog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AANVULLENDE"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan nie op hierdie toestel speel nie"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Gradeer rekening op om oor te skakel"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Kan nie aflaaie hier speel nie"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4d7731c5dd45..34f37b47fae6 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"አካባቢያዊ ተርሚናል"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"የአካባቢያዊ ሼል መዳረሻ የሚያቀርብ የተርሚናል መተግበሪያ አንቃ"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"የLinux ግንባታ አከባቢ"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android ላይ Linux ተርሚናል ያሂዱ"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(የሙከራ) Android ላይ Linux ተርሚናል ያሂዱ"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ካሰናከሉ የLinux ተርሚናል ውሂብ ይሰርዛል"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"የHDCP ምልከታ"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"የHDCP መመልከቻ ጠባይ አዘጋጅ"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ስህተት በማስወገድ ላይ"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"የውጭ መሣሪያ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"የተገናኘ መሣሪያ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ይህ ስልክ"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"አናሎግ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"ተጨማሪ"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"በዚህ መሣሪያ ላይ ማጫወት አልተቻለም"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ለመቀየር መለያ ያልቁ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ውርዶችን እዚህ ማጫወት አይቻልም"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 8b8131342b7d..2ea1486ace31 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"تطبيق طرفي محلي"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"تفعيل تطبيق طرفي يوفر إمكانية الدخول إلى واجهة النظام المحلية"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"‏بيئة تطوير نظام التشغيل Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"‏تشغيل محطة Linux الطرفية على Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"‏(تجريبي) تشغيل تطبيق وحدة Linux الطرفية على Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"‏في حال إيقاف تطبيق وحدة Linux الطرفية، سيتم محو بياناتها"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"‏التحقق من HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"‏تعيين سلوك التحقق من HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"تصحيح الأخطاء"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"جهاز خارجي"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"جهاز متّصل"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"هذا الهاتف"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"مصدر إخراج صوت تناظري"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"لا يمكن تشغيل الوسائط هنا"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"يجب ترقية الحساب للتبديل"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"المحتوى المنزَّل غير متوافق"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 02324de0276f..432d443a5045 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"স্থানীয় টাৰ্মিনেল"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"স্থানীয় শ্বেলৰ এক্সেছ দিয়া টাৰ্মিনেল এপ্ সক্ষম কৰক"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux বিকাশৰ পৰিৱেশ"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Androidত Linux টাৰ্মিনেল চলাওক"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(পৰীক্ষামূলক) Androidত Linux টাৰ্মিনেল চলাওক"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"আপুনি যদি অক্ষম কৰে, Linux টাৰ্মিনেলৰ ডেটা মচি পেলোৱা হ’ব"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP পৰীক্ষণ"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP পৰীক্ষণ আচৰণ ছেট কৰক"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ডিবাগিং"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"বাহ্যিক ডিভাইচ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"সংযোগ হৈ থকা ডিভাইচ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফ’নটো"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"এনালগ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"অক্স"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"এই ডিভাইচটো প্লে\' কৰিব নোৱাৰি"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"সলনি কৰিবলৈ একাউণ্ট আপগ্ৰে’ড কৰক"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ইয়াত ডাউনল’ডসমূহ প্লে’ কৰিব নোৱাৰি"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 25e85d53cdce..330532ec48b0 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Yerli terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Yerli örtük girişini təklif edən terminal tətbiqi aktiv edin"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux inkişaf mühiti"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android-də Linux terminalını işə salın"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Təcrübi) Android-də Linux terminalını işlədin"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Deaktiv etsəniz, Linux terminal datası silinəcək"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP yoxlanışı"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP yoxlanışı qaydası ayalansın"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Sazlama"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Xarici cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Qoşulmuş cihaz"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analoq"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu cihazda oxutmaq olmur"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Keçirmək üçün hesabı güncəllə"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Burada endirmələri oxutmaq olmur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 4214a4016965..4dfd25302708 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Omogući apl. terminala za pristup lokalnom komandnom okruženju"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux okruženje za programiranje"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Pokrenite Linux terminal na Android-u"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimentalno) Pokrenite Linux terminal na Android-u"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ako onemogućite, podaci Linux terminala se brišu"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP provera"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Podešavanje ponašanja HDCP provere"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Otklanjanje grešaka"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Spoljni uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogni"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ne možete da pustite na ovom uređaju"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite nalog radi prebacivanja"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Preuzimanja ne mogu da se puštaju ovde"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 3e645b3f1ae0..de25460e4cbc 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Лакальны тэрмінал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Уключэнне прыкладання тэрмінала, якое прапануе доступ да лакальнай абалонкі"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Асяроддзе распрацоўкі Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Запусціць тэрмінал Linux на прыладзе Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"Запусціць тэрмінал Linux на прыладзе Android (эксперыментальная функцыя)"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Калі адключыць гэту функцыю, даныя тэрмінала Linux будуць сцёрты"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Праверка HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Усталяваць рэжым праверкі HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Адладка"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Знешняя прылада"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Падключаная прылада"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Гэты тэлефон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналагавы"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не ўдаецца прайграць на гэтай прыладзе"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Для пераключэння перайдзіце на іншую версію ўліковага запісу"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Тут не ўдаецца прайграць спампоўкі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 8bdd17ebd861..47ce37cfc900 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Локален терминал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Актив. на прил. за терминал с достъп до локалния команден ред"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Среда на програмиране на Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Стартиране на терминала на Linux под Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Експериментално) Стартиране на терминала на Linux под Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ако деактивир., данните в терминала на Linux ще бъдат изчистени"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Проверка с HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Проверка с HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Отстраняване на грешки"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Външно устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Свързано устройство"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Този телефон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналогов"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Възпроизвеждането не е възможно на това устройство"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надстройте профила, за да превключите"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Изтеглянията не могат да се възпроизвеждат тук"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 834eb1eef1ce..3b77cfdae6b5 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"স্থানীয় টার্মিনাল"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"স্থানীয় শেল অ্যাক্সেসের প্রস্তাব করে এমন টার্মিনাল অ্যাপ্লিকেশন সক্ষম করুন"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux ডেভেলপমেন্ট এনভায়র্নমেন্ট"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android-এ Linux টার্মিনাল রান করান"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(পরীক্ষামূলক) Android-এ Linux টার্মিনাল চালান"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"আপনি বন্ধ করে দিলে, Linux টার্মিনাল ডেটা মুছে যাবে"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP পরীক্ষণ"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP চেক করার আচরণ সেট করুন"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ডিবাগিং"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"এক্সটার্নাল ডিভাইস"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"কানেক্ট থাকা ডিভাইস"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফোনটি"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"অ্যানালগ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"এই ডিভাইসে চালানো যাবে না"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"পাল্টাতে অ্যাকাউন্ট আপগ্রেড করুন"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"এতে ডাউনলোড করা কন্টেন্ট প্লে করা যাবে না"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 75fe8181489d..65eb6817f631 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Omogući terminalnu aplik. koja nudi pristup lok. kom. okruženju"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linuxovo okruženje za razvoj"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Pokreni Linux terminal na Androidu"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimentalno) Pokreni Linux terminal na Androidu"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ako onemogućite ovo, podaci Linux terminala će se obrisati"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP provjera"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Postavke HDCP provjere"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Otklanjanje grešaka"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogni"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nije moguće reproducirati na uređaju"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite račun da promijenite"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Nije moguće reproducirati preuzimanja ovdje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 2c41b1aee8ef..a7c3fafd48ef 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Activa l\'aplicació de terminal que ofereix accés al shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Entorn de desenvolupament Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Executa el terminal de Linux a Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Executa el terminal de Linux a Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Si desactives l\'app, les dades del terminal de Linux s\'esborraran"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Comprovació d\'HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Defineix comprovació HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depuració"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositiu extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositiu connectat"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Aquest telèfon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analògic"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"No es pot reproduir en aquest dispositiu"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualitza el compte per canviar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Les baixades no es poden reproduir aquí"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a4b491bfc1f0..832d320cd805 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Místní terminál"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktivovat terminálovou aplikaci pro místní přístup k prostředí shell"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Vývojové prostředí Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Spustit na Androidu terminál Linux"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimentální) Spustit terminál Linux na Androidu"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Při deaktivaci se vymažou data terminálu Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Kontrola HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Nastavit chování kontroly HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Ladění"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externí zařízení"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Připojené zařízení"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogové"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"V zařízení nelze přehrávat"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Účet je třeba upgradovat"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Stažený obsah zde nelze přehrát"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index f7402732299b..708d5df4c6b3 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktivér terminalappen, der giver lokal shell-adgang"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-udviklingsmiljø"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Kør Linux-terminal i Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimentelt) Kør Linux-terminal i Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Hvis du deaktiverer Linux-terminaldata, ryddes dataene."</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-kontrol"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Angiv HDCP-kontroladfærd"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Fejlretning"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhed"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Forbundet enhed"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan ikke afspilles på denne enhed"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Opgrader kontoen for at skifte"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Downloads kan ikke afspilles her"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index c8d8cb55de99..069201a63174 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokales Terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Terminal-App mit Zugriff auf lokale Shell aktivieren"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-Entwicklungsumgebung"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Linux-Terminal unter Android ausführen"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimentell) Linux-Terminal unter Android ausführen"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Wenn du die Linux-Terminal App deaktivierst, werden die Daten darin gelöscht"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-Prüfung"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP-Prüfverhalten festlegen"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Debugging"</string>
@@ -503,7 +504,7 @@
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Wird geladen"</string>
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATUS">%2$s</xliff:g> – Vollständig geladen in <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> – Vollständig geladen in <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Vollständig geladen in <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Vollständig geladen um <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Vollständig geladen bis <xliff:g id="TIME">%1$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>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externes Gerät"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbundenes Gerät"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Dieses Smartphone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Wiedergabe auf diesem Gerät nicht möglich"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Zum Umstellen Kontoupgrade durchführen"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Downloads können hier nicht abgespielt werden"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index c773372790b4..8577a9a8acdf 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Τοπική τερματική εφαρμογή"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Ενεργοπ.τερμ.εφαρμογής που προσφέρει πρόσβαση στο τοπικό κέλυφος"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Περιβάλλον ανάπτυξης Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Εκτέλεση τερματικού Linux σε Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Πειραματικό) Εκτέλεση τερματικού Linux σε Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Εάν απενεργοποιηθεί, τα δεδομένα τερματικού Linux θα διαγραφούν"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Έλεγχος HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Ρύθμιση συμπεριφοράς ελέγχου HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Εντοπισμός σφαλμάτων"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Εξωτερική συσκευή"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Συνδεδεμένη συσκευή"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Αυτό το τηλέφ."</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Αναλογικός"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Δεν είναι δυνατή η αναπαραγωγή σε αυτήν τη συσκευή"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Αναβαθμίστε τον λογαριασμό για εναλλαγή"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Δεν είναι δυνατή η αναπαραγωγή των λήψεων εδώ"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 8fe14350f3d9..f9d2f082b06c 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Enable terminal app that offers local shell access"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux development environment"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Run Linux terminal on Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Run Linux terminal on Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"If you disable, Linux terminal data will be cleared"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP checking"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Set HDCP checking behaviour"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Debugging"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogue"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Can\'t play on this device"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade account to switch"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Can\'t play downloads here"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 0d560ea7c8b9..2cf98ef44c26 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Enable terminal app that offers local shell access"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux development environment"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Run Linux terminal on Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Run Linux terminal on Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"If you disable, Linux terminal data will be cleared"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP checking"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Set HDCP checking behavior"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Debugging"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 8fe14350f3d9..f9d2f082b06c 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Enable terminal app that offers local shell access"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux development environment"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Run Linux terminal on Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Run Linux terminal on Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"If you disable, Linux terminal data will be cleared"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP checking"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Set HDCP checking behaviour"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Debugging"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogue"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Can\'t play on this device"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade account to switch"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Can\'t play downloads here"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 8fe14350f3d9..f9d2f082b06c 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Enable terminal app that offers local shell access"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux development environment"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Run Linux terminal on Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Run Linux terminal on Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"If you disable, Linux terminal data will be cleared"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP checking"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Set HDCP checking behaviour"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Debugging"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogue"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Can\'t play on this device"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade account to switch"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Can\'t play downloads here"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 99dd4d9a56b9..a4834d887140 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Habilitar aplicac. de terminal que ofrece acceso al shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Entorno de desarrollo de Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Ejecuta la terminal de Linux en Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Ejecuta la terminal de Linux en Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Si lo inhabilitas, se borrarán los datos de la terminal de Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Comprobación HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Configurar comportamiento de la comprobación HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depuración"</string>
@@ -490,7 +491,7 @@
<string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> según el uso"</string>
<string name="power_discharge_by" msgid="4113180890060388350">"Duración aproximada hasta: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"Debería durar aproximadamente hasta: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Hasta <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Hasta la(s) <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Es posible que la batería se agote para las <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analógico"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"No se puede reproducir en este dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualiza la cuenta para cambiar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"No se pueden reproducir las descargas aquí"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index cbbadd44d357..1792fd13a5f5 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Habilitar aplicación de terminal que ofrece acceso a shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Entorno de desarrollo de Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Ejecuta un terminal de Linux en Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Ejecutar un terminal de Linux en Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Si la inhabilitas, se borrarán los datos del terminal de Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Comprobación de HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Establecer comprobación HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depuración"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analógico"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"No se puede reproducir en este dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualiza la cuenta para cambiar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"No se pueden reproducir descargas aquí"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 3c337933fbfb..5411d0bd30b5 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Kohalik terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Luba kohalikku turvalist juurdepääsu pakkuv terminalirakendus"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linuxi arenduskeskkond"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Linuxi terminali käitamine Androidis"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Katseline) Linuxi terminal Androidis"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Keelamisel kustutatakse Linuxi terminali andmed"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-kontrollimine"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP käitumise määramine"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Silumine"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Väline seade"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ühendatud seade"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"See telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/SPDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analoog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Selles seadmes ei saa esitada"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Lülitamiseks täiendage kontot"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Siin ei saa allalaaditud faile esitada"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index c9947485e5f2..090d99d3b771 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Tokiko terminala"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Gaitu tokiko shell-sarbidea duen terminal-aplikazioa"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-eko garapen-ingurunea"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Exekutatu Linux-en terminala Android-en"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"Exekutatu Linux terminala Android-en (esperimentala)"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Desgaitzen baduzu, Linux-eko terminaleko datuak garbituko dira"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP egiaztapena"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Ezarri HDCP egiaztapen-portaera"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Arazketa"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kanpoko gailua"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Konektatutako gailua"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefono hau"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogikoa"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ezin da erreproduzitu gailu honetan"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Aldatzeko, bertsio-berritu kontua"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Deskargak ezin dira hemen erreproduzitu"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 75b805109824..c350175b788d 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"ترمینال محلی"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"فعال کردن ترمینال برنامه‌ کاربردی که دسترسی به برنامه محلی را پیشنهاد می‌کند"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"‏محیط توسعه نرم‌افزار Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"‏اجرا کردن پایانه Linux در Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"‏(آزمایشی) اجرا کردن «پایانه Linux» در Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"‏اگر پایانه Linux را غیرفعال کنید، داده‌های آن پاک خواهد شد"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"‏بررسی HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"‏تنظیم عملکرد بررسی HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"اشکال‌زدایی"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"دستگاه خارجی"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"دستگاه متصل"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"این تلفن"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"آنالوگ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"نمی‌توان در این دستگاه پخش کرد"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"برای تغییر، حساب را ارتقا دهید"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"نمی‌توان بارگیری‌ها را در اینجا پخش کرد"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 9cc33b013979..18a84b5f4ead 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Paikallinen pääte"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Ota käyttöön päätesov. joka mahdollistaa paikall. liittymäkäytön"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-kehitysympäristö"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Käynnistä Linux-pääte Androidilla"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Kokeellinen) Käynnistä Linux-pääte Androidilla"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Jos poistat tämän käytöstä, Linux-päätteen data tyhjennetään"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-tarkistus"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Aseta HDCP-tarkistus"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Vianetsintä"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ulkoinen laite"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Yhdistetty laite"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tämä puhelin"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analoginen"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ei voi toistaa tällä laitteella"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Vaihda päivittämällä tili"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Latauksia ei voi toistaa täällä"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 28692d0afa55..066244a06620 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Activer l\'appli Terminal permettant l\'accès au shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Environnement de développement Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Exécuter le terminal Linux sur Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Expérimental) Exécutez le terminal Linux sur Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"La désactivation effacera les données du terminal Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Vérification HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Configurer vérification HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Débogage"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogique"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossible de faire jouer le contenu sur cet appareil"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Mettez à jour le compte pour passer à la version payante"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Lecture des téléchargements impossible ici"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 4e7abc938ccf..84c2f15b12e2 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Environnement de développement Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Exécuter le terminal Linux sur Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Version expérimentale) Exécuter le terminal Linux sur Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"La désactivation entraîne la suppression des données du terminal Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Vérification HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Config. vérification HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Débogage"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogique"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossible de lire du contenu sur cet appareil"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Mettez à niveau le compte pour changer"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Impossible de lire les téléchargements ici"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index a4d3a0a4f751..d15b6e22e135 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Activa a aplicación terminal que ofrece acceso ao shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Contorno de programación Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Executar terminal de Linux en Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Executa o terminal de Linux en Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Se desactivas a opción, borraranse os datos do terminal de Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Comprobación HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Definir comprobación HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depuración"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analóxica"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Non se pode reproducir contido neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Cambia a conta a un plan superior para facer a modificación"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Non se poden reproducir as descargas neste dispositivo"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 7a26463bc9bd..5fd187f06c3c 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"સ્થાનિક ટર્મિનલ"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"સ્થાનિક શેલ અ‍ૅક્સેસની ઑફર કરતી ટર્મિનલ એપ્લિકેશનને સક્ષમ કરો"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux ડેવલપમેન્ટ એન્વાયરમેન્ટ"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android પર Linux ટર્મિનલ ચલાવો"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(પ્રાયોગિક) Android પર Linux ટર્મિનલ ચલાવો"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Linux ટર્મિનલ ઍપને બંધ કરવાથી તેનો ડેટા સાફ કરવામાં આવશે"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP તપાસણી"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP તપાસણીની વર્તણૂક બદલો"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ડીબગિંગ"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"બહારનું ડિવાઇસ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"કનેક્ટ કરેલું ડિવાઇસ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"આ ફોન"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"એનાલોગ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"ઑગ્ઝિલરી"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"આ ડિવાઇસ પર ચલાવી શકતા નથી"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"સ્વિચ કરવા માટે એકાઉન્ટ અપગ્રેડ કરો"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ડાઉનલોડ કરેલું કન્ટેન્ટ અહીં ચલાવી શકતા નથી"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 83cb3989e909..fa0716e4ad22 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"लोकल शेल तक पहुंचने की सुविधा देने वाले टर्मिनल ऐप को चालू करें"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux डेवलपमेंट एनवायरमेंट"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android पर Linux का टर्मिनल ऐप्लिकेशन चलाएं"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(एक्सपेरिमेंट के तौर पर) Android पर Linux का टर्मिनल ऐप्लिकेशन चलाएं"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Linux टर्मिनल ऐप्लिकेशन को बंद करने पर, उसका डेटा मिट जाएगा"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP जांच"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP जाँच व्‍यवहार सेट करें"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"डीबग करना"</string>
@@ -584,19 +585,16 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"यह फ़ोन"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"यह टैबलेट"</string>
- <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"इस कंप्यूटर पर (इंटरनल)"</string>
+ <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"यह कंप्यूटर (इंटरनल)"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाहरी डिवाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट किया गया डिवाइस"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यह फ़ोन"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ऐनालॉग"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"ऑक्स"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"इस डिवाइस पर मीडिया नहीं चलाया जा सकता"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"प्रीमियम खाते में स्विच करने के लिए, अपना खाता अपग्रेड करें"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"डाउनलोड किए गए वीडियो यहां नहीं चलाए जा सकते"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index e78884d65538..8ad5c9d559d7 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Omogući aplikaciju terminala koja nudi pristup lokalnoj ovojnici"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linuxovo razvojno okruženje"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Pokrenite Linux terminal na Androidu"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimentalno) Pokreni Linux terminal na Androidu"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ako to onemogućite, podaci Linux terminala će se izbrisati"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP provjera"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Postavke HDCP provjere"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Otklanjanje pogrešaka"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogni"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ne može se reproducirati ovdje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite i prebacite se"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Ne može se tu reproducirati"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index ca18ac2e191f..18c6ea307651 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Helyi végpont"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Végalkalmazás engedélyezése a helyi rendszerhéj eléréséhez"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux fejlesztői környezet"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Linux-terminál futtatása Androidon"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Kísérleti) Linux-terminál futtatása Androidon"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Letiltás esetén törlődnek a Linux-terminál adatai"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-ellenőrzés"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP-ellenőrzés beállítása"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Hibakeresés"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Külső eszköz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Csatlakoztatott eszköz"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ez a telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analóg"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nem játszható le ezen az eszközön"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"A váltáshoz frissítse fiókját"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Itt nem játszhatók le a letöltések"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 0749d6042b6b..593479a4c011 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Տեղային տերմինալ"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Միացնել տերմինալային հավելվածը, որն առաջարկում է մուտք տեղային խեցի"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Լինուքսի մշակման միջավայր"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Գործարկել Լինուքս տերմինալը Android-ում"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"Գործարկել Լինուքս տերմինալը Android-ում (փորձնական)"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Եթե անջատեք, Լինուքս տերմինալի տվյալները կջնջվեն"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP ստուգում"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP-ի ստուգման կարգը"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Վրիպազերծում"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Արտաքին սարք"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Միացված սարք"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Այս հեռախոսը"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Անալոգային"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Հնարավոր չէ նվագարկել այս սարքում"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Փոխելու համար անցեք հաշվի պրեմիում տարբերակին"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Ներբեռնումները չեն նվագարկվում այստեղ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 7d652c9db683..6522e22734b9 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal lokal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktifkan aplikasi terminal yang menawarkan akses kerangka lokal"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Lingkungan pengembangan Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Jalankan terminal Linux di Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimental) Jalankan terminal Linux di Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Jika dinonaktifkan, data terminal Linux akan dihapus"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Pemeriksaan HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Setel perilaku pemeriksaan HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Proses debug"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Perangkat Eksternal"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Perangkat yang terhubung"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ponsel ini"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Tidak dapat memutar di perangkat ini"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade akun untuk beralih"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tidak dapat memutar hasil download di sini"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 67f4fe1b9562..4a10fb3e94d3 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Staðbundin skipanalína"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Virkja skipanalínuforrit sem leyfir staðbundinn skeljaraðgang"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Þróunarumhverfi Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Keyra Linux-útstöð í Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Á tilraunastigi) Keyrðu Linux-útstöð í Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ef þú slekkur á þessu verður gögnum í Linux-útstöð eytt"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-athugun"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Velja virkni HDCP-ath."</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Villuleit"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ytra tæki"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tengt tæki"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Þessi sími"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Hliðrænt"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ekki er hægt að spila í þessu tæki"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Uppfærðu reikninginn til að skipta"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Ekki er hægt að spila niðurhal hér"</string>
@@ -739,7 +737,7 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ef þú sendir út <xliff:g id="SWITCHAPP">%1$s</xliff:g> eða skiptir um úttak lýkur yfirstandandi útsendingu"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Senda út <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Skipta um úttak"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Hreyfimyndir flýtiritunar við bendinguna „til baka“"</string>
+ <string name="back_navigation_animation" msgid="8105467568421689484">"Hreyfimyndir flýtiritunar við bendinguna „Til baka“"</string>
<string name="back_navigation_animation_summary" msgid="741292224121599456">"Kveikja á hreyfimyndum í kerfinu til að sýna hreyfimyndir þegar bendingin „til baka“ er gerð."</string>
<string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Þessi stilling kveikir á hreyfimyndum í kerfinu til að sýna hreyfimyndir flýtiritunar með bendingum. Stillingin krefst þess að kveikt sé á enableOnBackInvokedCallback í upplýsingaskránni fyrir hvert forrit."</string>
<string name="font_scale_percentage" msgid="2624057443622817886">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 9f7f41b8b16f..21f78ddbdb72 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminale locale"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Ambiente di sviluppo Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Esegui il terminale Linux su Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Sperimentale) Esegui il terminale Linux su Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Se disattivi l\'opzione, i dati del terminale Linux verranno cancellati"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Verifica HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Comportamento di verifica HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Debug"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo connesso"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Questo smartphone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogico"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossibile riprodurre su questo dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Esegui l\'upgrade dell\'account per cambiare"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Qui non è possibile riprodurre i download"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 056aae170610..3b28bd2745e3 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"מסוף מקומי"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"הפעלה של אפליקציית מסוף המציעה גישה מקומית למעטפת"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"‏סביבת פיתוח של Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"‏הפעלת טרמינל Linux ב-Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"‏(ניסיוני) הפעלת טרמינל Linux ב-Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"‏אם ההגדרה תושבת, הנתונים של טרמינל Linux יימחקו"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"‏בדיקת HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"‏הגדרת האופן של בדיקת HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ניפוי באגים"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"מכשיר חיצוני"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"המכשיר המחובר"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"הטלפון הזה"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"אנלוגי"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"לא ניתן להפעיל במכשיר"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"יש לשדרג חשבון כדי לעבור"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"לא ניתן להפעיל הורדות"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 833d1dcf4aef..a826810508e5 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"ローカルターミナル"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"ローカルシェルアクセスを提供するターミナルアプリを有効にします"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux 開発環境"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android で Linux ターミナルを実行する"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(試験運用版)Android で Linux ターミナルを実行する"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"無効にすると、Linux ターミナルのデータが消去されます"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP チェック"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP チェック動作を設定"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"デバッグ"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部デバイス"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"接続済みのデバイス"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"このデバイス"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"アナログ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"このデバイスでは再生できません"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"アカウントを更新して切り替えてください"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"再生不可: ダウンロードしたコンテンツ"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index acad174698fb..f321371a744e 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"ადგილობრივი ტერმინალი"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"ლოკალურ გარსზე წვდომის ტერმინალური აპლიკაციის ჩართვა"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-ის შემუშავების გარემო"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Linux ტერმინალის გაშვება Android-ზე"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ექსპერიმენტული) Linux ტერმინალის გაშვება Android-ზე"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"გათიშვის შემთხვევაში, წაიშლება Linux ტერმინალის მონაცემები"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP შემოწმება"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"დააყენე HDCP შემოწმების ქცევა"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"გამართვა"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"გარე მოწყობილობა"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"დაკავშირებული მოწყობილობა"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ეს ტელეფონი"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ანალოგური"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ამ მოწყობილობაზე დაკვრა შეუძლებელია"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"გადასართავად განაახლეთ ანგარიში"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"შეუძლებელია აქ ჩამოტვირ. თამაში"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index e2ce5b0e8ef3..85b86d4ef392 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Жергілікті терминал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Жергілікті шелл-код қол жетімділігін ұсынатын терминалды қолданбаны қосу"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux әзірлеуші ортасы"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android-та Linux терминалын іске қосыңыз."</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Эксперименттік) Linux терминалын Android-та іске қосу"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Өшірсеңіз, Linux терминалының деректері өшіріледі."</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP тексерісі"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP (кең жолақты цифрлық контент қорғау) тексеру мүмкіндігін орнату"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Түзету"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Сыртқы құрылғы"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Жалғанған құрылғы"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Осы телефон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналогтік"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Осы құрылғыда ойнату мүмкін емес."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Ауысу үшін аккаунтты жаңартыңыз."</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Жүктеп алынғандарды осы жерде ойнату мүмкін емес."</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index c06aaeeb4bda..12d35cf78685 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"ស្ថានីយ​មូលដ្ឋាន"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"បើក​កម្មវិធី​ស្ថានីយ​ដែល​ផ្ដល់​ការ​ចូល​សែល​មូលដ្ឋាន"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"មជ្ឈដ្ឋាន​អភិវឌ្ឍន៍ Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"ដំណើរការទែមីណាល់ Linux នៅលើ Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ពិសោធន៍) ដំណើរការទែមីណាល់ Linux នៅលើ Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ប្រសិនបើអ្នកបិទ ទិន្នន័យទែមីណាល់ Linux នឹងត្រូវបានសម្អាត"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"ពិនិត្យ HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"កំណត់​ឥរិយាបថ​ពិនិត្យ HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ការជួសជុល"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ឧបករណ៍ខាងក្រៅ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"​ឧបករណ៍ដែលបាន​ភ្ជាប់"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ទូរសព្ទនេះ"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"អាណាឡូក"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"មិនអាចចាក់នៅលើ​ឧបករណ៍នេះបានទេ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ដំឡើងកម្រិតគណនី ដើម្បីប្ដូរ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"មិនអាចចាក់ខ្លឹមសារដែលបានទាញយកនៅទីនេះបានទេ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 2c25501e60a7..d95846fba071 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"ಪ್ರೊಫೈಲ್ ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="category_personal" msgid="6236798763159385225">"ವೈಯಕ್ತಿಕ"</string>
<string name="category_work" msgid="4014193632325996115">"ಕೆಲಸ"</string>
- <string name="category_private" msgid="4244892185452788977">"ಖಾಸಗಿ"</string>
+ <string name="category_private" msgid="4244892185452788977">"ಪ್ರೈವೆಟ್"</string>
<string name="category_clone" msgid="1554511758987195974">"ಕ್ಲೋನ್"</string>
<string name="development_settings_title" msgid="140296922921597393">"ಡೆವಲಪರ್ ಆಯ್ಕೆಗಳು"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"ಡೆವಲಪರ್ ಆಯ್ಕೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"ಸ್ಥಳೀಯ ಟರ್ಮಿನಲ್"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"ಸ್ಥಳೀಯ ಶೆಲ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸುವ ಟರ್ಮಿನಲ್ ಆ್ಯಪ್‌ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux ಡೆವಲಪ್‌ಮೆಂಟ್ ಎನ್ವಿರಾನ್‌ಮೆಂಟ್"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android ನಲ್ಲಿ Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ರನ್ ಮಾಡಿ"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ಪ್ರಾಯೋಗಿಕ) Android ನಲ್ಲಿ Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ರನ್ ಮಾಡಿ"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ನೀವು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದರೆ, Linux ಟರ್ಮಿನಲ್ ಡೇಟಾ ತೆರವುಗೊಳಿಸಲಾಗುತ್ತದೆ"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP ಪರೀಕ್ಷಿಸುವಿಕೆ"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP ಪರಿಶೀಲನಾ ನಡವಳಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ಡೀಬಗ್ ಮಾಡುವಿಕೆ"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ಬಾಹ್ಯ ಸಾಧನ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ಕನೆಕ್ಟ್ ಮಾಡಿರುವ ಸಾಧನ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ಈ ಫೋನ್"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ಅನಲಾಗ್"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ಈ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ಬದಲಾಯಿಸಲು ಖಾತೆಯನ್ನು ಅಪ್‌ಗ್ರೇಡ್ ಮಾಡಿ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ಇಲ್ಲಿ ಡೌನ್‌ಲೋಡ್‌ಗಳನ್ನು ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index f7dc6ae8603d..f82a6a6ec442 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"로컬 터미널"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"로컬 셸 액세스를 제공하는 터미널 앱 사용"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux 개발 환경"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android에서 Linux 터미널 실행"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(실험용) Android에서 Linux 터미널 실행"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"사용 중지하면 Linux 터미널 데이터가 삭제됩니다."</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP 확인"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP 확인 동작 설정"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"디버깅"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"외부 기기"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"연결된 기기"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"이 휴대전화"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"아날로그"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"이 기기에서 재생할 수 없음"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"계정을 업그레이드하여 전환하기"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"여기서 다운로드한 콘텐츠를 재생할 수 없습니다."</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 6105db0bf071..ff63c1922940 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"Профиль тандоо"</string>
<string name="category_personal" msgid="6236798763159385225">"Жеке"</string>
<string name="category_work" msgid="4014193632325996115">"Жумуш"</string>
- <string name="category_private" msgid="4244892185452788977">"Купуя"</string>
+ <string name="category_private" msgid="4244892185452788977">"Жеке профиль"</string>
<string name="category_clone" msgid="1554511758987195974">"Клон"</string>
<string name="development_settings_title" msgid="140296922921597393">"Иштеп чыгуучунун параметрлери"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Иштеп чыгуучунун параметрлерин иштетүү"</string>
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Жергиликтүү терминал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Жергиликтүү буйрук кабыгын сунуштаган терминалга уруксат берүү"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux иштеп чыгуу чөйрөсү"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android\'де Linux терминалын иштетүү"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Cынамык) Linux терминалын Android\'де иштетүү"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Эгер өчүрүп койсоңуз, Linux терминалынын маалыматы тазаланат"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP текшерүү"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP текшерүү тартиби"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Мүчүлүштүктөрдү аныктоо"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Тышкы түзмөк"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Туташкан түзмөк"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ушул телефон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналог"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"КШМЧ"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Бул түзмөктө ойнотууга болбойт"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Премиум аккаунтка которулуу керек"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Жүктөлүп алынгандар ойнотулбайт"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index df3689e72249..36d2ccf041db 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal ໃນໂຕເຄື່ອງ"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"ເປີດນຳໃຊ້ແອັບຯ Terminal ທີ່ໃຫ້ການເຂົ້າເຖິງ shell ໃນໂຕເຄື່ອງໄດ້"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"ສະພາບແວດລ້ອມໃນການພັດທະນາ Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"ເອີ້ນໃຊ້ເທີມິນອນ Linux ຢູ່ Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ເປັນການທົດລອງ) ເອີ້ນໃຊ້ເທີມິນອນ Linux ຢູ່ Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ຫາກທ່ານປິດການນຳໃຊ້, ລະບົບຈະລຶບລ້າງຂໍ້ມູນເທີມິນອນ Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"ການກວດສອບ HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"ຕັ້ງວິທີການກວດສອບ HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ການດີບັກ"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ອຸປະກອນພາຍນອກ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ໂທລະສັບນີ້"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ໂມງເຂັມ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ຫຼິ້ນຢູ່ອຸປະກອນນີ້ບໍ່ໄດ້"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ອັບເກຣດບັນຊີເພື່ອສະຫຼັບ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ບໍ່ສາມາດຫຼິ້ນເນື້ອຫາທີ່ດາວໂຫຼດຢູ່ນີ້ໄດ້"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 4d9858733f86..5b20db3cd464 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Vietinis terminalas"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Įgal. terminalo progr., siūlančią prieigą prie viet. apvalkalo"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"„Linux“ kūrimo aplinka"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"„Linux“ terminalo paleidimas sistemoje „Android“"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimentas) „Linux“ terminalo paleidimas sistemoje „Android“"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Jei išjungsite, „Linux“ terminalo duomenys bus išvalyti"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP tikrinimas"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Nust. HDCP tikrin. elgs."</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Derinimas"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Išorinis įrenginys"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Prijungtas įrenginys"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis telefonas"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analoginis"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Negalima leisti šiame įrenginyje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Jei norite perjungti, naujovinkite paskyrą"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Čia negalima paleisti atsisiuntimų"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 582982673441..620318a08f18 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -235,9 +235,9 @@
<item msgid="6946761421234586000">"400%"</item>
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Profila izvēlēšanās"</string>
- <string name="category_personal" msgid="6236798763159385225">"Privāts"</string>
+ <string name="category_personal" msgid="6236798763159385225">"Personīgais"</string>
<string name="category_work" msgid="4014193632325996115">"Darba"</string>
- <string name="category_private" msgid="4244892185452788977">"Privāti"</string>
+ <string name="category_private" msgid="4244892185452788977">"Privāts"</string>
<string name="category_clone" msgid="1554511758987195974">"Klons"</string>
<string name="development_settings_title" msgid="140296922921597393">"Izstrādātāju opcijas"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Izstrādātāju opciju iespējošana"</string>
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Vietējā beigu lietotne"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Iespējot beigu lietotni, kurā piedāvāta vietējā čaulas piekļuve"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux izstrādes vide"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Palaist Linux termināli Android ierīcē"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimentāls) Palaist Linux termināli Android ierīcē"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ja atspējosiet, Linux termināļa dati tiks notīrīti"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP pārbaude"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP pārb. iestatīšana"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Atkļūdošana"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ārēja ierīce"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pievienotā ierīce"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis tālrunis"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogā"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nevar atskaņot šajā ierīcē."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Lai pārslēgtu, jauniniet kontu"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Šeit nevar atskaņot lejupielādes"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 5d5d480ecd68..0331ece3c4dc 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -235,9 +235,9 @@
<item msgid="6946761421234586000">"400 %"</item>
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Изберете профил"</string>
- <string name="category_personal" msgid="6236798763159385225">"Лично"</string>
+ <string name="category_personal" msgid="6236798763159385225">"Личен"</string>
<string name="category_work" msgid="4014193632325996115">"Работа"</string>
- <string name="category_private" msgid="4244892185452788977">"Приватно"</string>
+ <string name="category_private" msgid="4244892185452788977">"Приватен"</string>
<string name="category_clone" msgid="1554511758987195974">"Клон"</string>
<string name="development_settings_title" msgid="140296922921597393">"Програмерски опции"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Овозможете ги програмерските опции"</string>
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Локален терминал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Овозможи апликација на терминал што овозможува локален пристап кон школка."</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Програмерска околина на Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Извршување Linux-терминал на Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Експериментално) Вклучете го Linux-терминалот на Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ако оневозможите, податоците за Linux-терминалот ќе се избришат"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Проверка со HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Постави однесување на проверка на HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Отстранување грешки"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Надворешен уред"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Поврзан уред"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овој телефон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналогно"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не може да се пушти на уредов"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надградете ја сметката за да се префрлите"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Не може да се пуштаат преземања тука"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 71406232cb64..aaebe4cd6abf 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"പ്രാദേശിക ടെർമിനൽ"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"പ്രാദേശിക ഷെൽ ആക്‌സസ് നൽകുന്ന ടെർമിനൽ അപ്ലിക്കേഷൻ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux ഡെവലപ്പ്മെന്റ് എൻവയോൺമെന്റ്"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android-ൽ Linux ടെർമിനൽ പ്രവർത്തിപ്പിക്കുക"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(പരീക്ഷണാത്മകം) Android-ൽ Linux ടെർമിനൽ റൺ ചെയ്യുക"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"പ്രവർത്തനരഹിതമാക്കുകയാണെങ്കിൽ, Linux ടെർമിനൽ ഡാറ്റ മായ്ക്കും"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP പരിശോധന"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP ചെക്കിംഗ്‌രീതി സജ്ജമാക്കുക"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ഡീബഗ്ഗിംഗ്"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ബാഹ്യ ഉപകരണം"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"കണക്‌റ്റ് ചെയ്‌ത ഉപകരണം"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ഈ ഫോൺ"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"അനലോഗ്"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ഈ ഉപകരണത്തിൽ പ്ലേ ചെയ്യാൻ കഴിയില്ല"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"അക്കൗണ്ട് മാറാൻ അപ്‌ഗ്രേഡ് ചെയ്യുക"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ഡൗൺലോഡുകൾ പ്ലേ ചെയ്യാനാകില്ല"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c9e0178ce54f..fb2b7291bb88 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Локал терминал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Локал суурьт хандалт хийх боломж олгодог терминалын апп-г идэвхжүүлэх"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-н хөгжүүлэлтийн орчин"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android дээр Linux терминалыг ажиллуулах"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Туршилтын) Android дээр Linux терминалыг ажиллуулах"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Хэрэв та идэвхгүй болговол Linux терминалын өгөгдлийг арилгана"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP шалгах"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP шалгах авирыг тохируулах"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Дебаг"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Гадаад төхөөрөмж"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Холбогдсон төхөөрөмж"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Энэ утас"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Aналог"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"НЭМЭЛТ"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Энэ төхөөрөмжид тоглуулах боломжгүй"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Сэлгэхийн тулд бүртгэлийг сайжруулна уу"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Татаж авсан файлыг энд тоглуулах боломжгүй"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index a6596cdf7d0c..023a2e47e8f3 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"स्थानिक टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"स्थानिक शेल प्रवेश देणारा टर्मिनल अ‍ॅप सुरू करा"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux विकास पर्यावरण"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android वर Linux टर्मिनल रन करा"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(प्रायोगिक) Android वर Linux टर्मिनल रन करा"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"तुम्ही Linux टर्मिनल बंद केल्यास, डेटा साफ केला जाईल"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP तपासणी"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP तपासणी वर्तन सेट करा"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"डीबग करणे"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिव्हाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट केलेले डिव्हाइस"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"हा फोन"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"अ‍ॅनालॉग"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"या डिव्हाइसवर प्ले करू शकत नाही"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"स्विच करण्यासाठी खाते अपग्रेड करा"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"येथे डाउनलोड प्ले केले जाऊ शकत नाहीत"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index ebde3319a806..4212eb49f2cf 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal setempat"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Dayakan apl terminal yang menawarkan akses shell tempatan"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Persekitaran pembangunan Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Terminal Run Linux pada Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Percubaan) Jalankan terminal Linux pada Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Jika dilumpuhkan, data terminal Linux akan dikosongkan"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Penyemakan HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Ttpkn tngkh laku smk HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Menyahpepijat"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Peranti Luar"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Peranti yang disambungkan"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefon ini"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Tidak dapat dimainkan pada peranti ini"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Tingkatkan akaun untuk beralih"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tidak dapat memainkan muat turun di sini"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 1131007fe1bd..df13e6c5f33e 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"လိုကယ်တာမီနယ်"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"local shell အသုံးပြုခွင့်ကမ်းလှမ်းသော တာမင်နယ်အပလီကေးရှင်းဖွင့်ပါ"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux ဆော့ဖ်ဝဲရေးမှု ပတ်ဝန်းကျင်"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android တွင် Linux တာမီနယ် လုပ်ဆောင်ရန်"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(စမ်းသပ်) Android တွင် Linux တာမီနယ်ကို လုပ်ဆောင်ရန်"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ပိတ်လိုက်ပါက Linux တာမီနယ်ဒေတာကို ရှင်းထုတ်ပါမည်"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP စစ်ဆေးမှု"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP စစ်ဆေးပုံကို သတ်မှတ်မည်"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"အမှားရှာဖွေဖယ်ရှားခြင်း"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ပြင်ပစက်"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ချိတ်ဆက်ကိရိယာ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ဤဖုန်း"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ရိုးရိုး"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ဤစက်ပစ္စည်းတွင် ဖွင့်၍မရပါ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ပြောင်းရန် အကောင့်အဆင့်ကိုမြှင့်ပါ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ဤနေရာတွင် ဒေါင်းလုဒ်များ ဖွင့်မရပါ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 1a71ec07457e..812666350505 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktiver terminalappen som gir lokal kommandolistetilgang"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-utviklingsmiljø"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Kjør Linux-terminal på Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(På forsøksstadiet) Kjør Linux-terminal på Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Hvis du slår av dette, slettes Linux-terminaldataene"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-kontroll"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Angi HDPC-kontrolladferd"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Feilsøking"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tilkoblet enhet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefonen"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan ikke spille på denne enheten"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Oppgrader kontoen for å bytte"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Kan ikke spille av nedlastinger her"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index dea9fcce87cf..a233622362b8 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -167,7 +167,7 @@
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"कम्प्युटर"</string>
<string name="bluetooth_talkback_headset" msgid="3406852564400882682">"हेडसेट"</string>
<string name="bluetooth_talkback_phone" msgid="868393783858123880">"फोन"</string>
- <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"छवि सम्बन्धी"</string>
+ <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"फोटो सम्बन्धी"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"हेडफोन"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"इनपुट सम्बन्धी बाह्य यन्त्र"</string>
<string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"हियरिङ डिभाइसहरू"</string>
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"प्रोफाइल रोज्नुहोस्"</string>
<string name="category_personal" msgid="6236798763159385225">"व्यक्तिगत"</string>
<string name="category_work" msgid="4014193632325996115">"काम"</string>
- <string name="category_private" msgid="4244892185452788977">"निजी"</string>
+ <string name="category_private" msgid="4244892185452788977">"निजी स्पेस"</string>
<string name="category_clone" msgid="1554511758987195974">"क्लोन"</string>
<string name="development_settings_title" msgid="140296922921597393">"विकासकर्ताका विकल्पहरू"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"विकासकर्ता विकल्प सक्रिया गर्नुहोस्"</string>
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"स्थानीय सेल पहुँच प्रदान गर्ने टर्मिनल एप सक्षम गर्नुहोस्"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux डेभलप्मेन्ट इन्भायरमेन्ट"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android मा Linux टर्मिनल एप प्रयोग गर्नुहोस्"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(परीक्षणको चरणमा रहेको) Android मा Linux टर्मिनल रन गर्नुहोस्"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"तपाईंले Linux टर्मिनल डिसएबल गर्नुभयो भने त्यसमा भएको डेटा मेटिने छ"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP जाँच"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP जाँच व्यवहार सेट गर्नुहोस्"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"डिबग गरिँदै छ"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिभाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट गरिएको डिभाइस"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यो फोन"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"एनालग"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"यो डिभाइसमा मिडिया प्ले गर्न मिल्दैन"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"आफूले प्रयोग गर्न चाहेको खाता अपग्रेड गर्नुहोस्"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"डाउनलोड गरिएका सामग्री यसमा प्ले गर्न मिल्दैन"</string>
@@ -713,7 +711,7 @@
<string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
<string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
<string name="data_connection_carrier_wifi" msgid="8932949159370130465">"W+"</string>
- <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा निष्क्रिय छ"</string>
+ <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा अफ छ"</string>
<string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा प्रयोग गर्ने गरी सेट गरिएन"</string>
<string name="accessibility_no_phone" msgid="2687419663127582503">"फोन छैन्।"</string>
<string name="accessibility_phone_one_bar" msgid="5719721147018970063">"फोन एउटा पट्टि।"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index e3be50736a88..551097d9e442 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokale terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Terminal-app aanzetten die lokale shell-toegang biedt"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-ontwikkelomgeving"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Linux-terminal uitvoeren op Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimenteel) Linux-terminal uitvoeren op Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Als je dit uitzet, worden Linux-terminalgegevens gewist"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-controle"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP-controlegedrag instellen"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Foutopsporing"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern apparaat"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbonden apparaat"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analoog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan niet afspelen op dit apparaat"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade het account om te schakelen"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Kan hier geen downloads afspelen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ea6fdba27506..790acffe2b80 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"ସ୍ଥାନୀୟ ଟର୍ମିନାଲ୍‌"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"ସ୍ଥାନୀୟ ଶେଲ୍‌କୁ ଆକ‌ସେସ୍‌ ଦେଉଥିବା ଟର୍ମିନଲ୍‌ ଆପ୍‌କୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux ଡେଭେଲପମେଣ୍ଟର ପରିବେଶ"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Androidରେ Linux ଟର୍ମିନାଲ ଚାଲୁ କରନ୍ତୁ"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ପରୀକ୍ଷାମୂଳକ) Androidରେ Linux ଟର୍ମିନାଲ ଚଲାନ୍ତୁ"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ଯଦି ଆପଣ ଅକ୍ଷମ କରନ୍ତି, ତେବେ Linux ଟର୍ମିନାଲ ଡାଟା ଖାଲି ହୋଇଯିବ"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP ଯାଞ୍ଚ"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCPର ଯାଞ୍ଚ ଗତିବିଧି ସେଟ୍‍ କରନ୍ତୁ"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ଡିବଗ୍‌ କରୁଛି"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ଏକ୍ସଟର୍ନଲ ଡିଭାଇସ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"କନେକ୍ଟ କରାଯାଇଥିବା ଡିଭାଇସ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ଏହି ଫୋନ୍"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ଆନାଲଗ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"ଅକ୍ସିଲାରି"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ଏହି ଡିଭାଇସରେ ପ୍ଲେ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ସ୍ୱିଚ କରିବା ପାଇଁ ଆକାଉଣ୍ଟକୁ ଅପଗ୍ରେଡ କରନ୍ତୁ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ଏଠାରେ ଡାଉନଲୋଡଗୁଡ଼ିକୁ ପ୍ଲେ କରାଯାଇପାରିବ ନାହିଁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 853405167e01..c20e0d88ee3f 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"ਸਥਾਨਕ ਟਰਮੀਨਲ"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"ਟਰਮੀਨਲ ਐਪ ਨੂੰ ਚਾਲੂ ਕਰੋ ਜੋ ਸਥਾਨਕ ਸ਼ੈਲ ਪਹੁੰਚ ਪੇਸ਼ਕਸ਼ ਕਰਦਾ ਹੈ"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux ਵਿਕਾਸ ਵਾਤਾਵਰਨ"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android \'ਤੇ Linux ਦੀ ਟਰਮੀਨਲ ਐਪ ਚਲਾਓ"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ਪ੍ਰਯੋਗਮਈ) Android \'ਤੇ Linux ਟਰਮੀਨਲ ਚਲਾਓ"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ਜੇ ਤੁਸੀਂ ਬੰਦ ਕਰਦੇ ਹੋ, ਤਾਂ Linux ਟਰਮੀਨਲ ਡਾਟਾ ਕਲੀਅਰ ਹੋ ਜਾਵੇਗਾ"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP ਜਾਂਚ"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP ਜਾਂਚ ਵਿਵਹਾਰ ਸੈੱਟ ਕਰੋ"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ਡੀਬੱਗਿੰਗ"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ਬਾਹਰੀ ਡੀਵਾਈਸ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ਕਨੈਕਟ ਕੀਤਾ ਡੀਵਾਈਸ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ਇਹ ਫ਼ੋਨ"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ਐਨਾਲੌਗ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਨਹੀਂ ਚਲਾਇਆ ਜਾ ਸਕਦਾ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ਸਵਿੱਚ ਕਰਨ ਲਈ ਖਾਤੇ ਨੂੰ ਅੱਪਗ੍ਰੇਡ ਕਰੋ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ਡਾਊਨਲੋਡਾਂ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਚਲਾਇਆ ਜਾ ਸਕਦਾ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index a9d4dcbf577a..f6ab8a7c19a4 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal lokalny"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Włącz terminal, który umożliwia dostęp do powłoki lokalnej"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Środowisko programistyczne Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Uruchom terminal Linux na Androidzie"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Wersja eksperymentalna) Uruchom terminal Linuxa na Androidzie"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Jeśli wyłączysz tę funkcję, dane terminala Linuxa będą usunięte"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Sprawdzanie HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Ustaw sprawdzanie HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Debugowanie"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Urządzenie zewnętrzne"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Połączone urządzenie"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ten telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogowe"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nie można odtworzyć na tym urządzeniu"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Aby przełączyć, potrzebujesz konta premium"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tutaj nie można odtworzyć pobranych plików"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index eac646ff4c10..dedc65c1369f 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Ativar o app terminal que oferece acesso ao shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Ambiente de desenvolvimento do Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Executar terminal Linux no Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Executar terminal Linux no Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Se desativar o app, os dados do terminal Linux serão removidos"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Verificação HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Config. a verificação HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depuração"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Neste telefone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analógico"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível abrir os downloads aqui"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index d8d172d25192..f1ac88bdda40 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Ativar aplicação terminal que oferece acesso local à shell"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Ambiente de programação Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Executar terminal do Linux no Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Executar terminal do Linux no Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Se desativar a app, os dados do terminal do Linux são limpos"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Verificação HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Definir o comportamento da verificação HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depuração"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo associado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telemóvel"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analógico"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Atualize a conta para mudar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível reproduzir as transferências aqui"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index eac646ff4c10..dedc65c1369f 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Ativar o app terminal que oferece acesso ao shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Ambiente de desenvolvimento do Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Executar terminal Linux no Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Executar terminal Linux no Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Se desativar o app, os dados do terminal Linux serão removidos"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Verificação HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Config. a verificação HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depuração"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Neste telefone"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analógico"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível abrir os downloads aqui"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index d507b8526c8d..cafb7881a32a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Aplicație terminal locală"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Activează aplicația terminal care oferă acces la shell local"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Mediu de dezvoltare Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Rulează Linux terminal pe Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Rulează terminalul Linux pe Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Dacă dezactivezi, datele terminalului Linux vor fi șterse"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Verificare HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Configurează verif. HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Depanare"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispozitiv extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispozitiv conectat"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Acest telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogic"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nu se poate reda pe acest dispozitiv"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Fă upgrade contului pentru a comuta"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Aici nu se pot reda descărcări"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 8d07c57fec56..951f3a0dd146 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Локальный терминальный доступ"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Разрешить терминальный доступ к локальной оболочке"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Среда разработки Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Запустить терминал Linux в Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"Запустить терминал Linux в Android (экспериментальная функция)"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Если отключить эту функцию, данные терминала Linux будут удалены"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Проверка HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Порядок проверки HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Отладка"</string>
@@ -584,19 +585,16 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Этот смартфон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Этот планшет"</string>
- <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Встроенный динамик компьютера"</string>
+ <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Встроенное"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Колонка с док-станцией"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Внешнее устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Подключенное устройство"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Этот смартфон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналоговый выход"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Невозможно воспроизвести на этом устройстве."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Для переключения требуется премиум-аккаунт"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Не удается воспроизвести скачанные файлы"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 6694bc552e11..8427064b99ef 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"පැතිකඩ තෝරන්න"</string>
<string name="category_personal" msgid="6236798763159385225">"පෞද්ගලික"</string>
<string name="category_work" msgid="4014193632325996115">"කාර්යාලය"</string>
- <string name="category_private" msgid="4244892185452788977">"පෞද්ගලික"</string>
+ <string name="category_private" msgid="4244892185452788977">"රහසිගත"</string>
<string name="category_clone" msgid="1554511758987195974">"ක්ලෝන කරන්න"</string>
<string name="development_settings_title" msgid="140296922921597393">"වර්ධක විකල්ප"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"සංවර්ධක විකල්ප සබල කිරීම"</string>
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"අභ්‍යන්තර අන්තය"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"දේශීය ෂෙල් ප්‍රවේශනය පිරිනමන ටර්මිනල් යෙදුම සබල කරන්න"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux සංවර්ධන පරිසරය"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android මත Linux ටර්මිනලය ධාවනය කරන්න"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(පර්යේෂණාත්මක) Android මත Linux ටර්මිනලය ධාවනය කරන්න"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"ඔබ අබල කරන්නේ නම්, Linux ටර්මිනල් දත්ත හිස් වනු ඇත"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP පරික්ෂාව"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP පරික්ෂා හැසිරීම සකසන්න"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"නිදොස්කරණය"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"බාහිර උපාංගය"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"සම්බන්ධ කළ උපාංගය"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"මෙම දුරකථනය"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"ප්‍රතිසමය"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"මෙම උපාංගය මත ධාවනය කළ නොහැක"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"මාරු වීමට ගිණුම උත්ශ්‍රේණි කරන්න"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"මෙහි බාගැනීම් වාදනය කළ නොහැක"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index fa525a20ca66..aca07e5a32c3 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Miestny terminál"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Povoliť terminálovú apl. na miestny prístup k prostrediu shell"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Vývojové prostredie Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Spúšťanie terminálu systému Linux v Androide"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimentálne) Spúšťať terminál systému Linux v Androide"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ak túto možnosť vypnete, údaje terminálu systému Linux sa vymažú"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Kontrola HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Nastaviť spôsob kontroly HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Ladenie"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externé zariadenie"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pripojené zariadenie"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefón"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analógový"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"V tomto zariadení sa nedá prehrávať obsah"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Inovujte účet a prejdite naň"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tu sa nedajú prehrať stiahnuté súbory"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 9b426aa27e19..00d93a65d2f1 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Omogočanje terminalske aplikacije za dostop do lokalne lupine"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Razvojno okolje Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Zagon terminala Linux v Androidu"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Preizkusno) Zagon terminala Linux v Androidu"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Če to onemogočite, bodo podatki terminala Linux izbrisani."</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Preverjanje HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Nastavi preverjanje HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Odpravljanje napak"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Zunanja naprava"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezana naprava"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ta telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogno"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ni mogoče predvajati v tej napravi."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Za preklop je potrebna nadgradnja računa"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Prenosov tu ni mogoče predvajati"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 73cc518dac0a..c907e22c7784 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminali lokal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktivizo aplikacionin terminal që ofron qasje në guaskën lokale"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Ambienti i zhvillimit për Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Ekzekuto terminalin e Linux në Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Eksperimentale) Ekzekuto terminalin e Linux në Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Nëse e çaktivizon, të dhënat e terminalit të Linux do të pastrohen"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Kontrolli HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Cakto kontrollin e HDCP-së"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Korrigjimi i gabimeve"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Pajisja e jashtme"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pajisja e lidhur"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ky telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analoge"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nuk mund të luhet në këtë pajisje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Përmirëso llogarinë për të ndryshuar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Shkarkimet nuk mund të luhen këtu"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index d8003d75bd4e..65000e468fea 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Локални терминал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Омогући апл. терминала за приступ локалном командном окружењу"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux окружење за програмирање"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Покрените Linux терминал на Android-у"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Експериментално) Покрените Linux терминал на Android-у"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ако онемогућите, подаци Linux терминала се бришу"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP провера"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Подешавање понашања HDCP провере"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Отклањање грешака"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Спољни уређај"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Повезани уређај"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овај телефон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналогни"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не можете да пустите на овом уређају"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надоградите налог ради пребацивања"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Преузимања не могу да се пуштају овде"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index f9bd295253a6..12c17290bf15 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktivera en terminalapp som ger åtkomst till hyllor lokalt"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux-utvecklingsmiljö"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Kör Linux-terminalen på Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimentellt) Kör Linux-terminalen på Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Om du inaktiverar detta rensas data i Linux-terminalen"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP-kontroll"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Konfigurera HDCP-kontroll"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Felsökning"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ansluten enhet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Den här telefonen"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan inte spelas på denna enhet"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Uppgradera kontot för att byta"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Det går inte att spela upp nedladdningar här"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index b86be31ec352..1bf5677668ca 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Kituo cha karibu"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Washa programu ya mwisho inayotoa ufikiaji mkuu wa karibu"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Mazingira ya usanidi wa Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Tumia temino ya Linux kwenye Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Ya majaribio) Tumia temino ya Linux kwenye Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ukizima, data ya kituo cha Linux itafutwa"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Inakagua HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Weka HDCP ya kukagua tabia"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Utatuzi"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kifaa cha Nje"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Kifaa kilichounganishwa"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Simu hii"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analogi"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Huwezi kucheza maudhui kwenye kifaa hiki"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Pata toleo jipya la akaunti ili ubadilishe"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Imeshindwa kucheza maudhui yaliyopakuliwa hapa"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 1fd78d3842eb..8ee8fa22c61f 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"அக முனையம்"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் ஆப்ஸை இயக்கு"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux டெவெலப்மெண்ட் சூழல்"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Androidல் Linux டெர்மினலை இயக்கும்"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(பரிசோதனை) Androidடில் Linux டெர்மினலை இயக்கலாம்"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"நீங்கள் முடக்கினால், Linux டெர்மினல் தரவு அழிக்கப்படும்"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP சரிபார்ப்பு"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP சரிபார்க்கும் செயல்பாடுகளை அமை"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"பிழைதிருத்தம்"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"வெளிப்புறச் சாதனம்"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"இணைக்கப்பட்டுள்ள சாதனம்"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"இந்த மொபைல்"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"அனலாக்"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"இந்தச் சாதனத்தில் பிளே செய்ய முடியவில்லை"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"மாற்ற, கணக்கை மேம்படுத்துங்கள்"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"பதிவிறக்கங்களை இங்கே பிளே செய்ய முடியாது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index fc45d2c8e149..46350d5bf30c 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"స్థానిక టెర్మినల్"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ యాక్సెస్‌ను అందించే టెర్మినల్ యాప్‌ను ప్రారంభించండి"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux డెవలప్మెంట్ ఎన్విరాన్మెంట్"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Androidలో Linux టెర్మినల్‌ను రన్ చేయండి"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ప్రయోగాత్మకం) Linux టెర్మినల్‌ను Androidలో రన్ చేయండి"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"మీరు డిజేబుల్ చేస్తే, Linux టెర్మినల్ డేటా క్లియర్ అవుతుంది"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP చెకింగ్‌"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP తనిఖీ ప్రవర్తనను సెట్ చేయండి"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"డీబగ్గింగ్"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ఎక్స్‌టర్నల్ పరికరం"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"కనెక్ట్ చేసిన పరికరం"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ఈ ఫోన్"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"అనలాగ్"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ఈ పరికరంలో ప్లే చేయడం సాధ్యపడదు"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"మారడానికి ఖాతాను అప్‌గ్రేడ్ చేయండి"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ఇక్కడ డౌన్‌లోడ్‌లను ప్లే చేయడం సాధ్యపడదు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index d525bc538ef8..460782af8457 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"เทอร์มินัลในตัวเครื่อง"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"เปิดใช้งานแอปเทอร์มินัลที่ให้การเข้าถึงเชลล์ในตัวเครื่อง"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"สภาพแวดล้อมในการพัฒนาซอฟต์แวร์ Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"เรียกใช้เทอร์มินัล Linux บน Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ทดลอง) เรียกใช้เทอร์มินัล Linux ใน Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"หากปิดใช้ ระบบจะล้างข้อมูลเทอร์มินัล Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"การตรวจสอบ HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"ตั้งค่าการตรวจสอบ HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"การแก้ไขข้อบกพร่อง"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"อุปกรณ์ภายนอก"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"อุปกรณ์ที่เชื่อมต่อ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"โทรศัพท์เครื่องนี้"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"แอนะล็อก"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"เล่นในอุปกรณ์นี้ไม่ได้"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"อัปเกรดบัญชีเพื่อเปลี่ยน"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"เล่นเนื้อหาที่ดาวน์โหลดที่นี่ไม่ได้"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 1df74736d879..986b7771d9f5 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokal na terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Paganahin ang terminal app na nag-aalok ng lokal na shell access"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Development environment ng Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Paganahin ang Linux terminal sa Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Pang-eksperimento) Patakbuhin ang terminal ng Linux sa Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Kung idi-disable mo, maki-clear ang data ng terminal ng Linux"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Pagsusuring HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP checking behavior"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Pagde-debug"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External na Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Nakakonektang device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ang teleponong ito"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Hindi ma-play sa device na ito"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"I-upgrade ang account para lumipat"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Hindi mape-play ang mga download dito"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index d62269605e84..df47dacc7d7b 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Yerel terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Yerel kabuk erişimi sunan terminal uygulamasını etkinleştir"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux geliştirme ortamı"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android\'de Linux terminali çalıştırın"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Deneysel) Android\'de Linux terminali çalıştırın"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Devre dışı bırakırsanız Linux terminali verileri temizlenir"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP denetimi"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP denetimini ayarla"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Hata ayıklama"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Harici Cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Bağlı cihaz"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu cihazda oynatılamıyor"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Geçiş yapmak için hesabı yükseltin"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"İndirilenler burada oynatılamaz"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index eb10cb209c20..3ba99a2f443e 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Локальний термінал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Увімк. програму-термінал, що надає локальний доступ до оболонки"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Середовище Linux для розробки"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Запуск термінала Linux на Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Експериментальна функція) Запуск термінала Linux на Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Якщо вимкнути, дані термінала Linux буде видалено"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Перевірка HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Порядок перевірки HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Налагодження"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Зовнішній пристрій"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Підключений пристрій"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Цей телефон"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Аналоговий"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не можна відтворювати тут"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Потрібний платний обліковий запис"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Завантаження не відтворюватимуться"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 8b2eb3fb0189..e5e29faae8f5 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"پروفائل منتخب کریں"</string>
<string name="category_personal" msgid="6236798763159385225">"ذاتی"</string>
<string name="category_work" msgid="4014193632325996115">"دفتر"</string>
- <string name="category_private" msgid="4244892185452788977">"نجی"</string>
+ <string name="category_private" msgid="4244892185452788977">"پرائیویٹ"</string>
<string name="category_clone" msgid="1554511758987195974">"کلون کریں"</string>
<string name="development_settings_title" msgid="140296922921597393">"ڈویلپر کے اختیارات"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"ڈویلپر کے اختیارات فعال کریں"</string>
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"مقامی ٹرمینل"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"مقامی شیل رسائی پیش کرنے والی ٹرمینل ایپ فعال کریں"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"‏‫Linux ڈیولپمنٹ ماحول"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"‏‫Android پر Linux ٹرمینل چلائیں"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"‏(تجرباتی) Android پر Linux ٹرمینل چلائیں"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"‏اگر آپ غیر فعال کرتے ہیں تو Linux ٹرمینل کا ڈیٹا صاف ہو جائے گا"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"‏HDCP چیکنگ"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"‏HDCP چیکنگ برتاؤ سیٹ کریں"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"ڈیبگ کرنا"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"بیرونی آلہ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"منسلک آلہ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"یہ فون"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"اینالاگ"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"اس آلے پر چلایا نہیں جا سکتا"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"سوئچ کرنے کے لیے اکاؤنٹ اپ گریڈ کریں"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ڈاؤن لوڈز کو یہاں چلایا نہیں جا سکتا"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 62a6303fd45b..2417d5556bee 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Mahalliy terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Mahalliy terminalga kirishga ruxsat beruvchi terminal ilovani faollashtirish"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux dasturlash muhiti"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Android orqali Linux terminalini ishga tushirish"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Tajribaviy) Linux terminalini Android tizimida ishga tushiring"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Agar faolsizlantirsangiz, Linux terminal maʼlumotlari tozalanadi"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP tekshiruvi"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCPni tekshirish tartibi"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Nosozliklarni tuzatish"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Tashqi qurilma"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ulangan qurilma"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Shu telefon"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu qurilmada ijro etilmaydi"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Oʻtish uchun hisobingizni yangilang"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Yuklab olingan fayllar ijro etilmaydi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 1b90818fbaf9..0239a3f2c39d 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Dòng lệnh cục bộ"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Bật ứng dụng dòng lệnh cung cấp quyền truy cập vỏ cục bộ"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Môi trường phát triển Linux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Chạy thiết bị đầu cuối Linux trên Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Thử nghiệm) Chạy cửa sổ dòng lệnh Linux trên Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Nếu bạn tắt, dữ liệu trên cửa sổ dòng lệnh Linux sẽ bị xoá"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Kiểm tra HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Đặt hành vi kiểm tra HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Gỡ lỗi"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Thiết bị bên ngoài"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Thiết bị đã kết nối"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Điện thoại này"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Không phát được trên thiết bị này"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nâng cấp tài khoản để chuyển đổi"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Không thể phát các tệp đã tải xuống tại đây"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 94915650223f..22bfda4fe6fc 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"本地终端"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"启用终端应用,以便在本地访问 Shell"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux 开发环境"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"在 Android 上运行 Linux 终端"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(实验性)在 Android 上运行 Linux 终端"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"如果您停用它,Linux 终端数据会被清除"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP 检查"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"设置 HDCP 检查行为"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"调试"</string>
@@ -490,7 +491,7 @@
<string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"根据您的使用情况,估计能用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by" msgid="4113180890060388350">"目前电量为 <xliff:g id="LEVEL">%2$s</xliff:g>,估计能用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"估计能用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_discharge_by_only_short" msgid="5883041507426914446">"可以用到 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_discharge_by_only_short" msgid="5883041507426914446">"可用到 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"电池电量可能在<xliff:g id="TIME">%1$s</xliff:g> 前耗尽"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"剩余电池续航时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"剩余电池续航时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部设备"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"连接的设备"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"这部手机"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"模拟"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"辅助"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"无法在此设备上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"升级账号后才能切换"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"无法在此设备上播放下载的内容"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index aa3ac06298c5..594273a327ce 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"本機終端機"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux 開發環境"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"在 Android 上執行 Linux 終端機"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(實驗性質) 在 Android 上執行 Linux 終端機"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"停用將清除 Linux 終端機資料"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP 檢查"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"設定 HDCP 檢查行為"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"除錯"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連接的裝置"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這部手機"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"類比"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"無法在此裝置上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"請升級要切換的帳戶"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"無法在此播放下載內容"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index b5eb87da6de3..483dbf30b31c 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"本機終端機"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux 開發環境"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"在 Android 上執行 Linux 終端機"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(實驗功能) 在 Android 上執行 Linux 終端機"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"如果停用,系統會清除 Linux 終端機資料"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP 檢查"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"設定 HDCP 檢查行為"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"偵錯"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連結的裝置"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"類比"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"無法在這部裝置上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"請升級要切換的帳戶"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"這裡無法播放下載內容"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 57e0b8d8afeb..2bb3f225565e 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -358,7 +358,8 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Itheminali yasendaweni"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Nika amandla uhlelo lokusebenza letheminali olunikeza ukufinyelela kwasendaweni kwe-shell"</string>
<string name="enable_linux_terminal_title" msgid="5076044866895670637">"Indawo yokuthuthukiswa yeLinux"</string>
- <string name="enable_linux_terminal_summary" msgid="5893216510985145320">"Sebenzisa itheminali yeLinux ku-Android"</string>
+ <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Ukuhlola) Qalisa itheminali yeLinux ku-Android"</string>
+ <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Uma ukhubazekile, idatha egciniwe yeLinux izosuswa"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Ihlola i-HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Hlela ukuhlola ukuziphatha kwe-HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Ilungisa inkinga"</string>
@@ -591,12 +592,9 @@
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Idivayisi Yangaphandle"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Idivayisi exhunyiwe"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Le foni"</string>
- <!-- no translation found for media_transfer_digital_line_name (312091711951124301) -->
- <skip />
- <!-- no translation found for media_transfer_analog_line_name (1841163866716302104) -->
- <skip />
- <!-- no translation found for media_transfer_aux_line_name (894135835967856689) -->
- <skip />
+ <string name="media_transfer_digital_line_name" msgid="312091711951124301">"I-S/PDIF"</string>
+ <string name="media_transfer_analog_line_name" msgid="1841163866716302104">"I-Analog"</string>
+ <string name="media_transfer_aux_line_name" msgid="894135835967856689">"I-AUX"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ayikwazi ukudlala kule divayisi"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Thuthukisa i-akhawunti ukuze ushintshe"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Awukwazi ukudlala okudawunilodiwe lapha"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index c710aa35fa95..eaf155df4785 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -821,9 +821,9 @@
<!-- Title of checkbox setting that enables the Linux terminal app. [CHAR LIMIT=32] -->
<string name="enable_linux_terminal_title">Linux development environment</string>
- <!-- Summary of checkbox setting that enables the Linux terminal app. [CHAR LIMIT=64] -->
- <string name="enable_linux_terminal_summary">Run Linux terminal on Android</string>
- <!-- Disclaimer below the checkbox that disabling the Linux terminal app would clear its data. [CHAR LIMIT=64] -->
+ <!-- Summary of checkbox setting that enables the Linux terminal app. [CHAR LIMIT=none] -->
+ <string name="enable_linux_terminal_summary">(Experimental) Run Linux terminal on Android</string>
+ <!-- Disclaimer below the checkbox that disabling the Linux terminal app would clear its data. [CHAR LIMIT=none] -->
<string name="disable_linux_terminal_disclaimer">If you disable, Linux terminal data will be cleared</string>
<!-- HDCP checking title, used for debug purposes only. [CHAR LIMIT=25] -->
@@ -1419,7 +1419,7 @@
<!-- Name of the internal speaker and mic. [CHAR LIMIT=30] -->
<string name="media_transfer_this_device_name_desktop">This computer (internal)</string>
<!-- Name of the default media output of the TV. [CHAR LIMIT=30] -->
- <string name="media_transfer_this_device_name_tv">@string/tv_media_transfer_default</string>
+ <string name="media_transfer_this_device_name_tv">This TV</string>
<!-- Name of the dock device. [CHAR LIMIT=30] -->
<string name="media_transfer_dock_speaker_device_name">Dock speaker</string>
<!-- Default name of the external device. [CHAR LIMIT=30] -->
@@ -1462,12 +1462,11 @@
<!-- Media output switcher. Subtitle for devices connected through HDMI EARC if a device name is available. [CHAR LIMIT=NONE] -->
<string name="tv_media_transfer_earc_subtitle">Connected via eARC</string>
- <!-- TV media output switcher. Title for the default audio output of the device [CHAR LIMIT=NONE] -->
- <string name="tv_media_transfer_default">TV default</string>
- <!-- TV media output switcher. Subtitle for default audio output which is HDMI, e.g. TV dongle [CHAR LIMIT=NONE] -->
- <string name="tv_media_transfer_hdmi">HDMI output</string>
- <!-- TV media output switcher. Subtitle for default audio output which is internal speaker, i.e. panel VTs [CHAR LIMIT=NONE] -->
- <string name="tv_media_transfer_internal_speakers">Internal speakers</string>
+ <!-- TV media output switcher. Subtitle for default audio output which is internal speaker [CHAR LIMIT=NONE] -->
+ <string name="tv_media_transfer_internal_speakers">Built-in speaker</string>
+
+ <!-- TV media output switcher. Title for default audio output which is HDMI, e.g. TV dongle [CHAR LIMIT=NONE] -->
+ <string name="tv_media_transfer_hdmi_title">TV Audio</string>
<!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
<string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java
index c0117b952beb..30ce13bf3b00 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java
@@ -22,6 +22,7 @@ import android.os.UserHandle;
import android.util.Log;
import android.util.LruCache;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
/**
@@ -33,7 +34,7 @@ public class AppIconCacheManager {
@VisibleForTesting
static final int MAX_CACHE_SIZE_IN_KB = getMaxCacheInKb();
private static final String DELIMITER = ":";
- private static AppIconCacheManager sAppIconCacheManager;
+ private static volatile AppIconCacheManager sAppIconCacheManager;
private final LruCache<String, Drawable> mDrawableCache;
private AppIconCacheManager() {
@@ -52,11 +53,18 @@ public class AppIconCacheManager {
/**
* Get an {@link AppIconCacheManager} instance.
*/
- public static synchronized AppIconCacheManager getInstance() {
- if (sAppIconCacheManager == null) {
- sAppIconCacheManager = new AppIconCacheManager();
+ public static @NonNull AppIconCacheManager getInstance() {
+ AppIconCacheManager result = sAppIconCacheManager;
+ if (result == null) {
+ synchronized (AppIconCacheManager.class) {
+ result = sAppIconCacheManager;
+ if (result == null) {
+ result = new AppIconCacheManager();
+ sAppIconCacheManager = result;
+ }
+ }
}
- return sAppIconCacheManager;
+ return result;
}
/**
@@ -118,7 +126,7 @@ public class AppIconCacheManager {
*
* @see android.content.ComponentCallbacks2#onTrimMemory(int)
*/
- public void trimMemory(int level) {
+ public static void trimMemory(int level) {
if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
// Time to clear everything
if (sAppIconCacheManager != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index a87b8153b858..216574a5fff9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,6 +1,7 @@
package com.android.settingslib.bluetooth;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.UNKNOWN_VALUE_PLACEHOLDER;
+import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix;
import static com.android.settingslib.widget.AdaptiveOutlineDrawable.ICON_TYPE_ADVANCED;
import android.annotation.SuppressLint;
@@ -651,6 +652,13 @@ public class BluetoothUtils {
context.getContentResolver()));
}
+ /** Returns if the le audio sharing hysteresis mode fix is available. */
+ @WorkerThread
+ public static boolean isAudioSharingHysteresisModeFixAvailable(@Nullable Context context) {
+ return (audioSharingHysteresisModeFix() && Flags.enableLeAudioSharing())
+ || (context != null && isAudioSharingPreviewEnabled(context.getContentResolver()));
+ }
+
/** Returns if the le audio sharing is enabled. */
public static boolean isAudioSharingEnabled() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -733,13 +741,15 @@ public class BluetoothUtils {
@WorkerThread
public static boolean hasConnectedBroadcastSourceForBtDevice(
@Nullable BluetoothDevice device, @Nullable LocalBluetoothManager localBtManager) {
- if (Flags.audioSharingHysteresisModeFix()) {
+ if (localBtManager == null) {
+ Log.d(TAG, "Skip check hasConnectedBroadcastSourceForBtDevice due to arg is null");
+ return false;
+ }
+ if (isAudioSharingHysteresisModeFixAvailable(localBtManager.getContext())) {
return hasActiveLocalBroadcastSourceForBtDevice(device, localBtManager);
}
LocalBluetoothLeBroadcastAssistant assistant =
- localBtManager == null
- ? null
- : localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
if (device == null || assistant == null) {
Log.d(TAG, "Skip check hasConnectedBroadcastSourceForBtDevice due to arg is null");
return false;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index d0827b30efc9..4eb0567c67d9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -133,8 +133,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
* If an ACTION_UUID intent comes in within
* MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
* again with the new UUIDs
+ * The value is reset if a manual disconnection happens.
*/
- private long mConnectAttempted;
+ private long mConnectAttempted = -1;
// Active device state
private boolean mIsActiveDeviceA2dp = false;
@@ -369,6 +370,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
public void disconnect() {
+ mConnectAttempted = -1;
synchronized (mProfileLock) {
if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
for (CachedBluetoothDevice member : getMemberDevice()) {
@@ -983,15 +985,19 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
if (BluetoothUtils.D) {
- Log.d(TAG, "onUuidChanged: Time since last connect="
- + (SystemClock.elapsedRealtime() - mConnectAttempted));
+ long lastConnectAttempted = mConnectAttempted == -1 ? 0 : mConnectAttempted;
+ Log.d(
+ TAG,
+ "onUuidChanged: Time since last connect/manual disconnect="
+ + (SystemClock.elapsedRealtime() - lastConnectAttempted));
}
/*
* If a connect was attempted earlier without any UUID, we will do the connect now.
* Otherwise, allow the connect on UUID change.
*/
- if ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime()) {
+ if (mConnectAttempted != -1
+ && (mConnectAttempted + timeout) > SystemClock.elapsedRealtime()) {
Log.d(TAG, "onUuidChanged: triggering connectDevice");
connectDevice();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index b3e48b26782e..fa28cf6c8a76 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -94,6 +94,14 @@ public class HearingAidDeviceManager {
boolean setSubDeviceIfNeeded(CachedBluetoothDevice newDevice) {
final long hiSyncId = newDevice.getHiSyncId();
if (isValidHiSyncId(hiSyncId)) {
+ // The remote device supports CSIP, the other ear should be processed as a member
+ // device. Ignore hiSyncId grouping from ASHA here.
+ if (newDevice.getProfiles().stream().anyMatch(
+ profile -> profile instanceof CsipSetCoordinatorProfile)) {
+ Log.w(TAG, "Skip ASHA grouping since this device supports CSIP");
+ return false;
+ }
+
final CachedBluetoothDevice hearingAidDevice = getCachedDevice(hiSyncId);
// Just add one of the hearing aids from a pair in the list that is shown in the UI.
// Once there is another device with the same hiSyncId, to add new device as sub
@@ -161,6 +169,7 @@ public class HearingAidDeviceManager {
// device. Ignore hiSyncId grouping from ASHA here.
if (cachedDevice.getProfiles().stream().anyMatch(
profile -> profile instanceof CsipSetCoordinatorProfile)) {
+ Log.w(TAG, "Skip ASHA grouping since this device supports CSIP");
continue;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 6a9d5687370e..b52ed42d567f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -18,6 +18,8 @@ package com.android.settingslib.bluetooth;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+import static com.android.settingslib.Utils.isAudioModeOngoingCall;
+
import static java.util.stream.Collectors.toList;
import android.annotation.CallbackExecutor;
@@ -54,7 +56,6 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.settingslib.R;
-import com.android.settingslib.flags.Flags;
import com.google.common.collect.ImmutableList;
@@ -303,6 +304,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
+ ", sourceId = "
+ sourceId);
}
+ updateFallbackActiveDeviceIfNeeded();
}
@Override
@@ -390,9 +392,6 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
+ ", state = "
+ state);
}
- if (BluetoothUtils.isConnected(state)) {
- updateFallbackActiveDeviceIfNeeded();
- }
}
};
@@ -1130,18 +1129,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded for work profile.");
return;
}
- if (mServiceBroadcast == null) {
- Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to broadcast profile is null");
- return;
- }
- List<BluetoothLeBroadcastMetadata> sources = mServiceBroadcast.getAllBroadcastMetadata();
- if (sources.stream()
- .noneMatch(source -> mServiceBroadcast.isPlaying(source.getBroadcastId()))) {
- Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no broadcast ongoing");
- return;
- }
- if (mServiceBroadcastAssistant == null) {
- Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null");
+ if (isAudioModeOngoingCall(mContext)) {
+ Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to ongoing call");
return;
}
Map<Integer, List<BluetoothDevice>> deviceGroupsInBroadcast = getDeviceGroupsInBroadcast();
@@ -1152,7 +1141,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
int targetGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
int fallbackActiveGroupId = BluetoothUtils.getPrimaryGroupIdForBroadcast(
mContext.getContentResolver());
- if (Flags.audioSharingHysteresisModeFix()) {
+ if (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)) {
int userPreferredPrimaryGroupId = getUserPreferredPrimaryGroupId();
if (userPreferredPrimaryGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
&& deviceGroupsInBroadcast.containsKey(userPreferredPrimaryGroupId)) {
@@ -1193,7 +1182,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
@NonNull
private Map<Integer, List<BluetoothDevice>> getDeviceGroupsInBroadcast() {
- boolean hysteresisModeFixEnabled = Flags.audioSharingHysteresisModeFix();
+ boolean hysteresisModeFixEnabled =
+ BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext);
List<BluetoothDevice> connectedDevices = mServiceBroadcastAssistant.getConnectedDevices();
return connectedDevices.stream()
.filter(
@@ -1227,12 +1217,13 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
}
}
+ Log.d(TAG, "updateFallbackActiveDeviceIfNeeded, earliest group id = " + targetGroupId);
return targetGroupId;
}
@Nullable
private CachedBluetoothDevice getMainDevice(@Nullable List<BluetoothDevice> devices) {
- if (devices == null || devices.size() == 1) return null;
+ if (devices == null || devices.isEmpty()) return null;
List<CachedBluetoothDevice> cachedDevices =
devices.stream()
.map(device -> mDeviceManager.findDevice(device))
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
index 91a99aed6db5..a0a6d2698d8c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
@@ -35,11 +35,7 @@ val LocalBluetoothLeBroadcastAssistant.onSourceConnectedOrRemoved: Flow<Unit>
sink: BluetoothDevice,
sourceId: Int,
state: BluetoothLeBroadcastReceiveState
- ) {
- if (BluetoothUtils.isConnected(state)) {
- launch { send(Unit) }
- }
- }
+ ) {}
override fun onSourceRemoved(sink: BluetoothDevice, sourceId: Int, reason: Int) {
launch { send(Unit) }
@@ -55,7 +51,9 @@ val LocalBluetoothLeBroadcastAssistant.onSourceConnectedOrRemoved: Flow<Unit>
override fun onSourceFound(source: BluetoothLeBroadcastMetadata) {}
- override fun onSourceAdded(sink: BluetoothDevice, sourceId: Int, reason: Int) {}
+ override fun onSourceAdded(sink: BluetoothDevice, sourceId: Int, reason: Int) {
+ launch { send(Unit) }
+ }
override fun onSourceAddFailed(
sink: BluetoothDevice,
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
index 717a8ee32082..aa2ede311e23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
@@ -33,6 +33,8 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
import android.media.MediaRoute2Info;
import android.os.SystemProperties;
import android.util.SparseIntArray;
@@ -116,14 +118,15 @@ public class DeviceIconUtil {
@SuppressLint("SwitchIntDef")
@DrawableRes
- private static int getIconResourceIdForTv(@MediaRoute2Info.Type int type) {
+ private int getIconResourceIdForTv(@MediaRoute2Info.Type int type) {
return switch (type) {
case MediaRoute2Info.TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_HEADSET ->
R.drawable.ic_headphone;
case MediaRoute2Info.TYPE_USB_ACCESSORY -> R.drawable.ic_usb;
case MediaRoute2Info.TYPE_DOCK -> R.drawable.ic_dock_device;
- case MediaRoute2Info.TYPE_HDMI, MediaRoute2Info.TYPE_BUILTIN_SPEAKER ->
- R.drawable.ic_tv;
+ case MediaRoute2Info.TYPE_BUILTIN_SPEAKER ->
+ isPanelTv() ? R.drawable.ic_tv : R.drawable.ic_tv_box_internal_speaker;
+ case MediaRoute2Info.TYPE_HDMI -> R.drawable.ic_tv;
case MediaRoute2Info.TYPE_HDMI_ARC, MediaRoute2Info.TYPE_HDMI_EARC ->
R.drawable.ic_hdmi;
case MediaRoute2Info.TYPE_WIRED_HEADSET, MediaRoute2Info.TYPE_WIRED_HEADPHONES ->
@@ -132,6 +135,23 @@ public class DeviceIconUtil {
};
}
+ private boolean isPanelTv() {
+ if (mContext == null) {
+ // This should only happen during testing.
+ return true;
+ }
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ AudioDeviceInfo[] devices = audioManager.getDevices(
+ AudioManager.GET_DEVICES_OUTPUTS);
+ // If we have an HDMI output (not ARC/eARC) we can assume it's a dongle / set top box.
+ for (AudioDeviceInfo device : devices) {
+ if (device.getType() == TYPE_HDMI) {
+ return false;
+ }
+ }
+ return true;
+ }
+
static {
AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_DEVICE);
AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_HEADSET, MediaRoute2Info.TYPE_USB_HEADSET);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
index 83ee9751329f..80e5e5981912 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
@@ -15,6 +15,7 @@
*/
package com.android.settingslib.media;
+import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET;
import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
import static android.media.AudioDeviceInfo.TYPE_USB_ACCESSORY;
@@ -103,7 +104,8 @@ public class InputMediaDevice extends MediaDevice {
TYPE_USB_DEVICE,
TYPE_USB_HEADSET,
TYPE_USB_ACCESSORY,
- TYPE_BLUETOOTH_SCO ->
+ TYPE_BLUETOOTH_SCO,
+ TYPE_BLE_HEADSET ->
true;
default -> false;
};
@@ -124,7 +126,7 @@ public class InputMediaDevice extends MediaDevice {
mProductName != null
? mProductName
: mContext.getString(R.string.media_transfer_usb_device_mic_name);
- case TYPE_BLUETOOTH_SCO ->
+ case TYPE_BLUETOOTH_SCO, TYPE_BLE_HEADSET ->
mProductName != null
? mProductName
: mContext.getString(R.string.media_transfer_bt_device_mic_name);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 2321097d42d7..b01b7c9048ba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -390,6 +390,16 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
}
/**
+ * Get the {@link MediaRoute2Info.Type} of the device.
+ */
+ public int getRouteType() {
+ if (mRouteInfo == null) {
+ return TYPE_UNKNOWN;
+ }
+ return mRouteInfo.getType();
+ }
+
+ /**
* Checks if route's volume is fixed, if true, we should disable volume control for the device.
*
* @return route for this device is fixed.
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 4766a869e406..6ff1a99156ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -29,6 +29,7 @@ import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
import static android.media.MediaRoute2Info.TYPE_LINE_DIGITAL;
import static android.media.MediaRoute2Info.TYPE_LINE_ANALOG;
import static android.media.MediaRoute2Info.TYPE_AUX_LINE;
+
import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
import android.Manifest;
@@ -40,6 +41,7 @@ import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
import android.media.MediaRoute2Info;
import android.media.RouteListingPreference;
+import android.os.Build;
import android.os.SystemProperties;
import android.util.Log;
@@ -72,7 +74,7 @@ public class PhoneMediaDevice extends MediaDevice {
/** Returns this device name for media transfer. */
public static @NonNull String getMediaTransferThisDeviceName(@NonNull Context context) {
if (isTv(context)) {
- return context.getString(R.string.media_transfer_this_device_name_tv);
+ return Build.MODEL;
} else if (isTablet()) {
return context.getString(R.string.media_transfer_this_device_name_tablet);
} else if (inputRoutingEnabledAndIsDesktop(context)) {
@@ -110,7 +112,7 @@ public class PhoneMediaDevice extends MediaDevice {
name = getMediaTransferThisDeviceName(context);
break;
case TYPE_HDMI:
- name = context.getString(isTv ? R.string.tv_media_transfer_default :
+ name = context.getString(isTv ? R.string.tv_media_transfer_hdmi_title :
R.string.media_transfer_external_device_name);
break;
case TYPE_HDMI_ARC:
@@ -223,8 +225,6 @@ public class PhoneMediaDevice extends MediaDevice {
switch (mRouteInfo.getType()) {
case TYPE_BUILTIN_SPEAKER:
return mContext.getString(R.string.tv_media_transfer_internal_speakers);
- case TYPE_HDMI:
- return mContext.getString(R.string.tv_media_transfer_hdmi);
case TYPE_HDMI_ARC:
if (getHdmiOutDeviceName(mContext) == null) {
// Connection type is already part of the title.
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
index 5eeb49a0b398..6842d0a949af 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
@@ -204,6 +204,13 @@ public class TestModeBuilder {
return this;
}
+ public TestModeBuilder implicitForPackage(String pkg) {
+ setPackage(pkg);
+ setId(ZenModeConfig.implicitRuleId(pkg));
+ setName("Do Not Disturb (" + pkg + ")");
+ return this;
+ }
+
public TestModeBuilder setActive(boolean active) {
if (active) {
mConfigZenRule.enabled = true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index 3cc111f6e099..d5cfe55813ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -24,7 +24,6 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleEvent;
import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleTime;
-import static android.service.notification.ZenModeConfig.tryParseCountdownConditionId;
import static android.service.notification.ZenModeConfig.tryParseEventConditionId;
import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId;
@@ -209,6 +208,11 @@ public class ZenMode implements Parcelable {
}
@NonNull
+ public Kind getKind() {
+ return mKind;
+ }
+
+ @NonNull
public Status getStatus() {
return mStatus;
}
@@ -225,27 +229,6 @@ public class ZenMode implements Parcelable {
}
/**
- * Returns a "dynamic" trigger description. For some modes (such as manual Do Not Disturb)
- * when activated, we know when (and if) the mode is expected to end on its own; this dynamic
- * description reflects that. In other cases, returns {@link #getTriggerDescription}.
- */
- @Nullable
- public String getDynamicDescription(Context context) {
- if (isManualDnd() && isActive()) {
- long countdownEndTime = tryParseCountdownConditionId(mRule.getConditionId());
- if (countdownEndTime > 0) {
- CharSequence formattedTime = ZenModeConfig.getFormattedTime(context,
- countdownEndTime, ZenModeConfig.isToday(countdownEndTime),
- context.getUserId());
- return context.getString(com.android.internal.R.string.zen_mode_until,
- formattedTime);
- }
- }
-
- return getTriggerDescription();
- }
-
- /**
* Returns the {@link ZenIcon.Key} corresponding to the icon resource for this mode. This can be
* either app-provided (via {@link AutomaticZenRule#setIconResId}, user-chosen (via the icon
* picker in Settings), or a default icon based on the mode {@link Kind} and {@link #getType}.
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java
new file mode 100644
index 000000000000..f5776989917e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.notification.modes;
+
+import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
+import static android.service.notification.ZenModeConfig.tryParseCountdownConditionId;
+
+import android.content.Context;
+import android.service.notification.SystemZenRules;
+import android.service.notification.ZenModeConfig;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.google.common.base.Strings;
+
+public final class ZenModeDescriptions {
+
+ private final Context mContext;
+
+ public ZenModeDescriptions(@NonNull Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Returns a version of the mode's trigger description that might be "dynamic".
+ *
+ * <p>For some modes (such as manual Do Not Disturb) when activated, we know when (and if) the
+ * mode is expected to end on its own; this description reflects that. In other cases,
+ * returns {@link ZenMode#getTriggerDescription}.
+ */
+ @Nullable
+ public String getTriggerDescription(@NonNull ZenMode mode) {
+ if (mode.isManualDnd() && mode.isActive()) {
+ long countdownEndTime = tryParseCountdownConditionId(mode.getRule().getConditionId());
+ if (countdownEndTime > 0) {
+ CharSequence formattedTime = ZenModeConfig.getFormattedTime(mContext,
+ countdownEndTime, ZenModeConfig.isToday(countdownEndTime),
+ mContext.getUserId());
+ return mContext.getString(com.android.internal.R.string.zen_mode_until,
+ formattedTime);
+ }
+ }
+
+ return Strings.emptyToNull(mode.getTriggerDescription());
+ }
+
+ /**
+ * Returns a version of the {@link ZenMode} trigger description that is suitable for
+ * accessibility (for example, where abbreviations are expanded to full words).
+ *
+ * <p>Returns {@code null} If the standard trigger description (returned by
+ * {@link #getTriggerDescription}) is sufficient.
+ */
+ @Nullable
+ public String getTriggerDescriptionForAccessibility(@NonNull ZenMode mode) {
+ // Only one special case: time-based schedules, where we want to use full day names.
+ if (mode.isSystemOwned() && mode.getType() == TYPE_SCHEDULE_TIME) {
+ ZenModeConfig.ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(
+ mode.getRule().getConditionId());
+ if (schedule != null) {
+ String fullDaysSummary = SystemZenRules.getDaysOfWeekFull(mContext, schedule);
+ if (fullDaysSummary != null) {
+ return fullDaysSummary + ", " + SystemZenRules.getTimeSummary(mContext,
+ schedule);
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
index b41e9703d427..4c4ce2a61851 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
@@ -221,6 +221,7 @@ class AudioSharingRepositoryImpl(
override suspend fun audioSharingAvailable(): Boolean {
return withContext(backgroundCoroutineContext) {
BluetoothUtils.isAudioSharingEnabled()
+ || BluetoothUtils.isAudioSharingPreviewEnabled(contentResolver)
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
index 18a4c6d1748d..791d86611b06 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
@@ -26,4 +26,6 @@ interface AudioSharingLogger {
fun onVolumeMapChanged(map: Map<Int, Int>)
fun onSetDeviceVolumeRequested(volume: Int)
+
+ fun onAudioSharingAvailabilityRequestedError(requestFrom: String, e: String)
} \ No newline at end of file
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
index cc4cc8d4ab96..731b3a136cd7 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
@@ -43,4 +43,8 @@ class FakeAudioSharingRepositoryLogger : AudioSharingLogger {
override fun onSetDeviceVolumeRequested(volume: Int) {
mutableLogs.add("onSetVolumeRequested volume=$volume")
}
+
+ override fun onAudioSharingAvailabilityRequestedError(requestFrom: String, e: String) {
+ mutableLogs.add("onAudioSharingAvailabilityRequestedError, requestFrom=$requestFrom")
+ }
} \ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
index 1b0e1f1236c8..013ff923e130 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
@@ -16,11 +16,14 @@
package com.android.settingslib.applications;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import android.graphics.drawable.Drawable;
+import android.util.Log;
import org.junit.After;
import org.junit.Before;
@@ -30,9 +33,12 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import java.util.concurrent.atomic.AtomicInteger;
+
@RunWith(RobolectricTestRunner.class)
public class AppIconCacheManagerTest {
+ private static final String TAG = "AppIconCacheManagerTest";
private static final String APP_PACKAGE_NAME = "com.test.app";
private static final String APP_PACKAGE_NAME1 = "com.test.app1";
private static final String APP_PACKAGE_NAME2 = "com.test.app2";
@@ -176,4 +182,28 @@ public class AppIconCacheManagerTest {
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME2, APP_UID)).isNull();
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME3, APP_UID)).isNull();
}
+
+ @Test
+ public void trimMemory_multiThread_shouldNotCrash() {
+ int numberOfTasks = 10;
+ AtomicInteger completedTasks = new AtomicInteger(0);
+
+ Runnable task =
+ () -> {
+ String threadName = Thread.currentThread().getName();
+ Log.i(TAG, "Starting thread: " + threadName);
+ AppIconCacheManager.getInstance().trimMemory(TRIM_MEMORY_BACKGROUND);
+ completedTasks.incrementAndGet();
+ Log.i(TAG, "Ending thread: " + threadName);
+ };
+
+ for (Integer i = 0; i < numberOfTasks; i++) {
+ Thread thread = new Thread(task);
+ thread.start();
+ }
+
+ while (completedTasks.get() < numberOfTasks) {
+ // Wait until all threads are finished.
+ }
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 6d481dbe64e9..fa5d54283a17 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -1256,4 +1256,40 @@ public class BluetoothUtilsTest {
assertThat(BluetoothUtils.isAudioSharingUIAvailable(mContext)).isTrue();
}
+
+ @Test
+ public void isAudioSharingHysteresisModeFixAvailable_mainAndPreviewFlagOff_returnsFalse() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+ assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isFalse();
+ }
+
+ @Test
+ public void isAudioSharingHysteresisModeFixAvailable_hysteresisFixFlagOff_returnsFalse() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+ assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isFalse();
+ }
+
+ @Test
+ public void isAudioSharingHysteresisModeFixAvailable_previewFlagOn_returnsTrue() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+ assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isTrue();
+ }
+
+ @Test
+ public void isAudioSharingHysteresisModeFixAvailable_mainAndPreviewFlagOn_returnsTrue() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+ assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isTrue();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
index 883640db5e27..5ac22a732f3c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
@@ -173,7 +173,7 @@ public class DeviceIconUtilTest {
public void getIconResIdFromMediaRouteType_tv_builtinSpeaker_isTv() {
assertThat(new DeviceIconUtil(/* isTv */ true)
.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_BUILTIN_SPEAKER))
- .isEqualTo(R.drawable.ic_tv);
+ .isAnyOf(R.drawable.ic_tv, R.drawable.ic_tv_box_internal_speaker);
}
@Test
@@ -331,7 +331,7 @@ public class DeviceIconUtilTest {
public void getIconResIdFromAudioDeviceType_tv_builtinSpeaker_isTv() {
assertThat(new DeviceIconUtil(/* isTv */ true)
.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER))
- .isEqualTo(R.drawable.ic_tv);
+ .isAnyOf(R.drawable.ic_tv, R.drawable.ic_tv_box_internal_speaker);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
index 7775b912e51d..8624c4df833b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
@@ -38,6 +38,7 @@ public class InputMediaDeviceTest {
private final int WIRED_HEADSET_ID = 2;
private final int USB_HEADSET_ID = 3;
private final int BT_HEADSET_ID = 4;
+ private final int BLE_HEADSET_ID = 5;
private final int MAX_VOLUME = 1;
private final int CURRENT_VOLUME = 0;
private final boolean IS_VOLUME_FIXED = true;
@@ -45,6 +46,7 @@ public class InputMediaDeviceTest {
private static final String PRODUCT_NAME_WIRED_HEADSET = "My Wired Headset";
private static final String PRODUCT_NAME_USB_HEADSET = "My USB Headset";
private static final String PRODUCT_NAME_BT_HEADSET = "My Bluetooth Headset";
+ private static final String PRODUCT_NAME_BLE_HEADSET = "My BLE Headset";
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -163,4 +165,35 @@ public class InputMediaDeviceTest {
assertThat(btMediaDevice.getName())
.isEqualTo(mContext.getString(R.string.media_transfer_bt_device_mic_name));
}
+
+ @Test
+ public void getName_returnCorrectName_bleHeadset() {
+ InputMediaDevice bleMediaDevice =
+ InputMediaDevice.create(
+ mContext,
+ String.valueOf(BLE_HEADSET_ID),
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED,
+ PRODUCT_NAME_BLE_HEADSET);
+ assertThat(bleMediaDevice).isNotNull();
+ assertThat(bleMediaDevice.getName()).isEqualTo(PRODUCT_NAME_BLE_HEADSET);
+ }
+
+ @Test
+ public void getName_returnCorrectName_bleHeadset_nullProductName() {
+ InputMediaDevice bleMediaDevice =
+ InputMediaDevice.create(
+ mContext,
+ String.valueOf(BLE_HEADSET_ID),
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED,
+ null);
+ assertThat(bleMediaDevice).isNotNull();
+ assertThat(bleMediaDevice.getName())
+ .isEqualTo(mContext.getString(R.string.media_transfer_bt_device_mic_name));
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeDescriptionsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeDescriptionsTest.java
new file mode 100644
index 000000000000..2b3accdbb906
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeDescriptionsTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 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.notification.modes;
+
+import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
+import static android.service.notification.SystemZenRules.PACKAGE_ANDROID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.service.notification.ZenModeConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Calendar;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenModeDescriptionsTest {
+
+ private final ZenModeDescriptions mDescriptions = new ZenModeDescriptions(
+ RuntimeEnvironment.getApplication());
+
+ @Test
+ public void getTriggerDescriptionForAccessibility_scheduleTime_usesFullDays() {
+ ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
+ scheduleInfo.days = new int[] { Calendar.MONDAY };
+ scheduleInfo.startHour = 11;
+ scheduleInfo.endHour = 15;
+ ZenMode mode = new TestModeBuilder()
+ .setPackage(PACKAGE_ANDROID)
+ .setType(TYPE_SCHEDULE_TIME)
+ .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
+ .build();
+
+ assertThat(mDescriptions.getTriggerDescriptionForAccessibility(mode))
+ .isEqualTo("Monday, 11:00 AM - 3:00 PM");
+ }
+
+ @Test
+ public void getTriggerDescriptionForAccessibility_otherMode_isNull() {
+ ZenMode mode = new TestModeBuilder().setTriggerDescription("When December ends").build();
+ assertThat(mDescriptions.getTriggerDescriptionForAccessibility(mode)).isNull();
+ }
+}
diff --git a/packages/SettingsProvider/res/xml/bookmarks.xml b/packages/SettingsProvider/res/xml/bookmarks.xml
index 22d02262c388..645b275e2af5 100644
--- a/packages/SettingsProvider/res/xml/bookmarks.xml
+++ b/packages/SettingsProvider/res/xml/bookmarks.xml
@@ -32,6 +32,9 @@
'y': YouTube
-->
<bookmarks>
+ <!-- TODO(b/358569822): Remove this from Settings DB
+ This is legacy implementation to store bookmarks in Settings DB, which is deprecated and
+ no longer used -->
<bookmark
role="android.app.role.BROWSER"
shortcut="b" />
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 927a1c59cc76..1f291cdefb03 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -107,6 +107,8 @@ public class SecureSettings {
Settings.Secure.DISPLAY_WHITE_BALANCE_ENABLED,
Settings.Secure.SYNC_PARENT_SOUNDS,
Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+ Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
+ Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
// ACCESSIBILITY_QS_TARGETS needs to be restored after ENABLED_ACCESSIBILITY_SERVICES
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 3530e0f5f9de..8e7180c4dc8d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -78,6 +78,7 @@ public class SystemSettings {
Settings.System.SHOW_WEB_SUGGESTIONS,
Settings.System.SIP_CALL_OPTIONS,
Settings.System.SIP_RECEIVE_CALLS,
+ Settings.System.TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION,
Settings.System.POINTER_SPEED,
Settings.System.POINTER_FILL_STYLE,
Settings.System.POINTER_STROKE_STYLE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 8f58e8cd1973..32d4580f67ec 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -462,5 +462,16 @@ public class GlobalSettingsValidators {
Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE_NONE,
Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE_COMPANION
));
+ VALIDATORS.put(Global.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Global.HEARING_DEVICE_LOCAL_NOTIFICATION, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(
+ Global.Wearable.WEAR_SYSTEM_STATUS_TRAY_CONFIGURATION,
+ new DiscreteValueValidator(
+ new String[] {
+ String.valueOf(
+ Global.Wearable.STATUS_TRAY_CONFIGURATION_DEFAULT),
+ String.valueOf(
+ Global.Wearable.STATUS_TRAY_CONFIGURATION_SYSTEM_HIDDEN)
+ }));
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 6d73ee27f076..abd5b9a4a4bb 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -160,6 +160,9 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.DISPLAY_WHITE_BALANCE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SYNC_PARENT_SOUNDS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
+ new InclusiveIntegerRangeValidator(0, 1));
VALIDATORS.put(Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.QS_TILES, TILE_LIST_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 558ccaf7a707..cfc7743f0a8d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -213,6 +213,8 @@ public class SystemSettingsValidators {
VALIDATORS.put(System.SIP_ADDRESS_ONLY, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.SIP_ASK_ME_EACH_TIME, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.POINTER_SPEED, new InclusiveFloatRangeValidator(-7, 7));
+ VALIDATORS.put(System.TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION,
+ NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(System.POINTER_FILL_STYLE,
new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_FILL_BEGIN,
POINTER_ICON_VECTOR_STYLE_FILL_END));
@@ -263,6 +265,5 @@ public class SystemSettingsValidators {
VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ALL, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(System.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, ANY_STRING_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index fbce6ca07b3e..aca2c4ef2a49 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -16,6 +16,7 @@
package com.android.providers.settings;
+import static android.provider.DeviceConfig.DUMP_ARG_NAMESPACE;
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_NONE;
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT;
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT;
@@ -42,6 +43,7 @@ import android.provider.DeviceConfigShellCommandHandler;
import android.provider.Settings;
import android.provider.Settings.Config.SyncDisabledMode;
import android.provider.UpdatableDeviceConfigServiceReadiness;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.util.FastPrintWriter;
@@ -55,11 +57,13 @@ import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.regex.Pattern;
/**
* Receives shell commands from the command line related to device config flags, and dispatches them
@@ -80,6 +84,7 @@ public final class DeviceConfigService extends Binder {
final SettingsProvider mProvider;
private static final String TAG = "DeviceConfigService";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public DeviceConfigService(SettingsProvider provider) {
mProvider = provider;
@@ -97,14 +102,35 @@ public final class DeviceConfigService extends Binder {
}
}
+ // TODO(b/364399200): add unit test
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ String filter = null;
if (android.provider.flags.Flags.dumpImprovements()) {
- pw.print("SyncDisabledForTests: ");
- MyShellCommand.getSyncDisabledForTests(pw, pw);
+ if (args.length > 0) {
+ switch (args[0]) {
+ case DUMP_ARG_NAMESPACE:
+ if (args.length < 2) {
+ throw new IllegalArgumentException("argument " + DUMP_ARG_NAMESPACE
+ + " requires an extra argument");
+ }
+ filter = args[1];
+ if (DEBUG) {
+ Slog.d(TAG, "dump(): setting filter as " + filter);
+ }
+ break;
+ default:
+ Slog.w(TAG, "dump(): ignoring invalid arguments: " + Arrays.toString(args));
+ break;
+ }
+ }
+ if (filter == null) {
+ pw.print("SyncDisabledForTests: ");
+ MyShellCommand.getSyncDisabledForTests(pw, pw);
- pw.print("UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService(): ");
- pw.println(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
+ pw.print("UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService(): ");
+ pw.println(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
+ }
pw.println("DeviceConfig provider: ");
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd)) {
@@ -117,8 +143,16 @@ public final class DeviceConfigService extends Binder {
IContentProvider iprovider = mProvider.getIContentProvider();
pw.println("DeviceConfig flags:");
+ Pattern lineFilter = filter == null ? null : Pattern.compile("^.*" + filter + ".*\\/.*$");
for (String line : MyShellCommand.listAll(iprovider)) {
- pw.println(line);
+ if (lineFilter == null || lineFilter.matcher(line).matches()) {
+ pw.println(line);
+ }
+ }
+
+ if (filter != null) {
+ // TODO(b/364399200): use filter to skip instead?
+ return;
}
ArrayList<String> missingFiles = new ArrayList<String>();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/OWNERS b/packages/SettingsProvider/src/com/android/providers/settings/OWNERS
index 0b7181606247..b0086c180cbd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/OWNERS
+++ b/packages/SettingsProvider/src/com/android/providers/settings/OWNERS
@@ -1 +1,2 @@
-per-file WritableNamespacePrefixes.java = cbrubaker@google.com,tedbauer@google.com
+per-file WritableNamespacePrefixes.java = mpgroover@google.com,tedbauer@google.com
+per-file WritableNamespaces.java = mpgroover@google.com,tedbauer@google.com
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index fb0aaf8e5ae1..5ae11bacb445 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2124,6 +2124,15 @@ class SettingsProtoDumpUtil {
SecureSettingsProto.Display.SCREEN_RESOLUTION_MODE);
p.end(displayToken);
+ final long doubleTapPowerButtonToken = p.start(SecureSettingsProto.DOUBLE_TAP_POWER_BUTTON);
+ dumpSetting(s, p,
+ Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
+ SecureSettingsProto.DoubleTapPowerButton.GESTURE_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
+ SecureSettingsProto.DoubleTapPowerButton.GESTURE);
+ p.end(doubleTapPowerButtonToken);
+
final long dozeToken = p.start(SecureSettingsProto.DOZE);
dumpSetting(s, p,
Settings.Secure.DOZE_ENABLED,
@@ -3037,6 +3046,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.System.TOUCHPAD_TAP_DRAGGING,
SystemSettingsProto.Touchpad.TAP_DRAGGING);
+ dumpSetting(s, p,
+ Settings.System.TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION,
+ SystemSettingsProto.Touchpad.THREE_FINGER_TAP_CUSTOMIZATION);
p.end(touchpadToken);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 603a91195d04..03fea37deaf5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2434,28 +2434,40 @@ public class SettingsProvider extends ContentProvider {
context.checkCallingOrSelfPermission(
Manifest.permission.WRITE_DEVICE_CONFIG)
== PackageManager.PERMISSION_GRANTED;
- boolean isRoot = Binder.getCallingUid() == Process.ROOT_UID;
+ // Only the shell user and tests request the allowlist permission; this is used to force
+ // the WRITE_ALLOWLISTED_DEVICE_CONFIG path to log any flags that need to be allowlisted.
+ boolean isRestrictedShell = android.security.Flags.protectDeviceConfigFlags()
+ && hasAllowlistPermission;
- if (isRoot) {
- return;
- }
-
- if (hasWritePermission) {
+ if (!isRestrictedShell && hasWritePermission) {
assertCallingUserDenyList(flags);
} else if (hasAllowlistPermission) {
for (String flag : flags) {
boolean namespaceAllowed = false;
- for (String allowlistedPrefix : WritableNamespacePrefixes.ALLOWLIST) {
- if (flag.startsWith(allowlistedPrefix)) {
+ if (isRestrictedShell) {
+ int delimiterIndex = flag.indexOf("/");
+ String flagNamespace;
+ if (delimiterIndex != -1) {
+ flagNamespace = flag.substring(0, delimiterIndex);
+ } else {
+ flagNamespace = flag;
+ }
+ if (WritableNamespaces.ALLOWLIST.contains(flagNamespace)) {
namespaceAllowed = true;
- break;
+ }
+ } else {
+ for (String allowlistedPrefix : WritableNamespacePrefixes.ALLOWLIST) {
+ if (flag.startsWith(allowlistedPrefix)) {
+ namespaceAllowed = true;
+ break;
+ }
}
}
if (!namespaceAllowed && !DeviceConfig.getAdbWritableFlags().contains(flag)) {
- throw new SecurityException("Permission denial for flag '"
- + flag
- + "'; allowlist permission granted, but must add flag to the allowlist.");
+ Slog.wtf(LOG_TAG, "Permission denial for flag '" + flag
+ + "'; allowlist permission granted, but must add flag to the "
+ + "allowlist");
}
}
assertCallingUserDenyList(flags);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java
new file mode 100644
index 000000000000..b0409c037107
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 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.providers.settings;
+
+import android.util.ArraySet;
+
+import java.util.Arrays;
+import java.util.Set;
+
+/**
+ * Contains the list of namespaces in which any flag can be written by adb without root
+ * permissions.
+ * <p>
+ * A security review is required for any namespace that's added to this list. To add to
+ * the list, create a change and tag the OWNER. In the commit message, include a
+ * description of the flag's functionality, and a justification for why it needs to be
+ * allowlisted.
+ */
+final class WritableNamespaces {
+ public static final Set<String> ALLOWLIST =
+ new ArraySet<String>(Arrays.asList(
+ "captive_portal_login",
+ "connectivity",
+ "exo",
+ "nearby",
+ "netd_native",
+ "network_security",
+ "on_device_personalization",
+ "tethering",
+ "tethering_u_or_later_native",
+ "thread_network"
+ ));
+}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index c2beaa8048f6..a62b7fd3db81 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -564,6 +564,8 @@ public class SettingsBackupTest {
Settings.Global.MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER,
Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
Settings.Global.ENABLE_BACK_ANIMATION, // Temporary for T, dev option only
+ Settings.Global.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, // cache per hearing device
+ Settings.Global.HEARING_DEVICE_LOCAL_NOTIFICATION, // cache per hearing device
Settings.Global.Wearable.COMBINED_LOCATION_ENABLE,
Settings.Global.Wearable.HAS_PAY_TOKENS,
Settings.Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN,
@@ -633,7 +635,8 @@ public class SettingsBackupTest {
Settings.Global.Wearable.WEAR_MEDIA_SESSIONS_PACKAGE,
Settings.Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED,
Settings.Global.Wearable.CONNECTIVITY_KEEP_DATA_ON,
- Settings.Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE);
+ Settings.Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE,
+ Settings.Global.Wearable.WEAR_SYSTEM_STATUS_TRAY_CONFIGURATION);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
@@ -944,8 +947,7 @@ public class SettingsBackupTest {
Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE,
Settings.System.WEAR_TTS_PREWARM_ENABLED,
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
- Settings.System.MULTI_AUDIO_FOCUS_ENABLED, // form-factor/OEM specific
- Settings.System.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME // internal cache
+ Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
);
if (!Flags.backUpSmoothDisplayAndForcePeakRefreshRate()) {
settings.add(Settings.System.MIN_REFRESH_RATE);
diff --git a/packages/Shell/Android.bp b/packages/Shell/Android.bp
index 3350efc33ad8..5f810858b7cd 100644
--- a/packages/Shell/Android.bp
+++ b/packages/Shell/Android.bp
@@ -27,6 +27,7 @@ android_app {
],
flags_packages: [
"android.security.flags-aconfig",
+ "android.permission.flags-aconfig",
],
platform_apis: true,
certificate: "platform",
@@ -51,5 +52,6 @@ android_library {
manifest: "AndroidManifest.xml",
flags_packages: [
"android.security.flags-aconfig",
+ "android.permission.flags-aconfig",
],
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7b6321d1cc7d..27e6bab1642d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -179,6 +179,7 @@
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGE_UPDATES" />
+ <uses-permission android:name="android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES" />
<uses-permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" />
<uses-permission android:name="android.permission.INSTALL_DPC_PACKAGES" />
<uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
@@ -242,6 +243,8 @@
<uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL" />
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
+ <uses-permission android:name="android.permission.COPY_ACCOUNTS" />
+ <uses-permission android:name="android.permission.REMOVE_ACCOUNTS" />
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
<uses-permission android:name="android.permission.FRAME_STATS" />
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
@@ -369,6 +372,9 @@
<!-- Permission needed for CTS test - UnsupportedErrorDialogTests -->
<uses-permission android:name="android.permission.RESET_APP_ERRORS" />
+ <!-- Permission needed tests -->
+ <uses-permission android:name="android.permission.OBSERVE_PICTURE_PROFILES" />
+
<!-- Permission needed for CTS test - CtsSystemUiTestCases:PipNotificationTests -->
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
@@ -743,6 +749,9 @@
<!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
<uses-permission android:name="android.permission.LOCK_DEVICE" />
+ <!-- Permission required for AuthenticationPolicyManagerTest -->
+ <uses-permission android:name="android.permission.MANAGE_SECURE_LOCK_DEVICE" />
+
<!-- Permissions required for CTS test - CtsSafetyCenterTestCases -->
<uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
<uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
@@ -929,7 +938,6 @@
<!-- Permission required for CTS test - CtsPackageManagerTestCases-->
<uses-permission android:name="android.permission.DOMAIN_VERIFICATION_AGENT" />
- <uses-permission android:name="android.permission.VERIFICATION_AGENT" />
<!-- Permission required for Cts test - CtsInputTestCases -->
<uses-permission
@@ -948,24 +956,39 @@
<!-- Permission required for CTS test - CtsNfcTestCases -->
<uses-permission android:name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON" />
<!-- Permission required for CTS test - AdvancedProtectionManagerTest -->
- <uses-permission android:name="android.permission.SET_ADVANCED_PROTECTION_MODE"
+ <uses-permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE"
android:featureFlag="android.security.aapm_api"/>
<uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE"
android:featureFlag="android.security.aapm_api"/>
+ <!-- Permission required for CTS test - IntrusionDetectionManagerTest -->
+ <uses-permission android:name="android.permission.READ_INTRUSION_DETECTION_STATE"
+ android:featureFlag="android.security.afl_api"/>
+ <uses-permission android:name="android.permission.MANAGE_INTRUSION_DETECTION_STATE"
+ android:featureFlag="android.security.afl_api"/>
+
+
<!-- Permission required for CTS test - CtsAppTestCases -->
<uses-permission android:name="android.permission.KILL_UID" />
<!-- Permission required for CTS test - CtsTelephonyTestCases -->
<uses-permission android:name="android.permission.READ_BASIC_PHONE_STATE" />
- <!-- Permission required for ExecutableMethodFileOffsetsTest -->
+ <!-- Permission required for CTS test - CtsDynamicInstrumentationManagerTest -->
<uses-permission android:name="android.permission.DYNAMIC_INSTRUMENTATION" />
<!-- Permissions required for CTS test - SettingsPreferenceServiceClientTest -->
<uses-permission android:name="android.permission.READ_SYSTEM_PREFERENCES" />
<uses-permission android:name="android.permission.WRITE_SYSTEM_PREFERENCES" />
+ <!-- Permissions required for CTS test - ActivityManagerForegroundServiceTypeTest -->
+ <uses-permission android:name="android.permission.health.READ_HEART_RATE"
+ android:featureFlag="android.permission.flags.replace_body_sensor_permission_enabled"/>
+ <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION"
+ android:featureFlag="android.permission.flags.replace_body_sensor_permission_enabled"/>
+ <uses-permission android:name="android.permission.health.READ_SKIN_TEMPERATURE"
+ android:featureFlag="android.permission.flags.replace_body_sensor_permission_enabled"/>
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 8feefa5d892f..d4b5b86223ea 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -12,3 +12,4 @@ patb@google.com
cbrubaker@google.com
omakoto@google.com
michaelwr@google.com
+ronish@google.com
diff --git a/packages/Shell/aconfig/Android.bp b/packages/Shell/aconfig/Android.bp
new file mode 100644
index 000000000000..1d797b29c1a4
--- /dev/null
+++ b/packages/Shell/aconfig/Android.bp
@@ -0,0 +1,13 @@
+aconfig_declarations {
+ name: "wear_aconfig_declarations",
+ package: "com.android.shell.flags",
+ container: "system",
+ srcs: [
+ "wear.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "wear_aconfig_declarations_flags_java_lib",
+ aconfig_declarations: "wear_aconfig_declarations",
+}
diff --git a/packages/Shell/aconfig/wear.aconfig b/packages/Shell/aconfig/wear.aconfig
new file mode 100644
index 000000000000..d88fd46cb68d
--- /dev/null
+++ b/packages/Shell/aconfig/wear.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.shell.flags"
+container: "system"
+
+flag {
+ name: "handle_bugreports_for_wear"
+ namespace: "wear_services"
+ description: "This flag enables Shell to propagate bugreport results to WearServices."
+ bug: "338029043"
+} \ No newline at end of file
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 7c478ac78a29..7f25b51e35ca 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -153,6 +153,10 @@ public class BugreportProgressService extends Service {
static final String INTENT_BUGREPORT_FINISHED =
"com.android.internal.intent.action.BUGREPORT_FINISHED";
+ // Intent sent to notify external apps that bugreport aborted due to error.
+ static final String INTENT_BUGREPORT_ABORTED =
+ "com.android.internal.intent.action.BUGREPORT_ABORTED";
+
// Internal intents used on notification actions.
static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
static final String INTENT_BUGREPORT_SHARE = "android.intent.action.BUGREPORT_SHARE";
@@ -174,6 +178,8 @@ public class BugreportProgressService extends Service {
static final String EXTRA_INFO = "android.intent.extra.INFO";
static final String EXTRA_EXTRA_ATTACHMENT_URIS =
"android.intent.extra.EXTRA_ATTACHMENT_URIS";
+ static final String EXTRA_ABORTED_ERROR_CODE =
+ "android.intent.extra.EXTRA_ABORTED_ERROR_CODE";
private static final ThreadFactory sBugreportManagerCallbackThreadFactory =
new ThreadFactory() {
@@ -404,6 +410,7 @@ public class BugreportProgressService extends Service {
@Override
public void onError(@BugreportErrorCode int errorCode) {
synchronized (mLock) {
+ sendBugreportAbortedBroadcastLocked(errorCode);
stopProgressLocked(mInfo.id);
mInfo.deleteEmptyFiles();
}
@@ -460,6 +467,13 @@ public class BugreportProgressService extends Service {
onBugreportFinished(mInfo);
}
}
+
+ @GuardedBy("mLock")
+ private void sendBugreportAbortedBroadcastLocked(@BugreportErrorCode int errorCode) {
+ final Intent intent = new Intent(INTENT_BUGREPORT_ABORTED);
+ intent.putExtra(EXTRA_ABORTED_ERROR_CODE, errorCode);
+ mContext.sendBroadcast(intent, android.Manifest.permission.DUMP);
+ }
}
private void sendRemoteBugreportFinishedBroadcast(Context context,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index bffda8bcae65..d1a22e8612d3 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -90,8 +90,6 @@ filegroup {
"tests/src/**/systemui/globalactions/GlobalActionsDialogLiteTest.java",
"tests/src/**/systemui/globalactions/GlobalActionsImeTest.java",
"tests/src/**/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt",
- "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
- "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
"tests/src/**/systemui/media/dialog/MediaOutputAdapterTest.java",
"tests/src/**/systemui/media/dialog/MediaOutputBaseDialogTest.java",
"tests/src/**/systemui/media/dialog/MediaOutputBroadcastDialogTest.java",
@@ -134,7 +132,6 @@ filegroup {
"tests/src/**/systemui/accessibility/floatingmenu/MenuViewLayerTest.java",
"tests/src/**/systemui/accessibility/floatingmenu/MenuViewTest.java",
"tests/src/**/systemui/classifier/PointerCountClassifierTest.java",
- "tests/src/**/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt",
"tests/src/**/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java",
"tests/src/**/systemui/screenrecord/RecordingControllerTest.java",
"tests/src/**/systemui/screenshot/RequestProcessorTest.kt",
@@ -211,13 +208,13 @@ filegroup {
"tests/src/**/systemui/qs/tiles/DreamTileTest.java",
"tests/src/**/systemui/qs/FgsManagerControllerTest.java",
"tests/src/**/systemui/qs/QSPanelTest.kt",
+ "tests/src/**/systemui/reardisplay/RearDisplayCoreStartableTest.kt",
"tests/src/**/systemui/reardisplay/RearDisplayDialogControllerTest.java",
+ "tests/src/**/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt",
"tests/src/**/systemui/statusbar/KeyboardShortcutListSearchTest.java",
"tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java",
"tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt",
"tests/src/**/systemui/statusbar/notification/AssistantFeedbackControllerTest.java",
- "tests/src/**/systemui/statusbar/notification/PropertyAnimatorTest.java",
- "tests/src/**/systemui/statusbar/notification/collection/NotifCollectionTest.java",
"tests/src/**/systemui/statusbar/notification/collection/NotificationEntryTest.java",
"tests/src/**/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt",
"tests/src/**/systemui/statusbar/notification/collection/ShadeListBuilderTest.java",
@@ -233,9 +230,7 @@ filegroup {
"tests/src/**/systemui/statusbar/notification/row/NotificationConversationInfoTest.java",
"tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerTest.java",
"tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt",
- "tests/src/**/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt",
"tests/src/**/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt",
- "tests/src/**/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java",
"tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java",
"tests/src/**/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt",
"tests/src/**/systemui/statusbar/phone/AutoTileManagerTest.java",
@@ -250,7 +245,6 @@ filegroup {
"tests/src/**/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt",
- "tests/src/**/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt",
"tests/src/**/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt",
"tests/src/**/systemui/statusbar/policy/CallbackControllerTest.java",
"tests/src/**/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java",
@@ -263,11 +257,9 @@ filegroup {
"tests/src/**/systemui/theme/ThemeOverlayApplierTest.java",
"tests/src/**/systemui/touch/TouchInsetManagerTest.java",
"tests/src/**/systemui/util/LifecycleFragmentTest.java",
- "tests/src/**/systemui/util/TestableAlertDialogTest.kt",
"tests/src/**/systemui/util/kotlin/PairwiseFlowTest",
"tests/src/**/systemui/util/sensors/AsyncManagerTest.java",
"tests/src/**/systemui/util/sensors/ThresholdSensorImplTest.java",
- "tests/src/**/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java",
"tests/src/**/systemui/volume/VolumeDialogImplTest.java",
"tests/src/**/systemui/wallet/controller/QuickAccessWalletControllerTest.java",
"tests/src/**/systemui/wallet/ui/WalletScreenControllerTest.java",
@@ -288,9 +280,6 @@ filegroup {
"tests/src/**/systemui/qs/QSImplTest.java",
"tests/src/**/systemui/qs/panels/ui/compose/DragAndDropTest.kt",
"tests/src/**/systemui/qs/panels/ui/compose/ResizingTest.kt",
- "tests/src/**/systemui/screenshot/ActionExecutorTest.kt",
- "tests/src/**/systemui/screenshot/ScreenshotDetectionControllerTest.kt",
- "tests/src/**/systemui/screenshot/TakeScreenshotServiceTest.kt",
"tests/src/**/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java",
"tests/src/**/systemui/accessibility/floatingmenu/PositionTest.java",
"tests/src/**/systemui/animation/TransitionAnimatorTest.kt",
@@ -303,10 +292,45 @@ filegroup {
"tests/src/**/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt",
"tests/src/**/systemui/statusbar/policy/RotationLockControllerImplTest.java",
"tests/src/**/systemui/statusbar/phone/ScrimControllerTest.java",
- "tests/src/**/systemui/stylus/StylusUsiPowerStartableTest.kt",
"tests/src/**/systemui/toast/ToastUITest.java",
"tests/src/**/systemui/statusbar/policy/FlashlightControllerImplTest.kt",
"tests/src/**/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt",
+ "tests/src/**/systemui/stylus/StylusUsiPowerUiTest.kt",
+ ],
+}
+
+// Files which use ExtendedMockito on the device.
+filegroup {
+ name: "SystemUI-tests-broken-robofiles-mockito-extended",
+ srcs: [
+ "tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
+ "tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
+ "tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
+ "tests/src/**/systemui/stylus/StylusManagerTest.kt",
+ "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt",
+ "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt",
+ "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java",
+ "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt",
+ "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
+ "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
+ "tests/src/**/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt",
+ "tests/src/**/systemui/qs/tiles/HotspotTileTest.java",
+ "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java",
+ "tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
+ "tests/src/**/systemui/wmshell/BubblesTest.java",
+ "tests/src/**/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java",
+ "tests/src/**/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java",
+ "tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
+ "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java",
+ "tests/src/**/systemui/qs/external/TileLifecycleManagerTest.java",
+ "tests/src/**/systemui/ScreenDecorationsTest.java",
+ "tests/src/**/keyguard/CarrierTextManagerTest.java",
+ "tests/src/**/keyguard/KeyguardUpdateMonitorTest.java",
],
}
@@ -314,29 +338,23 @@ filegroup {
filegroup {
name: "SystemUI-tests-broken-robofiles-compile",
srcs: [
- "tests/src/**/keyguard/KeyguardUpdateMonitorTest.java",
"tests/src/**/systemui/statusbar/notification/icon/IconManagerTest.kt",
"tests/src/**/systemui/statusbar/KeyguardIndicationControllerTest.java",
"tests/src/**/systemui/doze/DozeScreenStateTest.java",
- "tests/src/**/keyguard/CarrierTextManagerTest.java",
"tests/src/**/systemui/notetask/NoteTaskInitializerTest.kt",
"tests/src/**/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt",
"tests/src/**/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt",
"tests/src/**/systemui/controls/management/ControlsFavoritingActivityTest.kt",
"tests/src/**/systemui/controls/management/ControlsProviderSelectorActivityTest.kt",
"tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt",
- "tests/src/**/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt",
"tests/src/**/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt",
"tests/src/**/systemui/qs/tileimpl/QSTileViewImplTest.kt",
- "tests/src/**/systemui/statusbar/policy/BatteryStateNotifierTest.kt",
"tests/src/**/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt",
"tests/src/**/keyguard/ClockEventControllerTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt",
- "tests/src/**/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt",
- "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt",
"tests/src/**/systemui/broadcast/UserBroadcastDispatcherTest.kt",
"tests/src/**/systemui/charging/WiredChargingRippleControllerTest.kt",
@@ -351,7 +369,6 @@ filegroup {
"tests/src/**/systemui/controls/ui/SelectionItemTest.kt",
"tests/src/**/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt",
"tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt",
- "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
"tests/src/**/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt",
"tests/src/**/systemui/media/controls/ui/animation/AnimationBindHandlerTest.kt",
"tests/src/**/systemui/media/controls/ui/animation/ColorSchemeTransitionTest.kt",
@@ -417,40 +434,9 @@ filegroup {
"tests/src/**/systemui/statusbar/policy/VariableDateViewControllerTest.kt",
"tests/src/**/systemui/statusbar/policy/WalletControllerImplTest.kt",
"tests/src/**/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt",
- "tests/src/**/systemui/stylus/StylusUsiPowerUiTest.kt",
"tests/src/**/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt",
- "tests/src/**/systemui/ScreenDecorationsTest.java",
- "tests/src/**/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt",
- "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
- "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
- "tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
- "tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
- "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt",
- "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt",
- "tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
- "tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
- "tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
- "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt",
- "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java",
- "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java",
- "tests/src/**/systemui/qs/tiles/HotspotTileTest.java",
- "tests/src/**/systemui/qs/external/TileLifecycleManagerTest.java",
- "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt",
- "tests/src/**/systemui/stylus/StylusManagerTest.kt",
- "tests/src/**/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java",
- "tests/src/**/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java",
"tests/src/**/systemui/statusbar/policy/BatteryControllerStartableTest.java",
- "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java",
- "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt",
- "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt",
- "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
- "tests/src/**/systemui/wmshell/BubblesTest.java",
- "tests/src/**/systemui/power/PowerUITest.java",
- "tests/src/**/systemui/qs/QSSecurityFooterTest.java",
- "tests/src/**/systemui/qs/tileimpl/QSTileImplTest.java",
"tests/src/**/systemui/shared/plugins/PluginActionManagerTest.java",
- "tests/src/**/systemui/statusbar/CommandQueueTest.java",
- "tests/src/**/systemui/statusbar/connectivity/CallbackHandlerTest.java",
"tests/src/**/systemui/statusbar/policy/SecurityControllerTest.java",
"tests/src/**/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt",
],
@@ -497,6 +483,9 @@ android_library {
resource_dirs: [],
static_libs: [
"//frameworks/libs/systemui:compilelib",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail:impl",
"SystemUI-res",
"WifiTrackerLib",
"WindowManager-Shell",
@@ -770,6 +759,9 @@ android_library {
],
static_libs: [
"//frameworks/libs/systemui:compilelib",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail:impl",
"SystemUI-tests-base",
"androidx.test.uiautomator_uiautomator",
"androidx.core_core-animation-testing",
@@ -910,6 +902,7 @@ android_robolectric_test {
":SystemUI-tests-robofiles",
],
exclude_srcs: [
+ ":SystemUI-tests-broken-robofiles-mockito-extended",
":SystemUI-tests-broken-robofiles-compile",
":SystemUI-tests-broken-robofiles-run",
":SystemUI-tests-broken-robofiles-sysui-run",
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 380344a23c99..e47704ebdf86 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -153,5 +153,11 @@
{
"path": "cts/tests/tests/multiuser"
}
+ ],
+
+ "sysui-e2e-presubmit": [
+ {
+ "name": "PlatformScenarioTests_SysUI_Presubmit"
+ }
]
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a4b8821383e0..e59fe47194da 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -632,9 +632,9 @@ flag {
flag {
name: "status_bar_connected_displays"
- namespace: "systemui"
+ namespace: "lse_desktop_experience"
description: "Shows the status bar on connected displays"
- bug: "362720336"
+ bug: "379264862"
}
flag {
@@ -1215,6 +1215,13 @@ flag {
}
flag {
+ name: "glanceable_hub_v2"
+ namespace: "systemui"
+ description: "Gates the refreshed glanceable hub experience that also brings the glanceable hub to mobile phones"
+ bug: "375689917"
+}
+
+flag {
name: "dream_overlay_updated_font"
namespace: "systemui"
description: "Flag to enable updated font settings for dream overlay"
@@ -1748,6 +1755,13 @@ flag {
}
flag {
+ name: "notification_shade_blur"
+ namespace: "systemui"
+ description: "Enables the new blur effect on the Notification Shade."
+ bug: "370555223"
+}
+
+flag {
name: "ensure_enr_views_visibility"
namespace: "systemui"
description: "Ensures public and private visibilities"
@@ -1773,6 +1787,16 @@ flag {
}
flag {
+ name: "notification_reentrant_dismiss"
+ namespace: "systemui"
+ description: "Posts to avoid a crashing reentrant pipeline run"
+ bug: "328328054"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "stoppable_fgs_system_app"
namespace: "systemui"
description: "System app with foreground service can opt in to be stoppable."
@@ -1790,4 +1814,32 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
-} \ No newline at end of file
+}
+
+flag {
+ name: "gsf_bouncer"
+ namespace: "systemui"
+ description: "Applies GSF font styles to Bouncer surfaces."
+ bug: "379364381"
+}
+
+flag {
+ name: "gsf_quick_settings"
+ namespace: "systemui"
+ description: "Applies GSF font styles to Quick Settings surfaces."
+ bug: "379364381"
+}
+
+flag {
+ name: "glanceable_hub_shortcut_button"
+ namespace: "systemui"
+ description: "Adds a shortcut button to lockscreen to show glanceable hub."
+ bug: "378173531"
+}
+
+flag {
+ name: "spatial_model_launcher_pushback"
+ namespace: "systemui"
+ description: "Implement the depth push scaling effect on Launcher when users pull down shade."
+ bug: "370562309"
+}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
index 2b5ff7c4b598..0f5e3679cc5f 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
@@ -44,6 +44,7 @@ import java.util.List;
/**
* An implementation of {@link IRemoteTransition} that accepts a {@link UIComponent} as the origin
* and automatically attaches it to the transition leash before the transition starts.
+ *
* @hide
*/
public class OriginRemoteTransition extends IRemoteTransition.Stub {
@@ -258,8 +259,7 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
// The transition didn't start. Ensure we apply the start transaction and report
// finish afterwards.
mStartTransaction
- .addTransactionCommittedListener(
- mContext.getMainExecutor(), this::finishInternal)
+ .addTransactionCommittedListener(mHandler::post, this::finishInternal)
.apply();
return;
}
@@ -268,8 +268,7 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
mPlayer.onEnd(finished);
// Detach the origin from the transition leash and report finish after it's done.
mOriginTransaction
- .detachFromTransitionLeash(
- mOrigin, mContext.getMainExecutor(), this::finishInternal)
+ .detachFromTransitionLeash(mOrigin, mHandler::post, this::finishInternal)
.commit();
}
@@ -329,7 +328,9 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
/* baseBounds= */ maxBounds);
}
- /** An interface that represents an origin transitions.
+ /**
+ * An interface that represents an origin transitions.
+ *
* @hide
*/
public interface TransitionPlayer {
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
index 4c047d589a66..9cef43c3deba 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
@@ -38,6 +38,7 @@ import java.util.concurrent.Executor;
* be changed to INVISIBLE in its view tree. This allows the {@link View} to transform in the
* full-screen size leash without being constrained by the view tree's boundary or inheriting its
* parent's alpha and transformation.
+ *
* @hide
*/
public class ViewUIComponent implements UIComponent {
@@ -98,9 +99,7 @@ public class ViewUIComponent implements UIComponent {
mView.getViewTreeObserver().addOnDrawListener(mOnDrawListener);
// Make the view invisible AFTER the surface is shown.
- t.addTransactionCommittedListener(
- mView.getContext().getMainExecutor(),
- () -> mView.setVisibility(View.INVISIBLE))
+ t.addTransactionCommittedListener(mView::post, () -> mView.setVisibility(View.INVISIBLE))
.apply();
}
@@ -118,7 +117,7 @@ public class ViewUIComponent implements UIComponent {
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.reparent(sc, null)
.addTransactionCommittedListener(
- mView.getContext().getMainExecutor(),
+ mView::post,
() -> {
s.release();
sc.release();
@@ -235,41 +234,40 @@ public class ViewUIComponent implements UIComponent {
mView.post(this::draw);
}
- /**
- * @hide
- */
+ /** @hide */
public static class Transaction implements UIComponent.Transaction<ViewUIComponent> {
private final List<Runnable> mChanges = new ArrayList<>();
@Override
public Transaction setAlpha(ViewUIComponent ui, float alpha) {
- mChanges.add(() -> ui.setAlpha(alpha));
+ mChanges.add(() -> ui.mView.post(() -> ui.setAlpha(alpha)));
return this;
}
@Override
public Transaction setVisible(ViewUIComponent ui, boolean visible) {
- mChanges.add(() -> ui.setVisible(visible));
+ mChanges.add(() -> ui.mView.post(() -> ui.setVisible(visible)));
return this;
}
@Override
public Transaction setBounds(ViewUIComponent ui, Rect bounds) {
- mChanges.add(() -> ui.setBounds(bounds));
+ mChanges.add(() -> ui.mView.post(() -> ui.setBounds(bounds)));
return this;
}
@Override
public Transaction attachToTransitionLeash(
ViewUIComponent ui, SurfaceControl transitionLeash, int w, int h) {
- mChanges.add(() -> ui.attachToTransitionLeash(transitionLeash, w, h));
+ mChanges.add(
+ () -> ui.mView.post(() -> ui.attachToTransitionLeash(transitionLeash, w, h)));
return this;
}
@Override
public Transaction detachFromTransitionLeash(
ViewUIComponent ui, Executor executor, Runnable onDone) {
- mChanges.add(() -> ui.detachFromTransitionLeash(executor, onDone));
+ mChanges.add(() -> ui.mView.post(() -> ui.detachFromTransitionLeash(executor, onDone)));
return this;
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index 18f40c98fe04..f1cbba7272b0 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -17,6 +17,7 @@
package com.android.systemui.animation
import android.app.ActivityManager
+import android.app.ActivityOptions
import android.app.ActivityTaskManager
import android.app.PendingIntent
import android.app.TaskInfo
@@ -24,18 +25,22 @@ import android.app.WindowConfiguration
import android.content.ComponentName
import android.graphics.Color
import android.graphics.Matrix
+import android.graphics.PointF
import android.graphics.Rect
import android.graphics.RectF
import android.os.Binder
import android.os.Build
import android.os.Handler
+import android.os.IBinder
import android.os.Looper
import android.os.RemoteException
+import android.util.ArrayMap
import android.util.Log
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationRunner
import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
import android.view.ViewGroup
@@ -45,8 +50,12 @@ import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_BACK
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.view.animation.PathInterpolator
+import android.window.IRemoteTransition
+import android.window.IRemoteTransitionFinishedCallback
import android.window.RemoteTransition
import android.window.TransitionFilter
+import android.window.TransitionInfo
+import android.window.WindowAnimationState
import androidx.annotation.AnyThread
import androidx.annotation.BinderThread
import androidx.annotation.UiThread
@@ -55,11 +64,14 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.systemui.Flags.activityTransitionUseLargestWindow
import com.android.systemui.Flags.translucentOccludingActivityFix
+import com.android.systemui.animation.TransitionAnimator.Companion.assertLongLivedReturnAnimations
+import com.android.systemui.animation.TransitionAnimator.Companion.assertReturnAnimations
+import com.android.systemui.animation.TransitionAnimator.Companion.longLivedReturnAnimationsEnabled
+import com.android.systemui.animation.TransitionAnimator.Companion.returnAnimationsEnabled
import com.android.systemui.animation.TransitionAnimator.Companion.toTransitionState
-import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
-import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived
import com.android.wm.shell.shared.IShellTransitions
import com.android.wm.shell.shared.ShellTransitions
+import com.android.wm.shell.shared.TransitionUtil
import java.util.concurrent.Executor
import kotlin.math.roundToInt
@@ -194,7 +206,13 @@ constructor(
private const val LONG_TRANSITION_TIMEOUT = 5_000L
private fun defaultTransitionAnimator(mainExecutor: Executor): TransitionAnimator {
- return TransitionAnimator(mainExecutor, TIMINGS, INTERPOLATORS)
+ return TransitionAnimator(
+ mainExecutor,
+ TIMINGS,
+ INTERPOLATORS,
+ SPRING_TIMINGS,
+ SPRING_INTERPOLATORS,
+ )
}
private fun defaultDialogToAppAnimator(mainExecutor: Executor): TransitionAnimator {
@@ -275,7 +293,7 @@ constructor(
"ActivityTransitionAnimator.callback must be set before using this animator"
)
val runner = createRunner(controller)
- val runnerDelegate = runner.delegate!!
+ val runnerDelegate = runner.delegate
val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen
// Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the
@@ -330,7 +348,11 @@ constructor(
// If we expect an animation, post a timeout to cancel it in case the remote animation is
// never started.
if (willAnimate) {
- runnerDelegate.postTimeouts()
+ if (longLivedReturnAnimationsEnabled()) {
+ runner.postTimeouts()
+ } else {
+ runnerDelegate!!.postTimeouts()
+ }
// Hide the keyguard using the launch animation instead of the default unlock animation.
if (hideKeyguardWithAnimation) {
@@ -390,7 +412,7 @@ constructor(
launchController: Controller,
transitionRegister: TransitionRegister?,
) {
- if (!returnAnimationFrameworkLibrary()) return
+ if (!returnAnimationsEnabled()) return
var cleanUpRunnable: Runnable? = null
val returnRunner =
@@ -435,7 +457,11 @@ constructor(
"${launchController.transitionCookie}_returnTransition",
)
- transitionRegister?.register(filter, transition)
+ transitionRegister?.register(
+ filter,
+ transition,
+ includeTakeover = longLivedReturnAnimationsEnabled(),
+ )
cleanUpRunnable = Runnable { transitionRegister?.unregister(transition) }
}
@@ -451,7 +477,10 @@ constructor(
/** Create a new animation [Runner] controlled by [controller]. */
@VisibleForTesting
- fun createRunner(controller: Controller): Runner {
+ @JvmOverloads
+ fun createRunner(controller: Controller, longLived: Boolean = false): Runner {
+ if (longLived) assertLongLivedReturnAnimations()
+
// Make sure we use the modified timings when animating a dialog into an app.
val transitionAnimator =
if (controller.isDialogLaunch) {
@@ -460,7 +489,7 @@ constructor(
transitionAnimator
}
- return Runner(controller, callback!!, transitionAnimator, lifecycleListener)
+ return Runner(controller, callback!!, transitionAnimator, lifecycleListener, longLived)
}
interface PendingIntentStarter {
@@ -628,10 +657,7 @@ constructor(
* this registration.
*/
fun register(controller: Controller) {
- check(returnAnimationFrameworkLongLived()) {
- "Long-lived registrations cannot be used when the returnAnimationFrameworkLongLived " +
- "flag is disabled"
- }
+ assertLongLivedReturnAnimations()
if (transitionRegister == null) {
throw IllegalStateException(
@@ -667,10 +693,10 @@ constructor(
}
val launchRemoteTransition =
RemoteTransition(
- RemoteAnimationRunnerCompat.wrap(createRunner(controller)),
+ OriginTransition(createRunner(controller, longLived = true)),
"${cookie}_launchTransition",
)
- transitionRegister.register(launchFilter, launchRemoteTransition)
+ transitionRegister.register(launchFilter, launchRemoteTransition, includeTakeover = true)
val returnController =
object : Controller by controller {
@@ -689,10 +715,10 @@ constructor(
}
val returnRemoteTransition =
RemoteTransition(
- RemoteAnimationRunnerCompat.wrap(createRunner(returnController)),
+ OriginTransition(createRunner(returnController, longLived = true)),
"${cookie}_returnTransition",
)
- transitionRegister.register(returnFilter, returnRemoteTransition)
+ transitionRegister.register(returnFilter, returnRemoteTransition, includeTakeover = true)
longLivedTransitions[cookie] = Pair(launchRemoteTransition, returnRemoteTransition)
}
@@ -738,14 +764,162 @@ constructor(
}
}
+ /** [Runner] wrapper that supports animation takeovers. */
+ private inner class OriginTransition(private val runner: Runner) : IRemoteTransition {
+ private val delegate = RemoteAnimationRunnerCompat.wrap(runner)
+
+ init {
+ assertLongLivedReturnAnimations()
+ }
+
+ override fun startAnimation(
+ token: IBinder?,
+ info: TransitionInfo?,
+ t: SurfaceControl.Transaction?,
+ finishCallback: IRemoteTransitionFinishedCallback?,
+ ) {
+ delegate.startAnimation(token, info, t, finishCallback)
+ }
+
+ override fun mergeAnimation(
+ transition: IBinder?,
+ info: TransitionInfo?,
+ t: SurfaceControl.Transaction?,
+ mergeTarget: IBinder?,
+ finishCallback: IRemoteTransitionFinishedCallback?,
+ ) {
+ delegate.mergeAnimation(transition, info, t, mergeTarget, finishCallback)
+ }
+
+ override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) {
+ delegate.onTransitionConsumed(transition, aborted)
+ }
+
+ override fun takeOverAnimation(
+ token: IBinder?,
+ info: TransitionInfo?,
+ t: SurfaceControl.Transaction?,
+ finishCallback: IRemoteTransitionFinishedCallback?,
+ states: Array<WindowAnimationState>,
+ ) {
+ if (info == null || t == null) {
+ Log.e(
+ TAG,
+ "Skipping the animation takeover because the required data is missing: " +
+ "info=$info, transaction=$t",
+ )
+ return
+ }
+
+ // The following code converts the contents of the given TransitionInfo into
+ // RemoteAnimationTargets. This is necessary because we must currently support both the
+ // new (Shell, remote transitions) and old (remote animations) framework to maintain
+ // functionality for all users of the library.
+ val apps = ArrayList<RemoteAnimationTarget>()
+ val filteredStates = ArrayList<WindowAnimationState>()
+ val leashMap = ArrayMap<SurfaceControl, SurfaceControl>()
+ val leafTaskFilter = TransitionUtil.LeafTaskFilter()
+
+ // About layering: we divide up the "layer space" into 2 regions (each the size of the
+ // change count). This lets us categorize things into above and below while
+ // maintaining their relative ordering.
+ val belowLayers = info.changes.size
+ val aboveLayers = info.changes.size * 2
+ for (i in info.changes.indices) {
+ val change = info.changes[i]
+ if (change == null || change.taskInfo == null) {
+ continue
+ }
+
+ val taskInfo = change.taskInfo
+
+ if (TransitionUtil.isWallpaper(change)) {
+ val target =
+ TransitionUtil.newTarget(
+ change,
+ belowLayers - i, // wallpapers go into the "below" layer space
+ info,
+ t,
+ leashMap,
+ )
+
+ // Make all the wallpapers opaque.
+ t.setAlpha(target.leash, 1f)
+ } else if (leafTaskFilter.test(change)) {
+ // Start by putting everything into the "below" layer space.
+ val target =
+ TransitionUtil.newTarget(change, belowLayers - i, info, t, leashMap)
+ apps.add(target)
+ filteredStates.add(states[i])
+
+ // Make all the apps opaque.
+ t.setAlpha(target.leash, 1f)
+
+ if (
+ TransitionUtil.isClosingType(change.mode) &&
+ taskInfo?.topActivityType != WindowConfiguration.ACTIVITY_TYPE_HOME
+ ) {
+ // Raise closing task to "above" layer so it isn't covered.
+ t.setLayer(target.leash, aboveLayers - i)
+ }
+ } else if (TransitionInfo.isIndependent(change, info)) {
+ // Root tasks
+ if (TransitionUtil.isClosingType(change.mode)) {
+ // Raise closing task to "above" layer so it isn't covered.
+ t.setLayer(change.leash, aboveLayers - i)
+ } else if (TransitionUtil.isOpeningType(change.mode)) {
+ // Put into the "below" layer space.
+ t.setLayer(change.leash, belowLayers - i)
+ }
+ } else if (TransitionUtil.isDividerBar(change)) {
+ val target =
+ TransitionUtil.newTarget(change, belowLayers - i, info, t, leashMap)
+ apps.add(target)
+ filteredStates.add(states[i])
+ }
+ }
+
+ val wrappedCallback: IRemoteAnimationFinishedCallback =
+ object : IRemoteAnimationFinishedCallback.Stub() {
+ override fun onAnimationFinished() {
+ leashMap.clear()
+ val finishTransaction = SurfaceControl.Transaction()
+ finishCallback?.onTransitionFinished(null, finishTransaction)
+ finishTransaction.close()
+ }
+ }
+
+ runner.takeOverAnimation(
+ apps.toTypedArray(),
+ filteredStates.toTypedArray(),
+ t,
+ wrappedCallback,
+ )
+ }
+
+ override fun asBinder(): IBinder {
+ return delegate.asBinder()
+ }
+ }
+
@VisibleForTesting
inner class Runner(
- controller: Controller,
- callback: Callback,
+ /**
+ * This can hold a reference to a view, so it needs to be cleaned up and can't be held on to
+ * forever when ![longLived].
+ */
+ private var controller: Controller?,
+ private val callback: Callback,
/** The animator to use to animate the window transition. */
- transitionAnimator: TransitionAnimator,
+ private val transitionAnimator: TransitionAnimator,
/** Listener for animation lifecycle events. */
- listener: Listener? = null,
+ private val listener: Listener? = null,
+ /**
+ * Whether the internal should be kept around after execution for later usage. IMPORTANT:
+ * should always be false if this [Runner] is to be used directly with [ActivityOptions]
+ * (i.e. for ephemeral launches), or the controller will leak its view.
+ */
+ private val longLived: Boolean = false,
) : IRemoteAnimationRunner.Stub() {
// This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
// etc.) are possible. So we need to make sure we drop any references that might
@@ -753,15 +927,14 @@ constructor(
@VisibleForTesting var delegate: AnimationDelegate?
init {
- delegate =
- AnimationDelegate(
- mainExecutor,
- controller,
- callback,
- DelegatingAnimationCompletionListener(listener, this::dispose),
- transitionAnimator,
- disableWmTimeout,
- )
+ delegate = null
+ if (!longLived) {
+ // Ephemeral launches bundle the runner with the launch request (instead of being
+ // registered ahead of time for later use). This means that there could be a timeout
+ // between creation and invocation, so the delegate needs to exist from the
+ // beginning in order to handle such timeout.
+ createDelegate()
+ }
}
@BinderThread
@@ -772,6 +945,36 @@ constructor(
nonApps: Array<out RemoteAnimationTarget>?,
finishedCallback: IRemoteAnimationFinishedCallback?,
) {
+ initAndRun(finishedCallback) { delegate ->
+ delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+ }
+ }
+
+ @VisibleForTesting
+ @BinderThread
+ fun takeOverAnimation(
+ apps: Array<RemoteAnimationTarget>?,
+ windowAnimationStates: Array<WindowAnimationState>,
+ startTransaction: SurfaceControl.Transaction,
+ finishedCallback: IRemoteAnimationFinishedCallback?,
+ ) {
+ assertLongLivedReturnAnimations()
+ initAndRun(finishedCallback) { delegate ->
+ delegate.takeOverAnimation(
+ apps,
+ windowAnimationStates,
+ startTransaction,
+ finishedCallback,
+ )
+ }
+ }
+
+ @BinderThread
+ private fun initAndRun(
+ finishedCallback: IRemoteAnimationFinishedCallback?,
+ performAnimation: (AnimationDelegate) -> Unit,
+ ) {
+ maybeSetUp()
val delegate = delegate
mainExecutor.execute {
if (delegate == null) {
@@ -780,7 +983,7 @@ constructor(
// signal back that we're done with it.
finishedCallback?.onAnimationFinished()
} else {
- delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+ performAnimation(delegate)
}
}
}
@@ -794,11 +997,43 @@ constructor(
}
}
+ @VisibleForTesting
+ @UiThread
+ fun postTimeouts() {
+ maybeSetUp()
+ delegate?.postTimeouts()
+ }
+
+ @AnyThread
+ private fun maybeSetUp() {
+ if (!longLived || delegate != null) return
+ createDelegate()
+ }
+
+ @AnyThread
+ private fun createDelegate() {
+ if (controller == null) return
+ delegate =
+ AnimationDelegate(
+ mainExecutor,
+ controller!!,
+ callback,
+ DelegatingAnimationCompletionListener(listener, this::dispose),
+ transitionAnimator,
+ disableWmTimeout,
+ )
+ }
+
@AnyThread
fun dispose() {
// Drop references to animation controller once we're done with the animation
// to avoid leaking.
- mainExecutor.execute { delegate = null }
+ mainExecutor.execute {
+ delegate = null
+ // When long lived, the same Runner can be used more than once. In this case we need
+ // to keep the controller around so we can rebuild the delegate on demand.
+ if (!longLived) controller = null
+ }
}
}
@@ -867,7 +1102,7 @@ constructor(
init {
// We do this check here to cover all entry points, including Launcher which doesn't
// call startIntentWithAnimation()
- if (!controller.isLaunching) TransitionAnimator.checkReturnAnimationFrameworkFlag()
+ if (!controller.isLaunching) assertReturnAnimations()
}
@UiThread
@@ -893,19 +1128,73 @@ constructor(
nonApps: Array<out RemoteAnimationTarget>?,
callback: IRemoteAnimationFinishedCallback?,
) {
+ val window = setUpAnimation(apps, callback) ?: return
+
+ if (controller.windowAnimatorState == null || !longLivedReturnAnimationsEnabled()) {
+ val navigationBar =
+ nonApps?.firstOrNull {
+ it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+ }
+
+ startAnimation(window, navigationBar, iCallback = callback)
+ } else {
+ // If a [controller.windowAnimatorState] exists, treat this like a takeover.
+ takeOverAnimationInternal(
+ window,
+ startWindowStates = null,
+ startTransaction = null,
+ callback,
+ )
+ }
+ }
+
+ @UiThread
+ internal fun takeOverAnimation(
+ apps: Array<out RemoteAnimationTarget>?,
+ startWindowStates: Array<WindowAnimationState>,
+ startTransaction: SurfaceControl.Transaction,
+ callback: IRemoteAnimationFinishedCallback?,
+ ) {
+ val window = setUpAnimation(apps, callback) ?: return
+ takeOverAnimationInternal(window, startWindowStates, startTransaction, callback)
+ }
+
+ private fun takeOverAnimationInternal(
+ window: RemoteAnimationTarget,
+ startWindowStates: Array<WindowAnimationState>?,
+ startTransaction: SurfaceControl.Transaction?,
+ callback: IRemoteAnimationFinishedCallback?,
+ ) {
+ val useSpring =
+ !controller.isLaunching && startWindowStates != null && startTransaction != null
+ startAnimation(
+ window,
+ navigationBar = null,
+ useSpring,
+ startWindowStates,
+ startTransaction,
+ callback,
+ )
+ }
+
+ @UiThread
+ private fun setUpAnimation(
+ apps: Array<out RemoteAnimationTarget>?,
+ callback: IRemoteAnimationFinishedCallback?,
+ ): RemoteAnimationTarget? {
removeTimeouts()
// The animation was started too late and we already notified the controller that it
// timed out.
if (timedOut) {
callback?.invoke()
- return
+ return null
}
// This should not happen, but let's make sure we don't start the animation if it was
// cancelled before and we already notified the controller.
if (cancelled) {
- return
+ return null
}
val window = findTargetWindowIfPossible(apps)
@@ -921,15 +1210,10 @@ constructor(
}
controller.onTransitionAnimationCancelled()
listener?.onTransitionAnimationCancelled()
- return
+ return null
}
- val navigationBar =
- nonApps?.firstOrNull {
- it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
- }
-
- startAnimation(window, navigationBar, callback)
+ return window
}
private fun findTargetWindowIfPossible(
@@ -950,7 +1234,7 @@ constructor(
for (it in apps) {
if (it.mode == targetMode) {
if (activityTransitionUseLargestWindow()) {
- if (returnAnimationFrameworkLibrary()) {
+ if (returnAnimationsEnabled()) {
// If the controller contains a cookie, _only_ match if either the
// candidate contains the matching cookie, or a component is also
// defined and is a match.
@@ -995,8 +1279,11 @@ constructor(
private fun startAnimation(
window: RemoteAnimationTarget,
- navigationBar: RemoteAnimationTarget?,
- iCallback: IRemoteAnimationFinishedCallback?,
+ navigationBar: RemoteAnimationTarget? = null,
+ useSpring: Boolean = false,
+ startingWindowStates: Array<WindowAnimationState>? = null,
+ startTransaction: SurfaceControl.Transaction? = null,
+ iCallback: IRemoteAnimationFinishedCallback? = null,
) {
if (TransitionAnimator.DEBUG) {
Log.d(TAG, "Remote animation started")
@@ -1046,18 +1333,66 @@ constructor(
val controller =
object : Controller by delegate {
override fun createAnimatorState(): TransitionAnimator.State {
- if (isLaunching) return delegate.createAnimatorState()
- return delegate.windowAnimatorState?.toTransitionState()
- ?: getWindowRadius(isExpandingFullyAbove).let {
- TransitionAnimator.State(
- top = windowBounds.top,
- bottom = windowBounds.bottom,
- left = windowBounds.left,
- right = windowBounds.right,
- topCornerRadius = it,
- bottomCornerRadius = it,
- )
+ if (isLaunching) {
+ return delegate.createAnimatorState()
+ } else if (!longLivedReturnAnimationsEnabled()) {
+ return delegate.windowAnimatorState?.toTransitionState()
+ ?: getWindowRadius(isExpandingFullyAbove).let {
+ TransitionAnimator.State(
+ top = windowBounds.top,
+ bottom = windowBounds.bottom,
+ left = windowBounds.left,
+ right = windowBounds.right,
+ topCornerRadius = it,
+ bottomCornerRadius = it,
+ )
+ }
+ }
+
+ // The states are sorted matching the changes inside the transition info.
+ // Using this info, the RemoteAnimationTargets are created, with their
+ // prefixOrderIndex fields in reverse order to that of changes. To extract
+ // the right state, we need to invert again.
+ val windowState =
+ if (startingWindowStates != null) {
+ startingWindowStates[
+ startingWindowStates.size - window.prefixOrderIndex]
+ } else {
+ controller.windowAnimatorState
}
+
+ // TODO(b/323863002): use the timestamp and velocity to update the initial
+ // position.
+ val bounds = windowState?.bounds
+ val left: Int = bounds?.left?.toInt() ?: windowBounds.left
+ val top: Int = bounds?.top?.toInt() ?: windowBounds.top
+ val right: Int = bounds?.right?.toInt() ?: windowBounds.right
+ val bottom: Int = bounds?.bottom?.toInt() ?: windowBounds.bottom
+
+ val width = windowBounds.right - windowBounds.left
+ val height = windowBounds.bottom - windowBounds.top
+ // Scale the window. We use the max of (widthRatio, heightRatio) so that
+ // there is no blank space on any side.
+ val widthRatio = (right - left).toFloat() / width
+ val heightRatio = (bottom - top).toFloat() / height
+ val startScale = maxOf(widthRatio, heightRatio)
+
+ val maybeRadius = windowState?.topLeftRadius
+ val windowRadius =
+ if (maybeRadius != null) {
+ maybeRadius * startScale
+ } else {
+ getWindowRadius(isExpandingFullyAbove)
+ }
+
+ return TransitionAnimator.State(
+ top = top,
+ bottom = bottom,
+ left = left,
+ right = right,
+ topCornerRadius = windowRadius,
+ bottomCornerRadius = windowRadius,
+ )
}
override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -1071,6 +1406,19 @@ constructor(
"[controller=$delegate]",
)
}
+
+ if (startTransaction != null) {
+ // Calling applyStateToWindow() here avoids skipping a frame when taking
+ // over an animation.
+ applyStateToWindow(
+ window,
+ createAnimatorState(),
+ linearProgress = 0f,
+ useSpring,
+ startTransaction,
+ )
+ }
+
delegate.onTransitionAnimationStart(isExpandingFullyAbove)
}
@@ -1094,14 +1442,29 @@ constructor(
progress: Float,
linearProgress: Float,
) {
- applyStateToWindow(window, state, linearProgress)
+ applyStateToWindow(window, state, linearProgress, useSpring)
navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
listener?.onTransitionAnimationProgress(linearProgress)
delegate.onTransitionAnimationProgress(state, progress, linearProgress)
}
}
-
+ val windowState =
+ if (startingWindowStates != null) {
+ startingWindowStates[startingWindowStates.size - window.prefixOrderIndex]
+ } else {
+ controller.windowAnimatorState
+ }
+ val velocityPxPerS =
+ if (longLivedReturnAnimationsEnabled() && windowState?.velocityPxPerMs != null) {
+ val xVelocityPxPerS = windowState.velocityPxPerMs.x * 1000
+ val yVelocityPxPerS = windowState.velocityPxPerMs.y * 1000
+ PointF(xVelocityPxPerS, yVelocityPxPerS)
+ } else if (useSpring) {
+ PointF(0f, 0f)
+ } else {
+ null
+ }
animation =
transitionAnimator.startAnimation(
controller,
@@ -1109,6 +1472,7 @@ constructor(
windowBackgroundColor,
fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
drawHole = !controller.isBelowAnimatingWindow,
+ startVelocity = velocityPxPerS,
)
}
@@ -1128,6 +1492,8 @@ constructor(
window: RemoteAnimationTarget,
state: TransitionAnimator.State,
linearProgress: Float,
+ useSpring: Boolean,
+ transaction: SurfaceControl.Transaction? = null,
) {
if (transactionApplierView.viewRootImpl == null || !window.leash.isValid) {
// Don't apply any transaction if the view root we synchronize with was detached or
@@ -1171,25 +1537,47 @@ constructor(
windowCropF.bottom.roundToInt(),
)
- val windowAnimationDelay =
+ val interpolators: TransitionAnimator.Interpolators
+ val windowProgress: Float
+
+ if (useSpring) {
+ val windowAnimationDelay: Float
+ val windowAnimationDuration: Float
if (controller.isLaunching) {
- TIMINGS.contentAfterFadeInDelay
+ windowAnimationDelay = SPRING_TIMINGS.contentAfterFadeInDelay
+ windowAnimationDuration = SPRING_TIMINGS.contentAfterFadeInDuration
} else {
- TIMINGS.contentBeforeFadeOutDelay
+ windowAnimationDelay = SPRING_TIMINGS.contentBeforeFadeOutDelay
+ windowAnimationDuration = SPRING_TIMINGS.contentBeforeFadeOutDuration
}
- val windowAnimationDuration =
+
+ interpolators = SPRING_INTERPOLATORS
+ windowProgress =
+ TransitionAnimator.getProgress(
+ linearProgress,
+ windowAnimationDelay,
+ windowAnimationDuration,
+ )
+ } else {
+ val windowAnimationDelay: Long
+ val windowAnimationDuration: Long
if (controller.isLaunching) {
- TIMINGS.contentAfterFadeInDuration
+ windowAnimationDelay = TIMINGS.contentAfterFadeInDelay
+ windowAnimationDuration = TIMINGS.contentAfterFadeInDuration
} else {
- TIMINGS.contentBeforeFadeOutDuration
+ windowAnimationDelay = TIMINGS.contentBeforeFadeOutDelay
+ windowAnimationDuration = TIMINGS.contentBeforeFadeOutDuration
}
- val windowProgress =
- TransitionAnimator.getProgress(
- TIMINGS,
- linearProgress,
- windowAnimationDelay,
- windowAnimationDuration,
- )
+
+ interpolators = INTERPOLATORS
+ windowProgress =
+ TransitionAnimator.getProgress(
+ TIMINGS,
+ linearProgress,
+ windowAnimationDelay,
+ windowAnimationDuration,
+ )
+ }
// The alpha of the opening window. If it opens above the expandable, then it should
// fade in progressively. Otherwise, it should be fully opaque and will be progressively
@@ -1197,12 +1585,12 @@ constructor(
val alpha =
if (controller.isBelowAnimatingWindow) {
if (controller.isLaunching) {
- INTERPOLATORS.contentAfterFadeInInterpolator.getInterpolation(
+ interpolators.contentAfterFadeInInterpolator.getInterpolation(
windowProgress
)
} else {
1 -
- INTERPOLATORS.contentBeforeFadeOutInterpolator.getInterpolation(
+ interpolators.contentBeforeFadeOutInterpolator.getInterpolation(
windowProgress
)
}
@@ -1216,6 +1604,7 @@ constructor(
// especially important for lock screen animations, where the window is not clipped by
// the shade.
val cornerRadius = maxOf(state.topCornerRadius, state.bottomCornerRadius) / scale
+
val params =
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash)
.withAlpha(alpha)
@@ -1223,11 +1612,15 @@ constructor(
.withWindowCrop(windowCrop)
.withCornerRadius(cornerRadius)
.withVisibility(true)
- .build()
+ if (transaction != null) params.withMergeTransaction(transaction)
- transactionApplier.scheduleApply(params)
+ transactionApplier.scheduleApply(params.build())
}
+ // TODO(b/377643129): remote transitions have no way of identifying the navbar when
+ // converting to RemoteAnimationTargets (and in my testing it was never included in the
+ // transition at all). So this method is not used anymore. Remove or adapt once we fully
+ // convert to remote transitions.
private fun applyStateToNavigationBar(
navigationBar: RemoteAnimationTarget,
state: TransitionAnimator.State,
@@ -1362,9 +1755,17 @@ constructor(
}
/** Register [remoteTransition] with WM Shell using the given [filter]. */
- internal fun register(filter: TransitionFilter, remoteTransition: RemoteTransition) {
+ internal fun register(
+ filter: TransitionFilter,
+ remoteTransition: RemoteTransition,
+ includeTakeover: Boolean,
+ ) {
shellTransitions?.registerRemote(filter, remoteTransition)
iShellTransitions?.registerRemote(filter, remoteTransition)
+ if (includeTakeover) {
+ shellTransitions?.registerRemoteForTakeover(filter, remoteTransition)
+ iShellTransitions?.registerRemoteForTakeover(filter, remoteTransition)
+ }
}
/** Unregister [remoteTransition] from WM Shell. */
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
index addabcc0282a..a137891f2d01 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
@@ -34,66 +34,60 @@ private const val FONT_ITALIC_MIN = 0f
private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
private const val FONT_ITALIC_DEFAULT_VALUE = 0f
-// Benchmarked via Perfetto, difference between 10 and 50 entries is about 0.3ms in
-// frame draw time on a Pixel 6.
-@VisibleForTesting const val DEFAULT_FONT_CACHE_MAX_ENTRIES = 10
+/** Caches for font interpolation */
+interface FontCache {
+ val animationFrameCount: Int
-/** Provide interpolation of two fonts by adjusting font variation settings. */
-class FontInterpolator(
- numberOfAnimationSteps: Int? = null,
-) {
- /**
- * Cache key for the interpolated font.
- *
- * This class is mutable for recycling.
- */
- private data class InterpKey(var l: Font?, var r: Font?, var progress: Float) {
- fun set(l: Font, r: Font, progress: Float) {
- this.l = l
- this.r = r
- this.progress = progress
- }
- }
+ fun get(key: InterpKey): Font?
- /**
- * Cache key for the font that has variable font.
- *
- * This class is mutable for recycling.
- */
- private data class VarFontKey(
- var sourceId: Int,
- var index: Int,
- val sortedAxes: MutableList<FontVariationAxis>
- ) {
- constructor(
- font: Font,
- axes: List<FontVariationAxis>
- ) : this(
- font.sourceIdentifier,
- font.ttcIndex,
- axes.toMutableList().apply { sortBy { it.tag } }
- )
-
- fun set(font: Font, axes: List<FontVariationAxis>) {
- sourceId = font.sourceIdentifier
- index = font.ttcIndex
- sortedAxes.clear()
- sortedAxes.addAll(axes)
- sortedAxes.sortBy { it.tag }
- }
- }
+ fun get(key: VarFontKey): Font?
+
+ fun put(key: InterpKey, font: Font)
+
+ fun put(key: VarFontKey, font: Font)
+}
+
+/** Cache key for the interpolated font. */
+data class InterpKey(val start: Font?, val end: Font?, val frame: Int)
+
+/** Cache key for the font that has variable font. */
+data class VarFontKey(val sourceId: Int, val index: Int, val sortedAxes: List<FontVariationAxis>) {
+ constructor(
+ font: Font,
+ axes: List<FontVariationAxis>,
+ ) : this(font.sourceIdentifier, font.ttcIndex, axes.sortedBy { it.tag })
+}
+class FontCacheImpl(override val animationFrameCount: Int = DEFAULT_FONT_CACHE_MAX_ENTRIES / 2) :
+ FontCache {
// Font interpolator has two level caches: one for input and one for font with different
// variation settings. No synchronization is needed since FontInterpolator is not designed to be
// thread-safe and can be used only on UI thread.
- val cacheMaxEntries = numberOfAnimationSteps?.let { it * 2 } ?: DEFAULT_FONT_CACHE_MAX_ENTRIES
+ val cacheMaxEntries = animationFrameCount * 2
private val interpCache = LruCache<InterpKey, Font>(cacheMaxEntries)
private val verFontCache = LruCache<VarFontKey, Font>(cacheMaxEntries)
- // Mutable keys for recycling.
- private val tmpInterpKey = InterpKey(null, null, 0f)
- private val tmpVarFontKey = VarFontKey(0, 0, mutableListOf())
+ override fun get(key: InterpKey): Font? = interpCache[key]
+ override fun get(key: VarFontKey): Font? = verFontCache[key]
+
+ override fun put(key: InterpKey, font: Font) {
+ interpCache.put(key, font)
+ }
+
+ override fun put(key: VarFontKey, font: Font) {
+ verFontCache.put(key, font)
+ }
+
+ companion object {
+ // Benchmarked via Perfetto, difference between 10 and 50 entries is about 0.3ms in frame
+ // draw time on a Pixel 6.
+ @VisibleForTesting const val DEFAULT_FONT_CACHE_MAX_ENTRIES = 10
+ }
+}
+
+/** Provide interpolation of two fonts by adjusting font variation settings. */
+class FontInterpolator(val fontCache: FontCache = FontCacheImpl()) {
/** Linear interpolate the font variation settings. */
fun lerp(start: Font, end: Font, progress: Float): Font {
if (progress == 0f) {
@@ -111,13 +105,12 @@ class FontInterpolator(
// Check we already know the result. This is commonly happens since we draws the different
// text chunks with the same font.
- tmpInterpKey.set(start, end, progress)
- val cachedFont = interpCache[tmpInterpKey]
- if (cachedFont != null) {
+ val iKey = InterpKey(start, end, (progress * fontCache.animationFrameCount).toInt())
+ fontCache.get(iKey)?.let {
if (DEBUG) {
- Log.d(LOG_TAG, "[$progress] Interp. cache hit for $tmpInterpKey")
+ Log.d(LOG_TAG, "[$progress] Interp. cache hit for $iKey")
}
- return cachedFont
+ return it
}
// General axes interpolation takes O(N log N), this is came from sorting the axes. Usually
@@ -131,14 +124,14 @@ class FontInterpolator(
MathUtils.lerp(
startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
- progress
+ progress,
)
TAG_ITAL ->
adjustItalic(
MathUtils.lerp(
startValue ?: FONT_ITALIC_DEFAULT_VALUE,
endValue ?: FONT_ITALIC_DEFAULT_VALUE,
- progress
+ progress,
)
)
else -> {
@@ -152,32 +145,31 @@ class FontInterpolator(
// Check if we already make font for this axes. This is typically happens if the animation
// happens backward.
- tmpVarFontKey.set(start, newAxes)
- val axesCachedFont = verFontCache[tmpVarFontKey]
- if (axesCachedFont != null) {
- interpCache.put(InterpKey(start, end, progress), axesCachedFont)
+ val vKey = VarFontKey(start, newAxes)
+ fontCache.get(vKey)?.let {
+ fontCache.put(iKey, it)
if (DEBUG) {
- Log.d(LOG_TAG, "[$progress] Axis cache hit for $tmpVarFontKey")
+ Log.d(LOG_TAG, "[$progress] Axis cache hit for $vKey")
}
- return axesCachedFont
+ return it
}
// This is the first time to make the font for the axes. Build and store it to the cache.
// Font.Builder#build won't throw IOException since creating fonts from existing fonts will
// not do any IO work.
val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
- interpCache.put(InterpKey(start, end, progress), newFont)
- verFontCache.put(VarFontKey(start, newAxes), newFont)
+ fontCache.put(iKey, newFont)
+ fontCache.put(vKey, newFont)
// Cache misses are likely to create memory leaks, so this is logged at error level.
- Log.e(LOG_TAG, "[$progress] Cache MISS for $tmpInterpKey / $tmpVarFontKey")
+ Log.e(LOG_TAG, "[$progress] Cache MISS for $iKey / $vKey")
return newFont
}
private fun lerp(
start: Array<FontVariationAxis>,
end: Array<FontVariationAxis>,
- filter: (tag: String, left: Float?, right: Float?) -> Float
+ filter: (tag: String, left: Float?, right: Float?) -> Float,
): List<FontVariationAxis> {
// Safe to modify result of Font#getAxes since it returns cloned object.
start.sortBy { axis -> axis.tag }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 978943ae7f7c..eef26b67614b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -35,6 +35,8 @@ private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
interface TypefaceVariantCache {
+ val fontCache: FontCache
+ val animationFrameCount: Int
fun getTypefaceForVariant(fvar: String?): Typeface?
companion object {
@@ -57,8 +59,10 @@ interface TypefaceVariantCache {
class TypefaceVariantCacheImpl(
var baseTypeface: Typeface,
+ override val animationFrameCount: Int,
) : TypefaceVariantCache {
private val cache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES)
+ override val fontCache = FontCacheImpl(animationFrameCount)
override fun getTypefaceForVariant(fvar: String?): Typeface? {
if (fvar == null) {
return baseTypeface
@@ -100,25 +104,17 @@ class TypefaceVariantCacheImpl(
*/
class TextAnimator(
layout: Layout,
- numberOfAnimationSteps: Int? = null, // Only do this number of discrete animation steps.
- private val invalidateCallback: () -> Unit,
+ private val typefaceCache: TypefaceVariantCache,
+ private val invalidateCallback: () -> Unit = {},
) {
- var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl(layout.paint.typeface)
- get() = field
- set(value) {
- field = value
- textInterpolator.typefaceCache = value
- }
-
// Following two members are for mutable for testing purposes.
- public var textInterpolator: TextInterpolator =
- TextInterpolator(layout, typefaceCache, numberOfAnimationSteps)
- public var animator: ValueAnimator =
+ public var textInterpolator = TextInterpolator(layout, typefaceCache)
+ public var animator =
ValueAnimator.ofFloat(1f).apply {
duration = DEFAULT_ANIMATION_DURATION
addUpdateListener {
textInterpolator.progress =
- calculateProgress(it.animatedValue as Float, numberOfAnimationSteps)
+ calculateProgress(it.animatedValue as Float, typefaceCache.animationFrameCount)
invalidateCallback()
}
addListener(
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 02caeeddd774..9c0c0ffc8d41 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -28,11 +28,7 @@ import com.android.internal.graphics.ColorUtils
import java.lang.Math.max
/** Provide text style linear interpolation for plain text. */
-class TextInterpolator(
- layout: Layout,
- var typefaceCache: TypefaceVariantCache,
- numberOfAnimationSteps: Int? = null,
-) {
+class TextInterpolator(layout: Layout, var typefaceCache: TypefaceVariantCache) {
/**
* Returns base paint used for interpolation.
*
@@ -66,7 +62,7 @@ class TextInterpolator(
val start: Int, // inclusive
val end: Int, // exclusive
var baseFont: Font,
- var targetFont: Font
+ var targetFont: Font,
) {
val length: Int
get() = end - start
@@ -79,14 +75,14 @@ class TextInterpolator(
val baseY: FloatArray, // same length as glyphIds
val targetX: FloatArray, // same length as glyphIds
val targetY: FloatArray, // same length as glyphIds
- val fontRuns: List<FontRun>
+ val fontRuns: List<FontRun>,
)
/** A class represents text layout of a single line. */
private class Line(val runs: List<Run>)
private var lines = listOf<Line>()
- private val fontInterpolator = FontInterpolator(numberOfAnimationSteps)
+ private val fontInterpolator = FontInterpolator(typefaceCache.fontCache)
// Recycling object for glyph drawing and tweaking.
private val tmpPaint = TextPaint()
@@ -343,12 +339,16 @@ class TextInterpolator(
private class MutablePositionedGlyph : TextAnimator.PositionedGlyph() {
override var runStart: Int = 0
public set
+
override var runLength: Int = 0
public set
+
override var glyphIndex: Int = 0
public set
+
override lateinit var font: Font
public set
+
override var glyphId: Int = 0
public set
}
@@ -401,7 +401,7 @@ class TextInterpolator(
0,
i - prevStart,
font,
- tmpPaintForGlyph
+ tmpPaintForGlyph,
)
prevStart = i
arrayIndex = 0
@@ -418,13 +418,13 @@ class TextInterpolator(
0,
run.end - prevStart,
font,
- tmpPaintForGlyph
+ tmpPaintForGlyph,
)
}
private fun updatePositionsAndFonts(
layoutResult: List<List<PositionedGlyphs>>,
- updateBase: Boolean
+ updateBase: Boolean,
) {
// Update target positions with newly calculated text layout.
check(layoutResult.size == lines.size) { "The new layout result has different line count." }
@@ -507,7 +507,7 @@ class TextInterpolator(
lineStart,
count,
layout.textDirectionHeuristic,
- paint
+ paint,
) { _, _, glyphs, _ ->
runs.add(glyphs)
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index fdb4871423c3..e2bc4095e1b5 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.internal.dynamicanimation.animation.SpringAnimation
import com.android.internal.dynamicanimation.animation.SpringForce
import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
+import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived
import java.util.concurrent.Executor
import kotlin.math.abs
import kotlin.math.max
@@ -113,13 +114,26 @@ class TransitionAnimator(
)
}
- internal fun checkReturnAnimationFrameworkFlag() {
- check(returnAnimationFrameworkLibrary()) {
- "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag is " +
- "disabled"
+ fun assertReturnAnimations() {
+ check(returnAnimationsEnabled()) {
+ "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag " +
+ "is disabled"
}
}
+ fun returnAnimationsEnabled() = returnAnimationFrameworkLibrary()
+
+ fun assertLongLivedReturnAnimations() {
+ check(longLivedReturnAnimationsEnabled()) {
+ "Long-lived registrations cannot be used when the " +
+ "returnAnimationFrameworkLibrary or the " +
+ "returnAnimationFrameworkLongLived flag are disabled"
+ }
+ }
+
+ fun longLivedReturnAnimationsEnabled() =
+ returnAnimationFrameworkLibrary() && returnAnimationFrameworkLongLived()
+
internal fun WindowAnimationState.toTransitionState() =
State().also {
bounds?.let { b ->
@@ -467,7 +481,8 @@ class TransitionAnimator(
drawHole: Boolean = false,
startVelocity: PointF? = null,
): Animation {
- if (!controller.isLaunching || startVelocity != null) checkReturnAnimationFrameworkFlag()
+ if (!controller.isLaunching) assertReturnAnimations()
+ if (startVelocity != null) assertLongLivedReturnAnimations()
// We add an extra layer with the same color as the dialog/app splash screen background
// color, which is usually the same color of the app background. We first fade in this layer
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
index 6c982a045084..9e872fc5d3c5 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
@@ -58,7 +58,12 @@ fun BackAnimationSpec.Companion.createFloatingSurfaceAnimationSpec(
val maxTranslationY = maxTranslationYByScale - maxMarginYPx
val minScaleReversed = 1f - minScale
- val direction = if (backEvent.swipeEdge == BackEvent.EDGE_LEFT) 1 else -1
+ val direction =
+ when (backEvent.swipeEdge) {
+ BackEvent.EDGE_LEFT -> 1
+ BackEvent.EDGE_RIGHT -> -1
+ else -> 0
+ }
val progressX = backEvent.progress
val ratioTranslateX = translateXEasing.getInterpolation(progressX)
diff --git a/packages/SystemUI/common/Android.bp b/packages/SystemUI/common/Android.bp
index 91dc3e338c59..9f1598364dbc 100644
--- a/packages/SystemUI/common/Android.bp
+++ b/packages/SystemUI/common/Android.bp
@@ -30,5 +30,9 @@ java_library {
"src/**/*.kt",
],
+ static_libs: ["SystemUI-shared-utils"],
+
+ libs: ["//frameworks/libs/systemui:tracinglib-platform"],
+
kotlincflags: ["-Xjvm-default=all"],
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt b/packages/SystemUI/common/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt
index 0c181e99b21c..0c181e99b21c 100644
--- a/packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt
+++ b/packages/SystemUI/common/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt
diff --git a/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt b/packages/SystemUI/common/src/com/android/systemui/coroutines/Tracing.kt
index efbdf4d1533d..efbdf4d1533d 100644
--- a/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt
+++ b/packages/SystemUI/common/src/com/android/systemui/coroutines/Tracing.kt
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
index d31d7aa59489..71ec63c1666c 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
@@ -63,6 +63,9 @@ private fun platformColorScheme(isDarkTheme: Boolean, context: Context): ColorSc
return if (isDarkTheme) {
dynamicDarkColorScheme(context)
.copy(
+ inverseSurface = color(context, R.color.system_inverse_surface_dark),
+ inverseOnSurface = color(context, R.color.system_inverse_on_surface_dark),
+ inversePrimary = color(context, R.color.system_inverse_primary_dark),
error = color(context, R.color.system_error_dark),
onError = color(context, R.color.system_on_error_dark),
errorContainer = color(context, R.color.system_error_container_dark),
@@ -71,6 +74,9 @@ private fun platformColorScheme(isDarkTheme: Boolean, context: Context): ColorSc
} else {
dynamicLightColorScheme(context)
.copy(
+ inverseSurface = color(context, R.color.system_inverse_surface_light),
+ inverseOnSurface = color(context, R.color.system_inverse_on_surface_light),
+ inversePrimary = color(context, R.color.system_inverse_primary_light),
error = color(context, R.color.system_error_light),
onError = color(context, R.color.system_on_error_light),
errorContainer = color(context, R.color.system_error_container_light),
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
index de021a0677cf..737853b88f7a 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
@@ -89,7 +89,7 @@ class PlatformThemeTest {
addValue(
"inversePrimary",
colorScheme.inversePrimary,
- R.attr.materialColorPrimaryInverse,
+ R.attr.materialColorInversePrimary,
)
addValue("secondary", colorScheme.secondary, R.attr.materialColorSecondary)
addValue("onSecondary", colorScheme.onSecondary, R.attr.materialColorOnSecondary)
@@ -131,12 +131,12 @@ class PlatformThemeTest {
addValue(
"inverseSurface",
colorScheme.inverseSurface,
- R.attr.materialColorSurfaceInverse,
+ R.attr.materialColorInverseSurface,
)
addValue(
"inverseOnSurface",
colorScheme.inverseOnSurface,
- R.attr.materialColorOnSurfaceInverse,
+ R.attr.materialColorInverseOnSurface,
)
addValue("error", colorScheme.error, R.attr.materialColorError)
addValue("onError", colorScheme.onError, R.attr.materialColorOnError)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 87e9c427d695..4705d8dd86c4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -44,6 +44,7 @@ import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
+import com.android.systemui.Flags.communalHubOnMobile
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
@@ -186,15 +187,19 @@ fun CommunalContainer(
) {
scene(
CommunalScenes.Blank,
- userActions = mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal),
+ userActions =
+ if (communalHubOnMobile()) emptyMap()
+ else mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal),
) {
// This scene shows nothing only allowing for transitions to the communal scene.
Box(modifier = Modifier.fillMaxSize())
}
- val userActions = mapOf(Swipe.End to CommunalScenes.Blank)
-
- scene(CommunalScenes.Communal, userActions = userActions) {
+ scene(
+ CommunalScenes.Communal,
+ userActions =
+ if (communalHubOnMobile()) emptyMap() else mapOf(Swipe.End to CommunalScenes.Blank),
+ ) {
CommunalScene(
backgroundType = backgroundType,
colors = colors,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
index 9392b1afffa3..778d7e7f99b3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
@@ -66,13 +66,14 @@ constructor(
interactionHandler = interactionHandler,
dialogFactory = dialogFactory,
widgetSection = widgetSection,
- modifier = Modifier.element(Communal.Elements.Grid)
+ modifier = Modifier.element(Communal.Elements.Grid),
+ sceneScope = this@Content,
)
}
with(lockSection) {
LockIcon(
overrideColor = MaterialTheme.colorScheme.onPrimaryContainer,
- modifier = Modifier.element(Communal.Elements.LockIcon)
+ modifier = Modifier.element(Communal.Elements.LockIcon),
)
}
with(bottomAreaSection) {
@@ -80,17 +81,13 @@ constructor(
Modifier.element(Communal.Elements.IndicationArea).fillMaxWidth()
)
}
- }
+ },
) { measurables, constraints ->
val communalGridMeasurable = measurables[0]
val lockIconMeasurable = measurables[1]
val bottomAreaMeasurable = measurables[2]
- val noMinConstraints =
- constraints.copy(
- minWidth = 0,
- minHeight = 0,
- )
+ val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0)
val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
val lockIconBounds =
@@ -109,14 +106,8 @@ constructor(
)
layout(constraints.maxWidth, constraints.maxHeight) {
- communalGridPlaceable.place(
- x = 0,
- y = 0,
- )
- lockIconPlaceable.place(
- x = lockIconBounds.left,
- y = lockIconBounds.top,
- )
+ communalGridPlaceable.place(x = 0, y = 0)
+ lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top)
bottomAreaPlaceable.place(
x = 0,
y = constraints.maxHeight - bottomAreaPlaceable.height,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 5e1ac1f30354..5b1203fa17c9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -163,6 +163,7 @@ import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.layout.WindowMetricsCalculator
import com.android.compose.animation.Easings.Emphasized
+import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.thenIf
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.internal.R.dimen.system_app_widget_background_radius
@@ -186,7 +187,9 @@ import com.android.systemui.communal.util.DensityUtils.Companion.adjustedDp
import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import kotlin.math.max
import kotlin.math.min
@@ -205,6 +208,7 @@ fun CommunalHub(
widgetConfigurator: WidgetConfigurator? = null,
onOpenWidgetPicker: (() -> Unit)? = null,
onEditDone: (() -> Unit)? = null,
+ sceneScope: SceneScope? = null,
) {
val communalContent by
viewModel.communalContent.collectAsStateWithLifecycle(initialValue = emptyList())
@@ -414,6 +418,7 @@ fun CommunalHub(
widgetConfigurator = widgetConfigurator,
interactionHandler = interactionHandler,
widgetSection = widgetSection,
+ sceneScope = sceneScope,
)
}
}
@@ -735,6 +740,7 @@ private fun BoxScope.CommunalHubLazyGrid(
widgetConfigurator: WidgetConfigurator?,
interactionHandler: RemoteViews.InteractionHandler?,
widgetSection: CommunalAppWidgetSection,
+ sceneScope: SceneScope?,
) {
var gridModifier =
Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
@@ -807,7 +813,6 @@ private fun BoxScope.CommunalHubLazyGrid(
) {
ResizeableItemFrameViewModel()
}
-
if (viewModel.isEditMode && dragDropState != null) {
val isItemDragging = dragDropState.draggingItemKey == item.key
val outlineAlpha by
@@ -872,6 +877,7 @@ private fun BoxScope.CommunalHubLazyGrid(
interactionHandler = interactionHandler,
widgetSection = widgetSection,
resizeableItemFrameViewModel = resizeableItemFrameViewModel,
+ sceneScope = sceneScope,
)
}
}
@@ -1096,6 +1102,7 @@ private fun CommunalContent(
interactionHandler: RemoteViews.InteractionHandler?,
widgetSection: CommunalAppWidgetSection,
resizeableItemFrameViewModel: ResizeableItemFrameViewModel,
+ sceneScope: SceneScope? = null,
) {
when (model) {
is CommunalContentModel.WidgetContent.Widget ->
@@ -1119,7 +1126,7 @@ private fun CommunalContent(
is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier)
is CommunalContentModel.Smartspace -> SmartspaceContent(interactionHandler, model, modifier)
is CommunalContentModel.Tutorial -> TutorialContent(modifier)
- is CommunalContentModel.Umo -> Umo(viewModel, modifier)
+ is CommunalContentModel.Umo -> Umo(viewModel, sceneScope, modifier)
}
}
@@ -1530,7 +1537,25 @@ private fun TutorialContent(modifier: Modifier = Modifier) {
}
@Composable
-private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) {
+private fun Umo(
+ viewModel: BaseCommunalViewModel,
+ sceneScope: SceneScope?,
+ modifier: Modifier = Modifier,
+) {
+ if (SceneContainerFlag.isEnabled && sceneScope != null) {
+ sceneScope.MediaCarousel(
+ modifier = modifier.fillMaxSize(),
+ isVisible = true,
+ mediaHost = viewModel.mediaHost,
+ carouselController = viewModel.mediaCarouselController,
+ )
+ } else {
+ UmoLegacy(viewModel, modifier)
+ }
+}
+
+@Composable
+private fun UmoLegacy(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) {
AndroidView(
modifier =
modifier.pointerInput(Unit) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
index 6e30575a684d..16002bc709fd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
@@ -59,7 +59,14 @@ internal constructor(
private val onAddWidget: (componentName: ComponentName, user: UserHandle, rank: Int) -> Unit,
private val onDeleteWidget: (id: Int, componentName: ComponentName, rank: Int) -> Unit,
private val onReorderWidgets: (widgetIdToRankMap: Map<Int, Int>) -> Unit,
- private val onResizeWidget: (id: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) -> Unit,
+ private val onResizeWidget:
+ (
+ id: Int,
+ spanY: Int,
+ widgetIdToRankMap: Map<Int, Int>,
+ componentName: ComponentName,
+ rank: Int,
+ ) -> Unit,
) {
var list = communalContent.toMutableStateList()
private set
@@ -105,7 +112,9 @@ internal constructor(
} else {
emptyMap()
}
- onResizeWidget(item.appWidgetId, newSpan, widgetIdToRankMap)
+ val componentName = item.componentName
+ val rank = item.rank
+ onResizeWidget(item.appWidgetId, newSpan, widgetIdToRankMap, componentName, rank)
}
/**
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 1551ca97a2e3..ef5e90bd7aad 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -179,11 +179,18 @@ internal constructor(
val targetItem =
if (communalWidgetResizing()) {
state.layoutInfo.visibleItemsInfo.findLast { item ->
+ val lastVisibleItemIndex = state.layoutInfo.visibleItemsInfo.last().index
val itemBoundingBox = IntRect(item.offset, item.size)
draggingItemKey != item.key &&
contentListState.isItemEditable(item.index) &&
(draggingBoundingBox.contains(itemBoundingBox.center) ||
- itemBoundingBox.contains(draggingBoundingBox.center))
+ itemBoundingBox.contains(draggingBoundingBox.center)) &&
+ // If we swap with the last visible item, and that item doesn't fit
+ // in the gap created by moving the current item, then the current item
+ // will get placed after the last visible item. In this case, it gets
+ // placed outside of the viewport. We avoid this here, so the user
+ // has to scroll first before the swap can happen.
+ (item.index != lastVisibleItemIndex || item.span <= draggingItem.span)
}
} else {
state.layoutInfo.visibleItemsInfo
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 2a2c2fc4934e..105e8dadfafb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -21,7 +21,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -70,10 +69,7 @@ constructor(
override val id: String = "default"
@Composable
- override fun SceneScope.Content(
- viewModel: LockscreenContentViewModel,
- modifier: Modifier,
- ) {
+ override fun SceneScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
@@ -85,22 +81,18 @@ constructor(
with(notificationSection) { HeadsUpNotifications() }
}
- LockscreenLongPress(
- viewModel = viewModel.touchHandling,
- modifier = modifier,
- ) { onSettingsMenuPlaced ->
+ LockscreenLongPress(viewModel = viewModel.touchHandling, modifier = modifier) {
+ onSettingsMenuPlaced ->
Layout(
content = {
// Constrained to above the lock icon.
- Column(
- modifier = Modifier.fillMaxSize(),
- ) {
+ Column(modifier = Modifier.fillMaxSize()) {
with(statusBarSection) {
StatusBar(
modifier =
Modifier.fillMaxWidth()
.padding(
- horizontal = { unfoldTranslations.start.roundToInt() },
+ horizontal = { unfoldTranslations.start.roundToInt() }
)
)
}
@@ -109,13 +101,14 @@ constructor(
with(topAreaSection) {
DefaultClockLayout(
smartSpacePaddingTop = viewModel::getSmartSpacePaddingTop,
+ isShadeLayoutWide = isShadeLayoutWide,
modifier =
Modifier.thenIf(isShadeLayoutWide) {
Modifier.fillMaxWidth(0.5f)
}
.graphicsLayer {
translationX = unfoldTranslations.start
- }
+ },
)
}
if (isShadeLayoutWide && !isBypassEnabled) {
@@ -127,7 +120,7 @@ constructor(
modifier =
Modifier.fillMaxWidth(0.5f)
.fillMaxHeight()
- .align(alignment = Alignment.TopEnd)
+ .align(alignment = Alignment.TopEnd),
)
}
}
@@ -142,7 +135,7 @@ constructor(
AodNotificationIcons(
modifier =
Modifier.align(alignment = Alignment.TopStart)
- .padding(start = aodIconPadding),
+ .padding(start = aodIconPadding)
)
Notifications(
areNotificationsVisible = areNotificationsVisible,
@@ -152,7 +145,7 @@ constructor(
}
} else {
AodNotificationIcons(
- modifier = Modifier.padding(start = aodIconPadding),
+ modifier = Modifier.padding(start = aodIconPadding)
)
}
}
@@ -205,11 +198,7 @@ constructor(
val endShortcutMeasurable = measurables[4]
val settingsMenuMeasurable = measurables[5]
- val noMinConstraints =
- constraints.copy(
- minWidth = 0,
- minHeight = 0,
- )
+ val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0)
val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
val lockIconBounds =
IntRect(
@@ -235,14 +224,8 @@ constructor(
val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints)
layout(constraints.maxWidth, constraints.maxHeight) {
- aboveLockIconPlaceable.place(
- x = 0,
- y = 0,
- )
- lockIconPlaceable.place(
- x = lockIconBounds.left,
- y = lockIconBounds.top,
- )
+ aboveLockIconPlaceable.place(x = 0, y = 0)
+ lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top)
belowLockIconPlaceable.place(
x = 0,
y = constraints.maxHeight - belowLockIconPlaceable.height,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index 9390664d1283..597cbf24729b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -31,6 +31,7 @@ import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
@@ -147,7 +148,7 @@ constructor(
} else {
val scaleFactor = authController.scaleFactor
val bottomPaddingPx =
- context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
+ context.resources.getDimensionPixelSize(customR.dimen.lock_icon_margin_bottom)
val heightPx = windowViewBounds.bottom.toFloat()
Pair(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
index 3ca2b9c1d86c..4a9f44b74099 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -17,9 +17,11 @@
package com.android.systemui.keyguard.ui.composable.section
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.dimensionResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
@@ -27,6 +29,7 @@ import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.res.R
import javax.inject.Inject
import javax.inject.Named
@@ -39,13 +42,22 @@ constructor(
) {
@Composable
- fun SceneScope.KeyguardMediaCarousel() {
+ fun SceneScope.KeyguardMediaCarousel(
+ isShadeLayoutWide: Boolean,
+ modifier: Modifier = Modifier,
+ ) {
val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle()
-
+ val horizontalPadding =
+ if (isShadeLayoutWide) {
+ dimensionResource(id = R.dimen.notification_side_paddings)
+ } else {
+ dimensionResource(id = R.dimen.notification_side_paddings) +
+ dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
+ }
MediaCarousel(
isVisible = isMediaVisible,
mediaHost = mediaHost,
- modifier = Modifier.fillMaxWidth(),
+ modifier = modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
carouselController = mediaCarouselController,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index afa92f2533ce..db33e7c628d7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -63,6 +63,7 @@ constructor(
@Composable
fun SceneScope.DefaultClockLayout(
smartSpacePaddingTop: (Resources) -> Int,
+ isShadeLayoutWide: Boolean,
modifier: Modifier = Modifier,
) {
val currentClockLayout by clockViewModel.currentClockLayout.collectAsStateWithLifecycle()
@@ -128,7 +129,7 @@ constructor(
)
}
}
- with(mediaCarouselSection) { KeyguardMediaCarousel() }
+ with(mediaCarouselSection) { KeyguardMediaCarousel(isShadeLayoutWide) }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 20c8c6a3f4bf..2d32fd768eaa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -36,6 +36,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
@@ -84,6 +85,7 @@ import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsSecurityButtonVi
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.qs.ui.composable.QuickSettingsTheme
+import com.android.systemui.qs.ui.compose.borderOnFocus
import com.android.systemui.res.R
import kotlinx.coroutines.launch
@@ -264,7 +266,11 @@ private fun IconButton(model: FooterActionsButtonViewModel, modifier: Modifier =
color = colorAttr(model.backgroundColor),
shape = CircleShape,
onClick = model.onClick,
- modifier = modifier,
+ modifier =
+ modifier.borderOnFocus(
+ color = MaterialTheme.colorScheme.secondary,
+ CornerSize(percent = 50),
+ ),
) {
val tint = model.iconTint?.let { Color(it) } ?: Color.Unspecified
Icon(model.icon, tint = tint, modifier = Modifier.size(20.dp))
@@ -291,7 +297,11 @@ private fun NumberButton(
shape = CircleShape,
onClick = onClick,
interactionSource = interactionSource,
- modifier = modifier,
+ modifier =
+ modifier.borderOnFocus(
+ color = MaterialTheme.colorScheme.secondary,
+ CornerSize(percent = 50),
+ ),
) {
Box(Modifier.size(40.dp)) {
Box(
@@ -342,7 +352,10 @@ private fun TextButton(
color = colorAttr(R.attr.underSurface),
contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
borderStroke = BorderStroke(1.dp, colorAttr(R.attr.shadeInactive)),
- modifier = modifier.padding(horizontal = 4.dp),
+ modifier =
+ modifier
+ .padding(horizontal = 4.dp)
+ .borderOnFocus(color = MaterialTheme.colorScheme.secondary, CornerSize(50)),
onClick = onClick,
) {
Row(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index e725ce589f3e..58336c2e9d41 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -79,8 +79,8 @@ object QuickSettings {
val MediaLandscapeTopOffset = ValueKey("MediaLandscapeTopOffset")
object MediaOffset {
- // Brightness + padding
- val InQS = 92.dp
+ // Brightness
+ val InQS = 60.dp
val Default = 0.dp
@Composable
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 0e7165c7f3ec..52adaf2a5b5d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -74,6 +74,7 @@ import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateSceneDpAsState
import com.android.compose.animation.scene.animateSceneFloatAsState
import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.modifiers.padding
import com.android.compose.modifiers.thenIf
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.battery.BatteryMeterViewController
@@ -379,7 +380,11 @@ private fun SceneScope.QuickSettingsScene(
mediaHost = mediaHost,
modifier =
Modifier.fillMaxWidth()
- .layoutId(QSMediaMeasurePolicy.LayoutId.Media),
+ .layoutId(QSMediaMeasurePolicy.LayoutId.Media)
+ .padding(
+ horizontal =
+ dimensionResource(id = R.dimen.qs_horizontal_margin)
+ ),
carouselController = mediaCarouselController,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 26c827a5417c..f84865ffc6af 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -168,7 +168,6 @@ fun SceneScope.QuickSettingsLayout(
modifier =
Modifier.fillMaxWidth()
.heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight),
- viewModel.editModeViewModel::startEditing,
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index ae5dd8abb82e..5fb9416cf35b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -19,12 +19,17 @@ package com.android.systemui.scene.ui.composable
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateContentDpAsState
import com.android.compose.animation.scene.animateContentFloatAsState
+import com.android.compose.animation.scene.content.state.TransitionState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.rememberViewModel
@@ -63,9 +68,25 @@ constructor(
}
@Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
+ override fun SceneScope.Content(modifier: Modifier) {
+
+ val isIdle by remember {
+ derivedStateOf { layoutState.transitionState is TransitionState.Idle }
+ }
+
+ LaunchedEffect(isIdle) {
+ // Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon,
+ // and another transition could override the NSSL stack bounds.
+ if (isIdle) {
+ // Reset the stack bounds to avoid caching these values from the previous Scenes,
+ // and not to confuse the StackScrollAlgorithm when it displays a HUN over GONE.
+ notificationStackScrolLView.get().apply {
+ setStackTop(0f)
+ setStackCutoff(0f)
+ }
+ }
+ }
+
animateContentFloatAsState(
value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting,
key = QuickSettings.SharedValues.TilesSquishiness,
@@ -75,9 +96,7 @@ constructor(
SnoozeableHeadsUpNotificationSpace(
stackScrollView = notificationStackScrolLView.get(),
viewModel =
- rememberViewModel("GoneScene") {
- notificationsPlaceholderViewModelFactory.create()
- },
+ rememberViewModel("GoneScene") { notificationsPlaceholderViewModelFactory.create() },
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 2d58c8cad2b1..a266e7eb44a1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -49,7 +49,6 @@ import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
import javax.inject.Provider
-import kotlinx.coroutines.flow.collectLatest
/**
* Renders a container of a collection of "scenes" that the user can switch between using certain
@@ -117,7 +116,7 @@ fun SceneContainer(
) {
"invalid ContentKey: $actionableContentKey"
}
- actionableContent.userActions.collectLatest { userActions ->
+ viewModel.filteredUserActions(actionableContent.userActions).collect { userActions ->
userActionsByContentKey[actionableContentKey] =
viewModel.resolveSceneFamilies(userActions)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 2cde6787f730..9de7a5d659ae 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -15,7 +15,10 @@ import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransit
import com.android.systemui.scene.ui.composable.transitions.bouncerToLockscreenPreview
import com.android.systemui.scene.ui.composable.transitions.communalToBouncerTransition
import com.android.systemui.scene.ui.composable.transitions.communalToShadeTransition
+import com.android.systemui.scene.ui.composable.transitions.dreamToBouncerTransition
+import com.android.systemui.scene.ui.composable.transitions.dreamToCommunalTransition
import com.android.systemui.scene.ui.composable.transitions.dreamToGoneTransition
+import com.android.systemui.scene.ui.composable.transitions.dreamToShadeTransition
import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.goneToShadeTransition
import com.android.systemui.scene.ui.composable.transitions.goneToSplitShadeTransition
@@ -55,7 +58,10 @@ val SceneContainerTransitions = transitions {
// Scene transitions
from(Scenes.Bouncer, to = Scenes.Gone) { bouncerToGoneTransition() }
+ from(Scenes.Dream, to = Scenes.Bouncer) { dreamToBouncerTransition() }
+ from(Scenes.Dream, to = Scenes.Communal) { dreamToCommunalTransition() }
from(Scenes.Dream, to = Scenes.Gone) { dreamToGoneTransition() }
+ from(Scenes.Dream, to = Scenes.Shade) { dreamToShadeTransition() }
from(Scenes.Gone, to = Scenes.Shade) { goneToShadeTransition() }
from(Scenes.Gone, to = Scenes.Shade, key = ToSplitShade) { goneToSplitShadeTransition() }
from(Scenes.Gone, to = Scenes.Shade, key = SlightlyFasterShadeCollapse) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToBouncerTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToBouncerTransition.kt
new file mode 100644
index 000000000000..8cb89f91a831
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToBouncerTransition.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.scene.ui.composable.transitions
+
+import com.android.compose.animation.scene.TransitionBuilder
+
+fun TransitionBuilder.dreamToBouncerTransition() {
+ toBouncerTransition()
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt
new file mode 100644
index 000000000000..93c10b6224ab
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.scene.ui.composable.transitions
+
+import androidx.compose.animation.core.tween
+import com.android.compose.animation.scene.Edge
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.communal.ui.compose.AllElements
+import com.android.systemui.communal.ui.compose.Communal
+
+fun TransitionBuilder.dreamToCommunalTransition() {
+ spec = tween(durationMillis = 1000)
+
+ // Translate communal hub grid from the end direction.
+ translate(Communal.Elements.Grid, Edge.End)
+
+ // Fade all communal hub elements.
+ timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToShadeTransition.kt
new file mode 100644
index 000000000000..e35aaae19e29
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToShadeTransition.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.scene.ui.composable.transitions
+
+import com.android.compose.animation.scene.TransitionBuilder
+
+fun TransitionBuilder.dreamToShadeTransition(durationScale: Double = 1.0) {
+ toShadeTransition(durationScale = durationScale)
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
index 71fa6c9e567a..ce7a85b19fb4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
@@ -19,11 +19,8 @@ package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
@@ -31,24 +28,17 @@ import com.android.systemui.shade.ui.composable.Shade
import com.android.systemui.shade.ui.composable.ShadeHeader
import kotlin.time.Duration.Companion.milliseconds
-fun TransitionBuilder.goneToSplitShadeTransition(
- durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.goneToSplitShadeTransition(durationScale: Double = 1.0) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
swipeSpec =
spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
)
- distance =
- object : UserActionDistance {
- override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
- orientation: Orientation,
- ): Float {
- return fromSceneSize.height.toFloat() * 2 / 3f
- }
- }
+ distance = UserActionDistance { fromContent, _, _ ->
+ val fromContentSize = checkNotNull(fromContent.targetSize())
+ fromContentSize.height.toFloat() * 2 / 3f
+ }
fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
index 1486ea7d53b5..1f7a7380bbc6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
@@ -19,35 +19,25 @@ package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.shade.ui.composable.Shade
import com.android.systemui.shade.ui.composable.ShadeHeader
import kotlin.time.Duration.Companion.milliseconds
-fun TransitionBuilder.lockscreenToSplitShadeTransition(
- durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.lockscreenToSplitShadeTransition(durationScale: Double = 1.0) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
swipeSpec =
spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
)
- distance =
- object : UserActionDistance {
- override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
- orientation: Orientation,
- ): Float {
- return fromSceneSize.height.toFloat() * 2 / 3f
- }
- }
+ distance = UserActionDistance { fromContent, _, _ ->
+ val fromContentSize = checkNotNull(fromContent.targetSize())
+ fromContentSize.height.toFloat() * 2 / 3f
+ }
fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
index 8cd357ef92a5..ba1972fbcc5a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
@@ -1,46 +1,36 @@
package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.composable.ShadeHeader
import kotlin.time.Duration.Companion.milliseconds
-fun TransitionBuilder.shadeToQuickSettingsTransition(
- durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.shadeToQuickSettingsTransition(durationScale: Double = 1.0) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
- distance =
- object : UserActionDistance {
- override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
- orientation: Orientation,
- ): Float {
- val distance =
- Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y
- ?: return 0f
- return fromSceneSize.height - distance
- }
- }
+ distance = UserActionDistance { fromContent, _, _ ->
+ val distance =
+ Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y
+ ?: return@UserActionDistance 0f
+ val fromContentSize = checkNotNull(fromContent.targetSize())
+ fromContentSize.height - distance
+ }
translate(Notifications.Elements.NotificationScrim, Edge.Bottom)
timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) }
translate(
ShadeHeader.Elements.CollapsedContentStart,
- y = ShadeHeader.Dimensions.CollapsedHeight
+ y = ShadeHeader.Dimensions.CollapsedHeight,
)
translate(ShadeHeader.Elements.CollapsedContentEnd, y = ShadeHeader.Dimensions.CollapsedHeight)
translate(
ShadeHeader.Elements.ExpandedContent,
- y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight)
+ y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight),
)
translate(ShadeHeader.Elements.ShadeCarrierGroup, y = -ShadeHeader.Dimensions.CollapsedHeight)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt
index de76f708c1c7..d35537a74c85 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt
@@ -28,8 +28,9 @@ private const val TO_BOUNCER_SWIPE_DISTANCE_FRACTION = 0.5f
fun TransitionBuilder.toBouncerTransition() {
spec = tween(durationMillis = 500)
- distance = UserActionDistance { fromSceneSize, _ ->
- fromSceneSize.height * TO_BOUNCER_SWIPE_DISTANCE_FRACTION
+ distance = UserActionDistance { fromContent, _, _ ->
+ val fromContentSize = checkNotNull(fromContent.targetSize())
+ fromContentSize.height * TO_BOUNCER_SWIPE_DISTANCE_FRACTION
}
translate(Bouncer.Elements.Content, y = 300.dp)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
index 55fa6ad94ed3..e78bc6afcc4f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
@@ -33,7 +33,10 @@ fun TransitionBuilder.toQuickSettingsShadeTransition(durationScale: Double = 1.0
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
)
- distance = UserActionDistance { fromSceneSize, _ -> fromSceneSize.height.toFloat() * 2 / 3f }
+ distance = UserActionDistance { fromContent, _, _ ->
+ val fromContentSize = checkNotNull(fromContent.targetSize())
+ fromContentSize.height.toFloat() * 2 / 3f
+ }
translate(OverlayShade.Elements.Panel, Edge.Top)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
index b677dff2dcf9..bfae4897dc68 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
@@ -19,12 +19,9 @@ package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
@@ -33,24 +30,16 @@ import com.android.systemui.shade.ui.composable.Shade
import com.android.systemui.shade.ui.composable.ShadeHeader
import kotlin.time.Duration.Companion.milliseconds
-fun TransitionBuilder.toShadeTransition(
- durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.toShadeTransition(durationScale: Double = 1.0) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
swipeSpec =
spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
)
- distance =
- object : UserActionDistance {
- override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
- orientation: Orientation,
- ): Float {
- return Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y ?: 0f
- }
- }
+ distance = UserActionDistance { _, _, _ ->
+ Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y ?: 0f
+ }
fractionRange(start = .58f) {
fade(ShadeHeader.Elements.Clock)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 05a0119d68e4..bfcde7dab6d2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -130,10 +130,6 @@ fun SceneScope.CollapsedShadeHeader(
modifier: Modifier = Modifier,
) {
val viewModel = rememberViewModel("CollapsedShadeHeader") { viewModelFactory.create() }
- val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
- if (isDisabled) {
- return
- }
val cutoutWidth = LocalDisplayCutout.current.width()
val cutoutHeight = LocalDisplayCutout.current.height()
@@ -196,7 +192,7 @@ fun SceneScope.CollapsedShadeHeader(
horizontalArrangement = Arrangement.End,
modifier =
Modifier.element(ShadeHeader.Elements.CollapsedContentEnd)
- .padding(horizontal = horizontalPadding)
+ .padding(horizontal = horizontalPadding),
) {
if (isLargeScreenLayout) {
ShadeCarrierGroup(
@@ -207,7 +203,7 @@ fun SceneScope.CollapsedShadeHeader(
SystemIconContainer(
viewModel = viewModel,
isClickable = isLargeScreenLayout,
- modifier = Modifier.align(Alignment.CenterVertically)
+ modifier = Modifier.align(Alignment.CenterVertically),
) {
StatusIcons(
viewModel = viewModel,
@@ -217,7 +213,7 @@ fun SceneScope.CollapsedShadeHeader(
modifier =
Modifier.align(Alignment.CenterVertically)
.padding(end = 6.dp)
- .weight(1f, fill = false)
+ .weight(1f, fill = false),
)
BatteryIcon(
createBatteryMeterViewController =
@@ -252,27 +248,15 @@ fun SceneScope.CollapsedShadeHeader(
CutoutLocation.NONE,
CutoutLocation.RIGHT -> {
startPlaceable.placeRelative(x = 0, y = 0)
- endPlaceable.placeRelative(
- x = startPlaceable.width,
- y = 0,
- )
+ endPlaceable.placeRelative(x = startPlaceable.width, y = 0)
}
CutoutLocation.CENTER -> {
startPlaceable.placeRelative(x = 0, y = 0)
- endPlaceable.placeRelative(
- x = startPlaceable.width + cutoutWidthPx,
- y = 0,
- )
+ endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0)
}
CutoutLocation.LEFT -> {
- startPlaceable.placeRelative(
- x = cutoutWidthPx,
- y = 0,
- )
- endPlaceable.placeRelative(
- x = startPlaceable.width + cutoutWidthPx,
- y = 0,
- )
+ startPlaceable.placeRelative(x = cutoutWidthPx, y = 0)
+ endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0)
}
}
}
@@ -288,10 +272,6 @@ fun SceneScope.ExpandedShadeHeader(
modifier: Modifier = Modifier,
) {
val viewModel = rememberViewModel("ExpandedShadeHeader") { viewModelFactory.create() }
- val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
- if (isDisabled) {
- return
- }
val useExpandedFormat by remember {
derivedStateOf { shouldUseExpandedFormat(layoutState.transitionState) }
@@ -302,17 +282,14 @@ fun SceneScope.ExpandedShadeHeader(
Box(modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root)) {
if (isPrivacyChipVisible) {
Box(modifier = Modifier.height(CollapsedHeight).fillMaxWidth()) {
- PrivacyChip(
- viewModel = viewModel,
- modifier = Modifier.align(Alignment.CenterEnd),
- )
+ PrivacyChip(viewModel = viewModel, modifier = Modifier.align(Alignment.CenterEnd))
}
}
Column(
verticalArrangement = Arrangement.Bottom,
modifier =
Modifier.fillMaxWidth()
- .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight)
+ .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight),
) {
Box(modifier = Modifier.fillMaxWidth()) {
Box {
@@ -362,11 +339,7 @@ fun SceneScope.ExpandedShadeHeader(
}
@Composable
-private fun SceneScope.Clock(
- scale: Float,
- viewModel: ShadeHeaderViewModel,
- modifier: Modifier,
-) {
+private fun SceneScope.Clock(scale: Float, viewModel: ShadeHeaderViewModel, modifier: Modifier) {
val layoutDirection = LocalLayoutDirection.current
Element(key = ShadeHeader.Elements.Clock, modifier = modifier) {
@@ -391,10 +364,10 @@ private fun SceneScope.Clock(
LayoutDirection.Ltr -> 0f
LayoutDirection.Rtl -> 1f
},
- 0.5f
+ 0.5f,
)
}
- .clickable { viewModel.onClockClicked() }
+ .clickable { viewModel.onClockClicked() },
)
}
}
@@ -447,10 +420,7 @@ private fun BatteryIcon(
}
@Composable
-private fun ShadeCarrierGroup(
- viewModel: ShadeHeaderViewModel,
- modifier: Modifier = Modifier,
-) {
+private fun ShadeCarrierGroup(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) {
Row(modifier = modifier) {
val subIds by viewModel.mobileSubIds.collectAsStateWithLifecycle()
@@ -465,11 +435,11 @@ private fun ShadeCarrierGroup(
viewModel =
(viewModel.mobileIconsViewModel.viewModelForSub(
subId,
- StatusBarLocation.SHADE_CARRIER_GROUP
+ StatusBarLocation.SHADE_CARRIER_GROUP,
) as ShadeCarrierGroupMobileIconViewModel),
)
.also { it.setOnClickListener { viewModel.onShadeCarrierGroupClicked() } }
- },
+ }
)
}
}
@@ -506,7 +476,7 @@ private fun SceneScope.StatusIcons(
Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary),
Utils.getColorAttrDefaultColor(
themedContext,
- android.R.attr.textColorPrimaryInverse
+ android.R.attr.textColorPrimaryInverse,
),
)
statusBarIconController.addIconGroup(iconManager)
@@ -551,7 +521,7 @@ private fun SystemIconContainer(
viewModel: ShadeHeaderViewModel,
isClickable: Boolean,
modifier: Modifier = Modifier,
- content: @Composable RowScope.() -> Unit
+ content: @Composable RowScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
val isHovered by interactionSource.collectIsHoveredAsState()
@@ -578,10 +548,7 @@ private fun SystemIconContainer(
}
@Composable
-private fun SceneScope.PrivacyChip(
- viewModel: ShadeHeaderViewModel,
- modifier: Modifier = Modifier,
-) {
+private fun SceneScope.PrivacyChip(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) {
val privacyList by viewModel.privacyItems.collectAsStateWithLifecycle()
AndroidView(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index bba3d69ea77f..fd1632ed4cb4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -353,13 +353,24 @@ private fun SceneScope.SingleShade(
)
}
+ val qqsLayoutPaddingBottom =
+ dimensionResource(id = R.dimen.qqs_layout_padding_bottom)
ShadeMediaCarousel(
isVisible = isMediaVisible,
isInRow = mediaInRow,
mediaHost = mediaHost,
mediaOffsetProvider = mediaOffsetProvider,
carouselController = mediaCarouselController,
- modifier = Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media),
+ modifier =
+ Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media)
+ .padding(
+ horizontal =
+ shadeHorizontalPadding +
+ dimensionResource(id = R.dimen.qs_horizontal_margin)
+ )
+ .thenIf(!mediaInRow) {
+ Modifier.padding(bottom = qqsLayoutPaddingBottom)
+ },
usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia,
isInSplitShade = false,
)
@@ -562,10 +573,14 @@ private fun SceneScope.SplitShade(
mediaOffsetProvider = mediaOffsetProvider,
modifier =
Modifier.thenIf(
- MediaContentPicker.shouldElevateMedia(layoutState)
- ) {
- Modifier.zIndex(1f)
- },
+ MediaContentPicker.shouldElevateMedia(layoutState)
+ ) {
+ Modifier.zIndex(1f)
+ }
+ .padding(
+ horizontal =
+ dimensionResource(id = R.dimen.qs_horizontal_margin)
+ ),
carouselController = mediaCarouselController,
isInSplitShade = true,
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
index 352d29e21987..74896482be88 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
@@ -25,7 +25,6 @@ import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.offset
-import androidx.compose.ui.util.fastFirst
import androidx.compose.ui.util.fastFirstOrNull
import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy.LayoutId
import kotlin.math.max
@@ -60,18 +59,20 @@ class SingleShadeMeasurePolicy(
val shadeHeaderPlaceable =
measurables
- .fastFirst { it.layoutId == LayoutId.ShadeHeader }
- .measure(constraintsWithCutout)
+ .fastFirstOrNull { it.layoutId == LayoutId.ShadeHeader }
+ ?.measure(constraintsWithCutout)
val mediaPlaceable =
measurables
.fastFirstOrNull { it.layoutId == LayoutId.Media }
?.measure(applyMediaConstraints(constraintsWithCutout, isMediaInRow))
val quickSettingsPlaceable =
measurables
- .fastFirst { it.layoutId == LayoutId.QuickSettings }
- .measure(constraintsWithCutout)
+ .fastFirstOrNull { it.layoutId == LayoutId.QuickSettings }
+ ?.measure(constraintsWithCutout)
val notificationsPlaceable =
- measurables.fastFirst { it.layoutId == LayoutId.Notifications }.measure(constraints)
+ measurables
+ .fastFirstOrNull { it.layoutId == LayoutId.Notifications }
+ ?.measure(constraints)
val notificationsTop =
calculateNotificationsTop(
@@ -84,23 +85,25 @@ class SingleShadeMeasurePolicy(
onNotificationsTopChanged(notificationsTop)
return layout(constraints.maxWidth, constraints.maxHeight) {
- shadeHeaderPlaceable.placeRelative(x = insetsLeft, y = insetsTop)
- quickSettingsPlaceable.placeRelative(
+ shadeHeaderPlaceable?.placeRelative(x = insetsLeft, y = insetsTop)
+ val statusBarHeaderHeight = shadeHeaderPlaceable?.height ?: 0
+ quickSettingsPlaceable?.placeRelative(
x = insetsLeft,
- y = insetsTop + shadeHeaderPlaceable.height,
+ y = insetsTop + statusBarHeaderHeight,
)
- if (mediaPlaceable != null)
+ if (mediaPlaceable != null) {
+ val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0
+
if (isMediaInRow) {
// mediaPlaceable height ranges from 0 to qsHeight. We want it to be centered
// vertically when it's smaller than the QS
- val mediaCenteringOffset =
- (quickSettingsPlaceable.height - mediaPlaceable.height) / 2
+ val mediaCenteringOffset = (quickSettingsHeight - mediaPlaceable.height) / 2
mediaPlaceable.placeRelative(
x = insetsLeft + constraintsWithCutout.maxWidth / 2,
y =
insetsTop +
- shadeHeaderPlaceable.height +
+ statusBarHeaderHeight +
mediaCenteringOffset +
mediaOffset(),
zIndex = mediaZIndex(),
@@ -108,30 +111,34 @@ class SingleShadeMeasurePolicy(
} else {
mediaPlaceable.placeRelative(
x = insetsLeft,
- y = insetsTop + shadeHeaderPlaceable.height + quickSettingsPlaceable.height,
+ y = insetsTop + statusBarHeaderHeight + quickSettingsHeight,
zIndex = mediaZIndex(),
)
}
+ }
// Notifications don't need to accommodate for horizontal insets
- notificationsPlaceable.placeRelative(x = 0, y = notificationsTop)
+ notificationsPlaceable?.placeRelative(x = 0, y = notificationsTop)
}
}
private fun calculateNotificationsTop(
- statusBarHeaderPlaceable: Placeable,
- quickSettingsPlaceable: Placeable,
+ statusBarHeaderPlaceable: Placeable?,
+ quickSettingsPlaceable: Placeable?,
mediaPlaceable: Placeable?,
insetsTop: Int,
isMediaInRow: Boolean,
): Int {
val mediaHeight = mediaPlaceable?.height ?: 0
+ val statusBarHeaderHeight = statusBarHeaderPlaceable?.height ?: 0
+ val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0
+
return insetsTop +
- statusBarHeaderPlaceable.height +
+ statusBarHeaderHeight +
if (isMediaInRow) {
- max(quickSettingsPlaceable.height, mediaHeight)
+ max(quickSettingsHeight, mediaHeight)
} else {
- quickSettingsPlaceable.height + mediaHeight
+ quickSettingsHeight + mediaHeight
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
index 163f4b36f472..78e605601b76 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
@@ -307,6 +307,6 @@ private fun draggableTopPadding(): Dp {
private object DraggableBottomSheet {
val DefaultTopPadding = 64.dp
- val LargeScreenTopPadding = 72.dp
+ val LargeScreenTopPadding = 56.dp
val MaxWidth = 640.dp
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index c33d655fe52b..cf0ba5196bad 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -30,8 +30,7 @@ import com.android.compose.nestedscroll.OnStopScope
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
import com.android.compose.nestedscroll.ScrollController
import kotlin.math.absoluteValue
-
-internal typealias SuspendedValue<T> = suspend () -> T
+import kotlinx.coroutines.launch
internal interface DraggableHandler {
/**
@@ -50,6 +49,7 @@ internal interface DragController {
/**
* Drag the current scene by [delta] pixels.
*
+ * @param delta The distance to drag the scene in pixels.
* @return the consumed [delta]
*/
fun onDrag(delta: Float): Float
@@ -57,9 +57,18 @@ internal interface DragController {
/**
* Stop the current drag with the given [velocity].
*
+ * @param velocity The velocity of the drag when it stopped.
+ * @param canChangeContent Whether the content can be changed as a result of this drag.
* @return the consumed [velocity] when the animation complete
*/
- fun onStop(velocity: Float, canChangeContent: Boolean): SuspendedValue<Float>
+ suspend fun onStop(velocity: Float, canChangeContent: Boolean): Float
+
+ /**
+ * Cancels the current drag.
+ *
+ * @param canChangeContent Whether the content can be changed as a result of this drag.
+ */
+ fun onCancel(canChangeContent: Boolean)
}
internal class DraggableHandlerImpl(
@@ -350,7 +359,7 @@ private class DragControllerImpl(
val result = swipes.findUserActionResult(directionOffset = newOffset)
if (result == null) {
- onStop(velocity = delta, canChangeContent = true)
+ onCancel(canChangeContent = true)
return 0f
}
@@ -379,11 +388,11 @@ private class DragControllerImpl(
return consumedDelta
}
- override fun onStop(velocity: Float, canChangeContent: Boolean): SuspendedValue<Float> {
+ override suspend fun onStop(velocity: Float, canChangeContent: Boolean): Float {
return onStop(velocity, canChangeContent, swipeAnimation)
}
- private fun <T : ContentKey> onStop(
+ private suspend fun <T : ContentKey> onStop(
velocity: Float,
canChangeContent: Boolean,
@@ -392,24 +401,23 @@ private class DragControllerImpl(
// callbacks (like onAnimationCompleted()) might incorrectly finish a new transition that
// replaced this one.
swipeAnimation: SwipeAnimation<T>,
- ): SuspendedValue<Float> {
+ ): Float {
// The state was changed since the drag started; don't do anything.
if (!isDrivingTransition || swipeAnimation.isAnimatingOffset()) {
- return { 0f }
+ return 0f
}
val fromContent = swipeAnimation.fromContent
- val consumedVelocity: SuspendedValue<Float>
- if (canChangeContent) {
- // If we are halfway between two contents, we check what the target will be based on the
- // velocity and offset of the transition, then we launch the animation.
+ val targetContent =
+ if (canChangeContent) {
+ // If we are halfway between two contents, we check what the target will be based on
+ // the velocity and offset of the transition, then we launch the animation.
- val toContent = swipeAnimation.toContent
+ val toContent = swipeAnimation.toContent
- // Compute the destination content (and therefore offset) to settle in.
- val offset = swipeAnimation.dragOffset
- val distance = swipeAnimation.distance()
- val targetContent =
+ // Compute the destination content (and therefore offset) to settle in.
+ val offset = swipeAnimation.dragOffset
+ val distance = swipeAnimation.distance()
if (
distance != DistanceUnspecified &&
shouldCommitSwipe(
@@ -424,16 +432,15 @@ private class DragControllerImpl(
} else {
fromContent
}
- consumedVelocity = swipeAnimation.animateOffset(velocity, targetContent = targetContent)
- } else {
- // We are doing an overscroll preview animation between scenes.
- check(fromContent == swipeAnimation.currentContent) {
- "canChangeContent is false but currentContent != fromContent"
+ } else {
+ // We are doing an overscroll preview animation between scenes.
+ check(fromContent == swipeAnimation.currentContent) {
+ "canChangeContent is false but currentContent != fromContent"
+ }
+ fromContent
}
- consumedVelocity = swipeAnimation.animateOffset(velocity, targetContent = fromContent)
- }
- return consumedVelocity
+ return swipeAnimation.animateOffset(velocity, targetContent)
}
/**
@@ -478,6 +485,12 @@ private class DragControllerImpl(
isCloserToTarget()
}
}
+
+ override fun onCancel(canChangeContent: Boolean) {
+ swipeAnimation.contentTransition.coroutineScope.launch {
+ onStop(velocity = 0f, canChangeContent = canChangeContent)
+ }
+ }
}
/** The [Swipe] associated to a given fromScene, startedPosition and pointersDown. */
@@ -530,16 +543,12 @@ internal class Swipes(val upOrLeft: Swipe.Resolved, val downOrRight: Swipe.Resol
}
internal class NestedScrollHandlerImpl(
- private val layoutImpl: SceneTransitionLayoutImpl,
- private val orientation: Orientation,
+ private val draggableHandler: DraggableHandlerImpl,
internal var topOrLeftBehavior: NestedScrollBehavior,
internal var bottomOrRightBehavior: NestedScrollBehavior,
internal var isExternalOverscrollGesture: () -> Boolean,
private val pointersInfoOwner: PointersInfoOwner,
) {
- private val layoutState = layoutImpl.state
- private val draggableHandler = layoutImpl.draggableHandler(orientation)
-
val connection: PriorityNestedScrollConnection = nestedScrollConnection()
private fun nestedScrollConnection(): PriorityNestedScrollConnection {
@@ -550,13 +559,15 @@ internal class NestedScrollHandlerImpl(
var lastPointersDown: PointersInfo.PointersDown? = null
fun shouldEnableSwipes(): Boolean {
- return layoutImpl.contentForUserActions().shouldEnableSwipes(orientation)
+ return draggableHandler.layoutImpl
+ .contentForUserActions()
+ .shouldEnableSwipes(draggableHandler.orientation)
}
var isIntercepting = false
return PriorityNestedScrollConnection(
- orientation = orientation,
+ orientation = draggableHandler.orientation,
canStartPreScroll = { offsetAvailable, offsetBeforeStart, _ ->
val pointersDown: PointersInfo.PointersDown? =
when (val info = pointersInfoOwner.pointersInfo()) {
@@ -578,8 +589,9 @@ internal class NestedScrollHandlerImpl(
draggableHandler.shouldImmediatelyIntercept(pointersDown)
if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
+ val layoutImpl = draggableHandler.layoutImpl
val threshold = layoutImpl.transitionInterceptionThreshold
- val hasSnappedToIdle = layoutState.snapToIdleIfClose(threshold)
+ val hasSnappedToIdle = layoutImpl.state.snapToIdleIfClose(threshold)
if (hasSnappedToIdle) {
// If the current swipe transition is closed to 0f or 1f, then we want to
// interrupt the transition (snapping it to Idle) and scroll the list.
@@ -702,13 +714,14 @@ private fun scrollController(
}
override suspend fun OnStopScope.onStop(initialVelocity: Float): Float {
- return dragController
- .onStop(velocity = initialVelocity, canChangeContent = canChangeScene)
- .invoke()
+ return dragController.onStop(
+ velocity = initialVelocity,
+ canChangeContent = canChangeScene,
+ )
}
override fun onCancel() {
- dragController.onStop(velocity = 0f, canChangeContent = canChangeScene)
+ dragController.onCancel(canChangeScene)
}
/**
@@ -732,5 +745,9 @@ internal const val OffsetVisibilityThreshold = 0.5f
private object NoOpDragController : DragController {
override fun onDrag(delta: Float) = 0f
- override fun onStop(velocity: Float, canChangeContent: Boolean) = suspend { 0f }
+ override suspend fun onStop(velocity: Float, canChangeContent: Boolean) = 0f
+
+ override fun onCancel(canChangeContent: Boolean) {
+ /* do nothing */
+ }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index d976e8e62f3c..eb2a01632095 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -50,6 +50,8 @@ import androidx.compose.ui.util.fastForEachReversed
import androidx.compose.ui.util.lerp
import com.android.compose.animation.scene.content.Content
import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
+import com.android.compose.animation.scene.transformation.InterpolatedPropertyTransformation
import com.android.compose.animation.scene.transformation.PropertyTransformation
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import com.android.compose.animation.scene.transformation.TransformationWithRange
@@ -348,8 +350,7 @@ internal class ElementNode(
val placeInThisContent =
elementContentWhenIdle(
layoutImpl,
- currentState.currentScene,
- currentState.currentOverlays,
+ currentState,
isInContent = { it in element.stateByContent },
) == content.key
@@ -637,20 +638,11 @@ internal inline fun elementState(
internal inline fun elementContentWhenIdle(
layoutImpl: SceneTransitionLayoutImpl,
- idle: TransitionState.Idle,
- isInContent: (ContentKey) -> Boolean,
-): ContentKey {
- val currentScene = idle.currentScene
- val overlays = idle.currentOverlays
- return elementContentWhenIdle(layoutImpl, currentScene, overlays, isInContent)
-}
-
-private inline fun elementContentWhenIdle(
- layoutImpl: SceneTransitionLayoutImpl,
- currentScene: SceneKey,
- overlays: Set<OverlayKey>,
+ currentState: TransitionState,
isInContent: (ContentKey) -> Boolean,
): ContentKey {
+ val currentScene = currentState.currentScene
+ val overlays = currentState.currentOverlays
if (overlays.isEmpty()) {
return currentScene
}
@@ -1308,7 +1300,14 @@ private inline fun <T> computeValue(
checkNotNull(if (currentContent == toContent) toState else fromState)
val idleValue = contentValue(overscrollState)
val targetValue =
- with(propertySpec.transformation) {
+ with(
+ propertySpec.transformation.requireInterpolatedTransformation(
+ element,
+ transition,
+ ) {
+ "Custom transformations in overscroll specs should not be possible"
+ }
+ ) {
layoutImpl.propertyTransformationScope.transform(
currentContent,
element.key,
@@ -1390,7 +1389,7 @@ private inline fun <T> computeValue(
// fromContent or toContent during interruptions.
val content = contentState.content
- val transformation =
+ val transformationWithRange =
transformation(transition.transformationSpec.transformations(element.key, content))
val previewTransformation =
@@ -1403,7 +1402,14 @@ private inline fun <T> computeValue(
val idleValue = contentValue(contentState)
val isEntering = content == toContent
val previewTargetValue =
- with(previewTransformation.transformation) {
+ with(
+ previewTransformation.transformation.requireInterpolatedTransformation(
+ element,
+ transition,
+ ) {
+ "Custom transformations in preview specs should not be possible"
+ }
+ ) {
layoutImpl.propertyTransformationScope.transform(
content,
element.key,
@@ -1413,8 +1419,15 @@ private inline fun <T> computeValue(
}
val targetValueOrNull =
- transformation?.let { transformation ->
- with(transformation.transformation) {
+ transformationWithRange?.let { transformation ->
+ with(
+ transformation.transformation.requireInterpolatedTransformation(
+ element,
+ transition,
+ ) {
+ "Custom transformations are not allowed for properties with a preview"
+ }
+ ) {
layoutImpl.propertyTransformationScope.transform(
content,
element.key,
@@ -1461,7 +1474,7 @@ private inline fun <T> computeValue(
lerp(
lerp(previewTargetValue, targetValueOrNull ?: idleValue, previewRangeProgress),
idleValue,
- transformation?.range?.progress(transition.progress) ?: transition.progress,
+ transformationWithRange?.range?.progress(transition.progress) ?: transition.progress,
)
} else {
if (targetValueOrNull == null) {
@@ -1474,22 +1487,39 @@ private inline fun <T> computeValue(
lerp(
lerp(idleValue, previewTargetValue, previewRangeProgress),
targetValueOrNull,
- transformation.range?.progress(transition.progress) ?: transition.progress,
+ transformationWithRange.range?.progress(transition.progress)
+ ?: transition.progress,
)
}
}
}
- if (transformation == null) {
+ if (transformationWithRange == null) {
// If there is no transformation explicitly associated to this element value, let's use
// the value given by the system (like the current position and size given by the layout
// pass).
return currentValue()
}
+ val transformation = transformationWithRange.transformation
+ when (transformation) {
+ is CustomPropertyTransformation ->
+ return with(transformation) {
+ layoutImpl.propertyTransformationScope.transform(
+ content,
+ element.key,
+ transition,
+ transition.coroutineScope,
+ )
+ }
+ is InterpolatedPropertyTransformation -> {
+ /* continue */
+ }
+ }
+
val idleValue = contentValue(contentState)
val targetValue =
- with(transformation.transformation) {
+ with(transformation) {
layoutImpl.propertyTransformationScope.transform(
content,
element.key,
@@ -1506,7 +1536,7 @@ private inline fun <T> computeValue(
val progress = transition.progress
// TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
- val rangeProgress = transformation.range?.progress(progress) ?: progress
+ val rangeProgress = transformationWithRange.range?.progress(progress) ?: progress
// Interpolate between the value at rest and the value before entering/after leaving.
val isEntering =
@@ -1523,6 +1553,22 @@ private inline fun <T> computeValue(
}
}
+private inline fun <T> PropertyTransformation<T>.requireInterpolatedTransformation(
+ element: Element,
+ transition: TransitionState.Transition,
+ errorMessage: () -> String,
+): InterpolatedPropertyTransformation<T> {
+ return when (this) {
+ is InterpolatedPropertyTransformation -> this
+ is CustomPropertyTransformation -> {
+ val elem = element.key.debugName
+ val fromContent = transition.fromContent
+ val toContent = transition.toContent
+ error("${errorMessage()} (element=$elem fromContent=$fromContent toContent=$toContent)")
+ }
+ }
+}
+
private inline fun <T> interpolateSharedElement(
transition: TransitionState.Transition,
contentValue: (Element.State) -> T,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index c790ff03aef1..509a16c5a704 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -188,7 +188,9 @@ private fun shouldComposeMovableElement(
return when (
val elementState = movableElementState(element, layoutImpl.state.transitionStates)
) {
- null -> false
+ null ->
+ movableElementContentWhenIdle(layoutImpl, element, layoutImpl.state.transitionState) ==
+ content
is TransitionState.Idle ->
movableElementContentWhenIdle(layoutImpl, element, elementState) == content
is TransitionState.Transition -> {
@@ -217,7 +219,7 @@ private fun movableElementState(
private fun movableElementContentWhenIdle(
layoutImpl: SceneTransitionLayoutImpl,
element: MovableElementKey,
- elementState: TransitionState.Idle,
+ elementState: TransitionState,
): ContentKey {
val contents = element.contentPicker.contents
return elementContentWhenIdle(layoutImpl, elementState, isInContent = { contents.contains(it) })
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 160326792f81..59ac68bd0299 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -318,17 +318,13 @@ internal class MultiPointerDraggableNode(
velocityTracker.calculateVelocity(maxVelocity)
}
.toFloat(),
- onFling = {
- controller.onStop(it, canChangeContent = true).invoke()
- },
+ onFling = { controller.onStop(it, canChangeContent = true) },
)
},
onDragCancel = { controller ->
startFlingGesture(
initialVelocity = 0f,
- onFling = {
- controller.onStop(it, canChangeContent = true).invoke()
- },
+ onFling = { controller.onStop(it, canChangeContent = true) },
)
},
swipeDetector = swipeDetector,
@@ -519,8 +515,19 @@ internal class MultiPointerDraggableNode(
// we intercept an ongoing swipe transition (i.e. startDragImmediately() returned
// true).
if (overSlop == 0f) {
- val delta = (drag.position - consumablePointer.position).toFloat()
- check(delta != 0f) { "delta is equal to 0" }
+ // If the user drags in the opposite direction, the delta becomes zero because
+ // we return to the original point. Therefore, we should use the previous event
+ // to calculate the direction.
+ val delta = (drag.position - drag.previousPosition).toFloat()
+ check(delta != 0f) {
+ buildString {
+ append("delta is equal to 0 ")
+ append("touchSlop ${currentValueOf(LocalViewConfiguration).touchSlop} ")
+ append("consumablePointer.position ${consumablePointer.position} ")
+ append("drag.position ${drag.position} ")
+ append("drag.previousPosition ${drag.previousPosition}")
+ }
+ }
overSlop = delta.sign
}
drag
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index fbd1cd542c05..955be603efaf 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -16,7 +16,6 @@
package com.android.compose.animation.scene
-import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
@@ -69,32 +68,28 @@ enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
}
internal fun Modifier.nestedScrollToScene(
- layoutImpl: SceneTransitionLayoutImpl,
- orientation: Orientation,
+ draggableHandler: DraggableHandlerImpl,
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
isExternalOverscrollGesture: () -> Boolean,
) =
this then
NestedScrollToSceneElement(
- layoutImpl = layoutImpl,
- orientation = orientation,
+ draggableHandler = draggableHandler,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
)
private data class NestedScrollToSceneElement(
- private val layoutImpl: SceneTransitionLayoutImpl,
- private val orientation: Orientation,
+ private val draggableHandler: DraggableHandlerImpl,
private val topOrLeftBehavior: NestedScrollBehavior,
private val bottomOrRightBehavior: NestedScrollBehavior,
private val isExternalOverscrollGesture: () -> Boolean,
) : ModifierNodeElement<NestedScrollToSceneNode>() {
override fun create() =
NestedScrollToSceneNode(
- layoutImpl = layoutImpl,
- orientation = orientation,
+ draggableHandler = draggableHandler,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
@@ -102,8 +97,7 @@ private data class NestedScrollToSceneElement(
override fun update(node: NestedScrollToSceneNode) {
node.update(
- layoutImpl = layoutImpl,
- orientation = orientation,
+ draggableHandler = draggableHandler,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
@@ -112,16 +106,14 @@ private data class NestedScrollToSceneElement(
override fun InspectorInfo.inspectableProperties() {
name = "nestedScrollToScene"
- properties["layoutImpl"] = layoutImpl
- properties["orientation"] = orientation
+ properties["draggableHandler"] = draggableHandler
properties["topOrLeftBehavior"] = topOrLeftBehavior
properties["bottomOrRightBehavior"] = bottomOrRightBehavior
}
}
private class NestedScrollToSceneNode(
- private var layoutImpl: SceneTransitionLayoutImpl,
- private var orientation: Orientation,
+ private var draggableHandler: DraggableHandlerImpl,
private var topOrLeftBehavior: NestedScrollBehavior,
private var bottomOrRightBehavior: NestedScrollBehavior,
private var isExternalOverscrollGesture: () -> Boolean,
@@ -129,12 +121,8 @@ private class NestedScrollToSceneNode(
private var scrollBehaviorOwner: ScrollBehaviorOwner? = null
private fun findScrollBehaviorOwner(): ScrollBehaviorOwner? {
- var behaviorOwner = scrollBehaviorOwner
- if (behaviorOwner == null) {
- behaviorOwner = findScrollBehaviorOwner(layoutImpl.draggableHandler(orientation))
- scrollBehaviorOwner = behaviorOwner
- }
- return behaviorOwner
+ return scrollBehaviorOwner
+ ?: findScrollBehaviorOwner(draggableHandler).also { scrollBehaviorOwner = it }
}
private val updateScrollBehaviorsConnection =
@@ -177,14 +165,12 @@ private class NestedScrollToSceneNode(
}
fun update(
- layoutImpl: SceneTransitionLayoutImpl,
- orientation: Orientation,
+ draggableHandler: DraggableHandlerImpl,
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
isExternalOverscrollGesture: () -> Boolean,
) {
- this.layoutImpl = layoutImpl
- this.orientation = orientation
+ this.draggableHandler = draggableHandler
this.topOrLeftBehavior = topOrLeftBehavior
this.bottomOrRightBehavior = bottomOrRightBehavior
this.isExternalOverscrollGesture = isExternalOverscrollGesture
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index dbf7d7b29834..d3ddb5003469 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -637,8 +637,8 @@ sealed class UserActionResult(
fun interface UserActionDistance {
/**
- * Return the **absolute** distance of the user action given the size of the scene we are
- * animating from and the [orientation].
+ * Return the **absolute** distance of the user action when going from [fromContent] to
+ * [toContent] in the given [orientation].
*
* Note: This function will be called for each drag event until it returns a value > 0f. This
* for instance allows you to return 0f or a negative value until the first layout pass of a
@@ -646,7 +646,8 @@ fun interface UserActionDistance {
* transitioning to when computing this absolute distance.
*/
fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
+ fromContent: ContentKey,
+ toContent: ContentKey,
orientation: Orientation,
): Float
}
@@ -656,7 +657,8 @@ interface UserActionDistanceScope : Density, ElementStateScope
/** The user action has a fixed [absoluteDistance]. */
class FixedDistance(private val distance: Dp) : UserActionDistance {
override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
+ fromContent: ContentKey,
+ toContent: ContentKey,
orientation: Orientation,
): Float = distance.toPx()
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index e93cf8f714cd..b916b0b45e41 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -125,8 +125,8 @@ internal class SceneTransitionLayoutImpl(
}
// TODO(b/317958526): Lazily allocate scene gesture handlers the first time they are needed.
- private val horizontalDraggableHandler: DraggableHandlerImpl
- private val verticalDraggableHandler: DraggableHandlerImpl
+ internal val horizontalDraggableHandler: DraggableHandlerImpl
+ internal val verticalDraggableHandler: DraggableHandlerImpl
internal val elementStateScope = ElementStateScopeImpl(this)
internal val propertyTransformationScope = PropertyTransformationScopeImpl(this)
@@ -163,12 +163,6 @@ internal class SceneTransitionLayoutImpl(
state.checkThread()
}
- internal fun draggableHandler(orientation: Orientation): DraggableHandlerImpl =
- when (orientation) {
- Orientation.Vertical -> verticalDraggableHandler
- Orientation.Horizontal -> horizontalDraggableHandler
- }
-
internal fun scene(key: SceneKey): Scene {
return scenes[key] ?: error("Scene $key is not configured")
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 72b29ee8848a..4bccac1e3ba0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -32,6 +32,7 @@ import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
/**
@@ -266,11 +267,12 @@ internal class MutableSceneTransitionLayoutStateImpl(
private set
/**
- * The flattened list of [SharedElementTransformation] within all the transitions in
+ * The flattened list of [SharedElementTransformation.Factory] within all the transitions in
* [transitionStates].
*/
- private val transformationsWithElevation: List<SharedElementTransformation> by derivedStateOf {
- transformationsWithElevation(transitionStates)
+ private val transformationFactoriesWithElevation:
+ List<SharedElementTransformation.Factory> by derivedStateOf {
+ transformationFactoriesWithElevation(transitionStates)
}
override val currentScene: SceneKey
@@ -352,8 +354,15 @@ internal class MutableSceneTransitionLayoutStateImpl(
}
override suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean) {
+ Log.i(TAG, "startTransition(transition=$transition, chain=$chain)")
checkThread()
+ // Prepare the transition before starting it. This is outside of the try/finally block on
+ // purpose because preparing a transition might throw an exception (e.g. if we find multiple
+ // specs matching this transition), in which case we want to throw that exception here
+ // before even starting the transition.
+ prepareTransitionBeforeStarting(transition)
+
try {
// Start the transition.
startTransitionInternal(transition, chain)
@@ -365,7 +374,7 @@ internal class MutableSceneTransitionLayoutStateImpl(
}
}
- private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) {
+ private fun prepareTransitionBeforeStarting(transition: TransitionState.Transition) {
// Set the current scene and overlays on the transition.
val currentState = transitionState
transition.currentSceneWhenTransitionStarted = currentState.currentScene
@@ -393,7 +402,9 @@ internal class MutableSceneTransitionLayoutStateImpl(
} else {
transition.updateOverscrollSpecs(fromSpec = null, toSpec = null)
}
+ }
+ private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) {
when (val currentState = transitionStates.last()) {
is TransitionState.Idle -> {
// Replace [Idle] by [transition].
@@ -419,14 +430,6 @@ internal class MutableSceneTransitionLayoutStateImpl(
check(transitionStates.size == 1)
check(transitionStates[0] is TransitionState.Idle)
transitionStates = listOf(transition)
- } else if (currentState == transition.replacedTransition) {
- // Replace the transition.
- transitionStates =
- transitionStates.subList(0, transitionStates.lastIndex) + transition
-
- // Make sure it is removed from the finishedTransitions set if it was already
- // finished.
- finishedTransitions.remove(currentState)
} else {
// Append the new transition.
transitionStates = transitionStates + transition
@@ -466,9 +469,9 @@ internal class MutableSceneTransitionLayoutStateImpl(
return
}
- // Make sure that this transition settles in case it was force finished, for instance by
- // calling snapToScene().
- transition.freezeAndAnimateToCurrentState()
+ // Make sure that this transition is cancelled in case it was force finished, for instance
+ // if snapToScene() is called.
+ transition.coroutineScope.cancel()
val transitionStates = this.transitionStates
if (!transitionStates.contains(transition)) {
@@ -476,6 +479,7 @@ internal class MutableSceneTransitionLayoutStateImpl(
return
}
+ Log.i(TAG, "finishTransition(transition=$transition)")
check(transitionStates.fastAll { it is TransitionState.Transition })
// Mark this transition as finished.
@@ -503,13 +507,10 @@ internal class MutableSceneTransitionLayoutStateImpl(
// If all transitions are finished, we are idle.
if (i == nStates) {
check(finishedTransitions.isEmpty())
- this.transitionStates =
- listOf(
- TransitionState.Idle(
- lastTransition.currentScene,
- lastTransition.currentOverlays,
- )
- )
+ val idle =
+ TransitionState.Idle(lastTransition.currentScene, lastTransition.currentOverlays)
+ Log.i(TAG, "all transitions finished. idle=$idle")
+ this.transitionStates = listOf(idle)
} else if (i > 0) {
this.transitionStates = transitionStates.subList(fromIndex = i, toIndex = nStates)
}
@@ -550,8 +551,8 @@ internal class MutableSceneTransitionLayoutStateImpl(
}
val shouldSnap =
- (isProgressCloseTo(0f) && transition.currentScene == transition.fromContent) ||
- (isProgressCloseTo(1f) && transition.currentScene == transition.toContent)
+ (isProgressCloseTo(0f) && transition.isFromCurrentContent()) ||
+ (isProgressCloseTo(1f) && transition.isToCurrentContent())
return if (shouldSnap) {
finishAllTransitions()
true
@@ -691,22 +692,23 @@ internal class MutableSceneTransitionLayoutStateImpl(
animate()
}
- private fun transformationsWithElevation(
+ private fun transformationFactoriesWithElevation(
transitionStates: List<TransitionState>
- ): List<SharedElementTransformation> {
+ ): List<SharedElementTransformation.Factory> {
return buildList {
transitionStates.fastForEach { state ->
if (state !is TransitionState.Transition) {
return@fastForEach
}
- state.transformationSpec.transformations.fastForEach { transformationWithRange ->
- val transformation = transformationWithRange.transformation
+ state.transformationSpec.transformationMatchers.fastForEach { transformationMatcher
+ ->
+ val factory = transformationMatcher.factory
if (
- transformation is SharedElementTransformation &&
- transformation.elevateInContent != null
+ factory is SharedElementTransformation.Factory &&
+ factory.elevateInContent != null
) {
- add(transformation)
+ add(factory)
}
}
}
@@ -721,10 +723,10 @@ internal class MutableSceneTransitionLayoutStateImpl(
* necessary, for performance.
*/
internal fun isElevationPossible(content: ContentKey, element: ElementKey?): Boolean {
- if (transformationsWithElevation.isEmpty()) return false
- return transformationsWithElevation.fastAny { transformation ->
- transformation.elevateInContent == content &&
- (element == null || transformation.matcher.matches(element, content))
+ if (transformationFactoriesWithElevation.isEmpty()) return false
+ return transformationFactoriesWithElevation.fastAny { factory ->
+ factory.elevateInContent == content &&
+ (element == null || factory.matcher.matches(element, content))
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index b083f79aebf5..8df3f2d932b3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -26,18 +26,10 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
import com.android.compose.animation.scene.content.state.TransitionState
-import com.android.compose.animation.scene.transformation.AnchoredSize
-import com.android.compose.animation.scene.transformation.AnchoredTranslate
-import com.android.compose.animation.scene.transformation.DrawScale
-import com.android.compose.animation.scene.transformation.EdgeTranslate
-import com.android.compose.animation.scene.transformation.Fade
-import com.android.compose.animation.scene.transformation.OverscrollTranslate
import com.android.compose.animation.scene.transformation.PropertyTransformation
-import com.android.compose.animation.scene.transformation.ScaleSize
import com.android.compose.animation.scene.transformation.SharedElementTransformation
-import com.android.compose.animation.scene.transformation.Transformation
+import com.android.compose.animation.scene.transformation.TransformationMatcher
import com.android.compose.animation.scene.transformation.TransformationWithRange
-import com.android.compose.animation.scene.transformation.Translate
/** The transitions configuration of a [SceneTransitionLayout]. */
class SceneTransitions
@@ -169,7 +161,7 @@ internal constructor(
}
/** The definition of a transition between [from] and [to]. */
-interface TransitionSpec {
+internal interface TransitionSpec {
/** The key of this [TransitionSpec]. */
val key: TransitionKey?
@@ -209,7 +201,7 @@ interface TransitionSpec {
fun previewTransformationSpec(transition: TransitionState.Transition): TransformationSpec?
}
-interface TransformationSpec {
+internal interface TransformationSpec {
/**
* The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
* the transition is triggered (i.e. it is not gesture-based).
@@ -232,8 +224,8 @@ interface TransformationSpec {
*/
val distance: UserActionDistance?
- /** The list of [Transformation] applied to elements during this transition. */
- val transformations: List<TransformationWithRange<*>>
+ /** The list of [TransformationMatcher] applied to elements during this transformation. */
+ val transformationMatchers: List<TransformationMatcher>
companion object {
internal val Empty =
@@ -241,7 +233,7 @@ interface TransformationSpec {
progressSpec = snap(),
swipeSpec = null,
distance = null,
- transformations = emptyList(),
+ transformationMatchers = emptyList(),
)
internal val EmptyProvider = { _: TransitionState.Transition -> Empty }
}
@@ -272,7 +264,14 @@ internal class TransitionSpecImpl(
progressSpec = reverse.progressSpec,
swipeSpec = reverse.swipeSpec,
distance = reverse.distance,
- transformations = reverse.transformations.map { it.reversed() },
+ transformationMatchers =
+ reverse.transformationMatchers.map {
+ TransformationMatcher(
+ matcher = it.matcher,
+ factory = it.factory,
+ range = it.range?.reversed(),
+ )
+ },
)
},
)
@@ -288,7 +287,7 @@ internal class TransitionSpecImpl(
}
/** The definition of the overscroll behavior of the [content]. */
-interface OverscrollSpec {
+internal interface OverscrollSpec {
/** The scene we are over scrolling. */
val content: ContentKey
@@ -325,7 +324,7 @@ internal class TransformationSpecImpl(
override val progressSpec: AnimationSpec<Float>,
override val swipeSpec: SpringSpec<Float>?,
override val distance: UserActionDistance?,
- override val transformations: List<TransformationWithRange<*>>,
+ override val transformationMatchers: List<TransformationMatcher>,
) : TransformationSpec {
private val cache = mutableMapOf<ElementKey, MutableMap<ContentKey, ElementTransformations>>()
@@ -335,7 +334,7 @@ internal class TransformationSpecImpl(
.getOrPut(content) { computeTransformations(element, content) }
}
- /** Filter [transformations] to compute the [ElementTransformations] of [element]. */
+ /** Filter [transformationMatchers] to compute the [ElementTransformations] of [element]. */
private fun computeTransformations(
element: ElementKey,
content: ContentKey,
@@ -346,48 +345,56 @@ internal class TransformationSpecImpl(
var drawScale: TransformationWithRange<PropertyTransformation<Scale>>? = null
var alpha: TransformationWithRange<PropertyTransformation<Float>>? = null
- transformations.fastForEach { transformationWithRange ->
- val transformation = transformationWithRange.transformation
- if (!transformation.matcher.matches(element, content)) {
+ transformationMatchers.fastForEach { transformationMatcher ->
+ if (!transformationMatcher.matcher.matches(element, content)) {
return@fastForEach
}
- when (transformation) {
- is SharedElementTransformation -> {
- throwIfNotNull(shared, element, name = "shared")
- shared =
- transformationWithRange
- as TransformationWithRange<SharedElementTransformation>
+ val transformation = transformationMatcher.factory.create()
+ val property =
+ when (transformation) {
+ is SharedElementTransformation -> {
+ throwIfNotNull(shared, element, name = "shared")
+ shared =
+ TransformationWithRange(transformation, transformationMatcher.range)
+ return@fastForEach
+ }
+ is PropertyTransformation<*> -> transformation.property
}
- is Translate,
- is OverscrollTranslate,
- is EdgeTranslate,
- is AnchoredTranslate -> {
+
+ when (property) {
+ is PropertyTransformation.Property.Offset -> {
throwIfNotNull(offset, element, name = "offset")
offset =
- transformationWithRange
- as TransformationWithRange<PropertyTransformation<Offset>>
+ TransformationWithRange(
+ transformation as PropertyTransformation<Offset>,
+ transformationMatcher.range,
+ )
}
- is ScaleSize,
- is AnchoredSize -> {
+ is PropertyTransformation.Property.Size -> {
throwIfNotNull(size, element, name = "size")
size =
- transformationWithRange
- as TransformationWithRange<PropertyTransformation<IntSize>>
+ TransformationWithRange(
+ transformation as PropertyTransformation<IntSize>,
+ transformationMatcher.range,
+ )
}
- is DrawScale -> {
+ is PropertyTransformation.Property.Scale -> {
throwIfNotNull(drawScale, element, name = "drawScale")
drawScale =
- transformationWithRange
- as TransformationWithRange<PropertyTransformation<Scale>>
+ TransformationWithRange(
+ transformation as PropertyTransformation<Scale>,
+ transformationMatcher.range,
+ )
}
- is Fade -> {
+ is PropertyTransformation.Property.Alpha -> {
throwIfNotNull(alpha, element, name = "alpha")
alpha =
- transformationWithRange
- as TransformationWithRange<PropertyTransformation<Float>>
+ TransformationWithRange(
+ transformation as PropertyTransformation<Float>,
+ transformationMatcher.range,
+ )
}
- else -> error("Unknown transformation: $transformation")
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
index f0043e1e89b0..ae235e5097af 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
@@ -24,11 +24,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
-import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified
import kotlin.math.absoluteValue
import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.launch
internal fun createSwipeAnimation(
layoutState: MutableSceneTransitionLayoutStateImpl,
@@ -66,8 +66,9 @@ internal fun createSwipeAnimation(
val absoluteDistance =
with(animation.contentTransition.transformationSpec.distance ?: DefaultSwipeDistance) {
layoutImpl.userActionDistanceScope.absoluteDistance(
- layoutImpl.content(animation.fromContent).targetSize,
- orientation,
+ fromContent = animation.fromContent,
+ toContent = animation.toContent,
+ orientation = orientation,
)
}
@@ -317,11 +318,11 @@ internal class SwipeAnimation<T : ContentKey>(
*
* @return the velocity consumed
*/
- fun animateOffset(
+ suspend fun animateOffset(
initialVelocity: Float,
targetContent: T,
spec: AnimationSpec<Float>? = null,
- ): SuspendedValue<Float> {
+ ): Float {
check(!isAnimatingOffset()) { "SwipeAnimation.animateOffset() can only be called once" }
val initialProgress = progress
@@ -379,7 +380,7 @@ internal class SwipeAnimation<T : ContentKey>(
if (skipAnimation) {
// Unblock the job.
offsetAnimationRunnable.complete(null)
- return { 0f }
+ return 0f
}
val isTargetGreater = targetOffset > animatable.value
@@ -440,7 +441,7 @@ internal class SwipeAnimation<T : ContentKey>(
}
}
- return { velocityConsumed.await() }
+ return velocityConsumed.await()
}
/** An exception thrown during the animation to stop it immediately. */
@@ -469,18 +470,22 @@ internal class SwipeAnimation<T : ContentKey>(
fun freezeAndAnimateToCurrentState() {
if (isAnimatingOffset()) return
- animateOffset(initialVelocity = 0f, targetContent = currentContent)
+ contentTransition.coroutineScope.launch {
+ animateOffset(initialVelocity = 0f, targetContent = currentContent)
+ }
}
}
private object DefaultSwipeDistance : UserActionDistance {
override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
+ fromContent: ContentKey,
+ toContent: ContentKey,
orientation: Orientation,
): Float {
+ val fromContentSize = checkNotNull(fromContent.targetSize())
return when (orientation) {
- Orientation.Horizontal -> fromSceneSize.width
- Orientation.Vertical -> fromSceneSize.height
+ Orientation.Horizontal -> fromContentSize.width
+ Orientation.Vertical -> fromContentSize.height
}.toFloat()
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index a448ee49d944..5ab306a63a7e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -165,8 +165,7 @@ private class SwipeToSceneNode(
private val nestedScrollHandlerImpl =
NestedScrollHandlerImpl(
- layoutImpl = draggableHandler.layoutImpl,
- orientation = draggableHandler.orientation,
+ draggableHandler = draggableHandler,
topOrLeftBehavior = NestedScrollBehavior.Default,
bottomOrRightBehavior = NestedScrollBehavior.Default,
isExternalOverscrollGesture = { false },
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index dc26b6b382b4..48f08a7086d6 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -26,6 +26,7 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.Transformation
import kotlin.math.tanh
/** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */
@@ -75,7 +76,7 @@ interface SceneTransitionsBuilder {
preview: (TransitionBuilder.() -> Unit)? = null,
reversePreview: (TransitionBuilder.() -> Unit)? = null,
builder: TransitionBuilder.() -> Unit = {},
- ): TransitionSpec
+ )
/**
* Define the animation to be played when transitioning [from] the specified content. For the
@@ -101,7 +102,7 @@ interface SceneTransitionsBuilder {
preview: (TransitionBuilder.() -> Unit)? = null,
reversePreview: (TransitionBuilder.() -> Unit)? = null,
builder: TransitionBuilder.() -> Unit = {},
- ): TransitionSpec
+ )
/**
* Define the animation to be played when the [content] is overscrolled in the given
@@ -114,13 +115,13 @@ interface SceneTransitionsBuilder {
content: ContentKey,
orientation: Orientation,
builder: OverscrollBuilder.() -> Unit,
- ): OverscrollSpec
+ )
/**
* Prevents overscroll the [content] in the given [orientation], allowing ancestors to
* eventually consume the remaining gesture.
*/
- fun overscrollDisabled(content: ContentKey, orientation: Orientation): OverscrollSpec
+ fun overscrollDisabled(content: ContentKey, orientation: Orientation)
}
interface BaseTransitionBuilder : PropertyTransformationBuilder {
@@ -527,6 +528,9 @@ interface PropertyTransformationBuilder {
anchorWidth: Boolean = true,
anchorHeight: Boolean = true,
)
+
+ /** Apply a [transformation] to the element(s) matching [matcher]. */
+ fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory)
}
/** This converter lets you change a linear progress into a function of your choice. */
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index e461f9ccc295..6742b3200ac4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -37,8 +37,8 @@ import com.android.compose.animation.scene.transformation.OverscrollTranslate
import com.android.compose.animation.scene.transformation.ScaleSize
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import com.android.compose.animation.scene.transformation.Transformation
+import com.android.compose.animation.scene.transformation.TransformationMatcher
import com.android.compose.animation.scene.transformation.TransformationRange
-import com.android.compose.animation.scene.transformation.TransformationWithRange
import com.android.compose.animation.scene.transformation.Translate
internal fun transitionsImpl(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions {
@@ -66,8 +66,8 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
preview: (TransitionBuilder.() -> Unit)?,
reversePreview: (TransitionBuilder.() -> Unit)?,
builder: TransitionBuilder.() -> Unit,
- ): TransitionSpec {
- return transition(from = null, to = to, key = key, preview, reversePreview, builder)
+ ) {
+ transition(from = null, to = to, key = key, preview, reversePreview, builder)
}
override fun from(
@@ -77,25 +77,25 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
preview: (TransitionBuilder.() -> Unit)?,
reversePreview: (TransitionBuilder.() -> Unit)?,
builder: TransitionBuilder.() -> Unit,
- ): TransitionSpec {
- return transition(from = from, to = to, key = key, preview, reversePreview, builder)
+ ) {
+ transition(from = from, to = to, key = key, preview, reversePreview, builder)
}
override fun overscroll(
content: ContentKey,
orientation: Orientation,
builder: OverscrollBuilder.() -> Unit,
- ): OverscrollSpec {
+ ) {
val impl = OverscrollBuilderImpl().apply(builder)
- check(impl.transformations.isNotEmpty()) {
+ check(impl.transformationMatchers.isNotEmpty()) {
"This method does not allow empty transformations. " +
"Use overscrollDisabled($content, $orientation) instead."
}
- return overscrollSpec(content, orientation, impl)
+ overscrollSpec(content, orientation, impl)
}
- override fun overscrollDisabled(content: ContentKey, orientation: Orientation): OverscrollSpec {
- return overscrollSpec(content, orientation, OverscrollBuilderImpl())
+ override fun overscrollDisabled(content: ContentKey, orientation: Orientation) {
+ overscrollSpec(content, orientation, OverscrollBuilderImpl())
}
private fun overscrollSpec(
@@ -112,7 +112,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
progressSpec = snap(),
swipeSpec = null,
distance = impl.distance,
- transformations = impl.transformations,
+ transformationMatchers = impl.transformationMatchers,
),
progressConverter = impl.progressConverter,
)
@@ -137,7 +137,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
progressSpec = impl.spec,
swipeSpec = impl.swipeSpec,
distance = impl.distance,
- transformations = impl.transformations,
+ transformationMatchers = impl.transformationMatchers,
)
}
@@ -157,7 +157,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
}
internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
- val transformations = mutableListOf<TransformationWithRange<*>>()
+ val transformationMatchers = mutableListOf<TransformationMatcher>()
private var range: TransformationRange? = null
protected var reversed = false
override var distance: UserActionDistance? = null
@@ -173,23 +173,31 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
range = null
}
- protected fun transformation(transformation: Transformation) {
- val transformationWithRange = TransformationWithRange(transformation, range)
- transformations.add(
- if (reversed) {
- transformationWithRange.reversed()
- } else {
- transformationWithRange
- }
+ protected fun addTransformation(
+ matcher: ElementMatcher,
+ transformation: Transformation.Factory,
+ ) {
+ transformationMatchers.add(
+ TransformationMatcher(
+ matcher,
+ transformation,
+ range?.let { range ->
+ if (reversed) {
+ range.reversed()
+ } else {
+ range
+ }
+ },
+ )
)
}
override fun fade(matcher: ElementMatcher) {
- transformation(Fade(matcher))
+ addTransformation(matcher, Fade.Factory)
}
override fun translate(matcher: ElementMatcher, x: Dp, y: Dp) {
- transformation(Translate(matcher, x, y))
+ addTransformation(matcher, Translate.Factory(x, y))
}
override fun translate(
@@ -197,19 +205,19 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
edge: Edge,
startsOutsideLayoutBounds: Boolean,
) {
- transformation(EdgeTranslate(matcher, edge, startsOutsideLayoutBounds))
+ addTransformation(matcher, EdgeTranslate.Factory(edge, startsOutsideLayoutBounds))
}
override fun anchoredTranslate(matcher: ElementMatcher, anchor: ElementKey) {
- transformation(AnchoredTranslate(matcher, anchor))
+ addTransformation(matcher, AnchoredTranslate.Factory(anchor))
}
override fun scaleSize(matcher: ElementMatcher, width: Float, height: Float) {
- transformation(ScaleSize(matcher, width, height))
+ addTransformation(matcher, ScaleSize.Factory(width, height))
}
override fun scaleDraw(matcher: ElementMatcher, scaleX: Float, scaleY: Float, pivot: Offset) {
- transformation(DrawScale(matcher, scaleX, scaleY, pivot))
+ addTransformation(matcher, DrawScale.Factory(scaleX, scaleY, pivot))
}
override fun anchoredSize(
@@ -218,7 +226,12 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
anchorWidth: Boolean,
anchorHeight: Boolean,
) {
- transformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight))
+ addTransformation(matcher, AnchoredSize.Factory(anchor, anchorWidth, anchorHeight))
+ }
+
+ override fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory) {
+ check(range == null) { "Custom transformations can not be applied inside a range" }
+ addTransformation(matcher, transformation)
}
}
@@ -257,7 +270,10 @@ internal class TransitionBuilderImpl(override val transition: TransitionState.Tr
"(${transition.toContent.debugName})"
}
- transformation(SharedElementTransformation(matcher, enabled, elevateInContent))
+ addTransformation(
+ matcher,
+ SharedElementTransformation.Factory(matcher, enabled, elevateInContent),
+ )
}
override fun timestampRange(
@@ -288,6 +304,6 @@ internal open class OverscrollBuilderImpl : BaseTransitionBuilderImpl(), Overscr
x: OverscrollScope.() -> Float,
y: OverscrollScope.() -> Float,
) {
- transformation(OverscrollTranslate(matcher, x, y))
+ addTransformation(matcher, OverscrollTranslate.Factory(x, y))
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 8187e3932975..255a16c6de6b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -16,7 +16,7 @@
package com.android.compose.animation.scene.content
-import androidx.compose.foundation.gestures.Orientation
+import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
@@ -72,6 +72,7 @@ internal sealed class Content(
var targetSize by mutableStateOf(IntSize.Zero)
var userActions by mutableStateOf(actions)
+ @SuppressLint("NotConstructor")
@Composable
fun Content(modifier: Modifier = Modifier) {
Box(
@@ -151,8 +152,7 @@ internal class ContentScopeImpl(
isExternalOverscrollGesture: () -> Boolean,
): Modifier {
return nestedScrollToScene(
- layoutImpl = layoutImpl,
- orientation = Orientation.Horizontal,
+ draggableHandler = layoutImpl.horizontalDraggableHandler,
topOrLeftBehavior = leftBehavior,
bottomOrRightBehavior = rightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
@@ -165,8 +165,7 @@ internal class ContentScopeImpl(
isExternalOverscrollGesture: () -> Boolean,
): Modifier {
return nestedScrollToScene(
- layoutImpl = layoutImpl,
- orientation = Orientation.Vertical,
+ draggableHandler = layoutImpl.verticalDraggableHandler,
topOrLeftBehavior = topBehavior,
bottomOrRightBehavior = bottomBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index e3118d67b434..d66fe42084de 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -35,6 +35,8 @@ import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransformationSpec
import com.android.compose.animation.scene.TransformationSpecImpl
import com.android.compose.animation.scene.TransitionKey
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
/** The state associated to a [SceneTransitionLayout] at some specific point in time. */
@@ -88,6 +90,10 @@ sealed interface TransitionState {
// The set of overlays does not change in a [ChangeCurrentScene] transition.
return currentOverlaysWhenTransitionStarted
}
+
+ override fun toString(): String {
+ return "ChangeScene(fromScene=$fromScene, toScene=$toScene)"
+ }
}
/**
@@ -128,7 +134,7 @@ sealed interface TransitionState {
* starting a swipe transition to show [overlay] and will be `true` only once the swipe
* transition is committed.
*/
- protected abstract val isEffectivelyShown: Boolean
+ abstract val isEffectivelyShown: Boolean
init {
check(
@@ -144,6 +150,12 @@ sealed interface TransitionState {
currentOverlaysWhenTransitionStarted - overlay
}
}
+
+ override fun toString(): String {
+ val isShowing = overlay == toContent
+ return "ShowOrHideOverlay(overlay=$overlay, fromOrToScene=$fromOrToScene, " +
+ "isShowing=$isShowing)"
+ }
}
/** We are transitioning from [fromOverlay] to [toOverlay]. */
@@ -163,7 +175,7 @@ sealed interface TransitionState {
* [fromOverlay] by [toOverlay] and will [toOverlay] once the swipe transition is
* committed.
*/
- protected abstract val effectivelyShownOverlay: OverlayKey
+ abstract val effectivelyShownOverlay: OverlayKey
init {
check(fromOverlay != toOverlay)
@@ -192,6 +204,10 @@ sealed interface TransitionState {
add(include)
}
}
+
+ override fun toString(): String {
+ return "ReplaceOverlay(fromOverlay=$fromOverlay, toOverlay=$toOverlay)"
+ }
}
/**
@@ -279,8 +295,24 @@ sealed interface TransitionState {
*/
private var interruptionDecay: Animatable<Float, AnimationVector1D>? = null
- /** Whether this transition was already started. */
- private var wasStarted = false
+ /**
+ * The coroutine scope associated to this transition.
+ *
+ * This coroutine scope can be used to launch animations associated to this transition,
+ * which will not finish until at least one animation/job is still running in the scope.
+ *
+ * Important: Make sure to never launch long-running jobs in this scope, otherwise the
+ * transition will never be considered as finished.
+ */
+ internal val coroutineScope: CoroutineScope
+ get() =
+ _coroutineScope
+ ?: error(
+ "Transition.coroutineScope can only be accessed once the transition was " +
+ "started "
+ )
+
+ private var _coroutineScope: CoroutineScope? = null
init {
check(fromContent != toContent)
@@ -326,6 +358,21 @@ sealed interface TransitionState {
}
}
+ /** Whether [fromContent] is effectively the current content of the transition. */
+ internal fun isFromCurrentContent() = isCurrentContent(expectedFrom = true)
+
+ /** Whether [toContent] is effectively the current content of the transition. */
+ internal fun isToCurrentContent() = isCurrentContent(expectedFrom = false)
+
+ private fun isCurrentContent(expectedFrom: Boolean): Boolean {
+ val expectedContent = if (expectedFrom) fromContent else toContent
+ return when (this) {
+ is ChangeScene -> currentScene == expectedContent
+ is ReplaceOverlay -> effectivelyShownOverlay == expectedContent
+ is ShowOrHideOverlay -> isEffectivelyShown == (expectedContent == overlay)
+ }
+ }
+
/** Run this transition and return once it is finished. */
protected abstract suspend fun run()
@@ -341,10 +388,11 @@ sealed interface TransitionState {
abstract fun freezeAndAnimateToCurrentState()
internal suspend fun runInternal() {
- check(!wasStarted) { "A Transition can be started only once." }
- wasStarted = true
-
- run()
+ check(_coroutineScope == null) { "A Transition can be started only once." }
+ coroutineScope {
+ _coroutineScope = this
+ run()
+ }
}
internal fun updateOverscrollSpecs(
@@ -367,7 +415,7 @@ sealed interface TransitionState {
else -> null
} ?: return true
- return specForCurrentScene.transformationSpec.transformations.isNotEmpty()
+ return specForCurrentScene.transformationSpec.transformationMatchers.isNotEmpty()
}
internal open fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
new file mode 100644
index 000000000000..bfb5ca733d90
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2024 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.compose.animation.scene.reveal
+
+import androidx.compose.animation.core.AnimationVector1D
+import androidx.compose.animation.core.DeferredTargetAnimation
+import androidx.compose.animation.core.ExperimentalAnimatableApi
+import androidx.compose.animation.core.FiniteAnimationSpec
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.spring
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastCoerceAtLeast
+import androidx.compose.ui.util.fastCoerceAtMost
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.OverlayKey
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.compose.animation.scene.UserActionDistance
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformationScope
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
+
+interface ContainerRevealHaptics {
+ /**
+ * Called when the reveal threshold is crossed while the user was dragging on screen.
+ *
+ * Important: This callback is called during layout and its implementation should therefore be
+ * very fast or posted to a different thread.
+ *
+ * @param revealed whether we go from hidden to revealed, i.e. whether the container size is
+ * going to jump from a smaller size to a bigger size.
+ */
+ fun onRevealThresholdCrossed(revealed: Boolean)
+}
+
+/** Animate the reveal of [container] by animating its size. */
+fun TransitionBuilder.verticalContainerReveal(
+ container: ElementKey,
+ haptics: ContainerRevealHaptics,
+) {
+ // Make the swipe distance be exactly the target height of the container.
+ // TODO(b/376438969): Make sure that this works correctly when the target size of the element
+ // is changing during the transition (e.g. a notification was added). At the moment, the user
+ // action distance is only called until it returns a value > 0f, which is then cached.
+ distance = UserActionDistance { fromContent, toContent, _ ->
+ val targetSizeInFromContent = container.targetSize(fromContent)
+ val targetSizeInToContent = container.targetSize(toContent)
+ if (targetSizeInFromContent != null && targetSizeInToContent != null) {
+ error(
+ "verticalContainerReveal should not be used with shared elements, but " +
+ "${container.debugName} is in both ${fromContent.debugName} and " +
+ toContent.debugName
+ )
+ }
+
+ (targetSizeInToContent?.height ?: targetSizeInFromContent?.height)?.toFloat() ?: 0f
+ }
+
+ // TODO(b/376438969): Improve the motion of this gesture using Motion Mechanics.
+
+ // The min distance to swipe before triggering the reveal spring.
+ val distanceThreshold = 80.dp
+
+ // The minimum height of the container.
+ val minHeight = 10.dp
+
+ // The amount removed from the container width at 0% progress.
+ val widthDelta = 140.dp
+
+ // The ratio at which the distance is tracked before reaching the threshold, e.g. if the user
+ // drags 60dp then the height will be 60dp * 0.25f = 15dp.
+ val trackingRatio = 0.25f
+
+ // The max progress starting from which the container should always be visible, even if we are
+ // animating the container out. This is used so that we don't immediately fade out the container
+ // when triggering a one-off animation that hides it.
+ val alphaProgressThreshold = 0.05f
+
+ // The spring animating the size of the container.
+ val sizeSpec = spring<Float>(stiffness = 380f, dampingRatio = 0.9f)
+
+ // The spring animating the alpha of the container.
+ val alphaSpec = spring<Float>(stiffness = 1200f, dampingRatio = 0.99f)
+
+ // The spring animating the progress when releasing the finger.
+ swipeSpec =
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ dampingRatio = Spring.DampingRatioNoBouncy,
+ visibilityThreshold = 0.5f,
+ )
+
+ // Size transformation.
+ transformation(container) {
+ VerticalContainerRevealSizeTransformation(
+ haptics,
+ distanceThreshold,
+ trackingRatio,
+ minHeight,
+ widthDelta,
+ sizeSpec,
+ )
+ }
+
+ // Alpha transformation.
+ transformation(container) {
+ ContainerRevealAlphaTransformation(alphaSpec, alphaProgressThreshold)
+ }
+}
+
+@OptIn(ExperimentalAnimatableApi::class)
+private class VerticalContainerRevealSizeTransformation(
+ private val haptics: ContainerRevealHaptics,
+ private val distanceThreshold: Dp,
+ private val trackingRatio: Float,
+ private val minHeight: Dp,
+ private val widthDelta: Dp,
+ private val spec: FiniteAnimationSpec<Float>,
+) : CustomPropertyTransformation<IntSize> {
+ override val property = PropertyTransformation.Property.Size
+
+ private val widthAnimation = DeferredTargetAnimation(Float.VectorConverter)
+ private val heightAnimation = DeferredTargetAnimation(Float.VectorConverter)
+
+ private var previousHasReachedThreshold: Boolean? = null
+
+ override fun PropertyTransformationScope.transform(
+ content: ContentKey,
+ element: ElementKey,
+ transition: TransitionState.Transition,
+ transitionScope: CoroutineScope,
+ ): IntSize {
+ // The distance to go to 100%. Note that we don't use
+ // TransitionState.HasOverscrollProperties.absoluteDistance because the transition will not
+ // implement HasOverscrollProperties if the transition is triggered and not gesture based.
+ val idleSize = checkNotNull(element.targetSize(content))
+ val userActionDistance = idleSize.height
+ val progress =
+ when ((transition as? TransitionState.HasOverscrollProperties)?.bouncingContent) {
+ null -> transition.progressTo(content)
+ content -> 1f
+ else -> 0f
+ }
+ val distance = (progress * userActionDistance).fastCoerceAtLeast(0f)
+ val threshold = distanceThreshold.toPx()
+
+ // Width.
+ val widthDelta = widthDelta.toPx()
+ val width =
+ (idleSize.width - widthDelta +
+ animateSize(
+ size = widthDelta,
+ distance = distance,
+ threshold = threshold,
+ transitionScope = transitionScope,
+ animation = widthAnimation,
+ ))
+ .roundToInt()
+
+ // Height.
+ val minHeight = minHeight.toPx()
+ val height =
+ (
+ // 1) The minimum size of the container.
+ minHeight +
+
+ // 2) The animated size between the minimum size and the threshold.
+ animateSize(
+ size = threshold - minHeight,
+ distance = distance,
+ threshold = threshold,
+ transitionScope = transitionScope,
+ animation = heightAnimation,
+ ) +
+
+ // 3) The remaining height after the threshold, tracking the finger.
+ (distance - threshold).fastCoerceAtLeast(0f))
+ .roundToInt()
+ .fastCoerceAtMost(idleSize.height)
+
+ // Haptics.
+ val hasReachedThreshold = distance >= threshold
+ if (
+ previousHasReachedThreshold != null &&
+ hasReachedThreshold != previousHasReachedThreshold &&
+ transition.isUserInputOngoing
+ ) {
+ haptics.onRevealThresholdCrossed(revealed = hasReachedThreshold)
+ }
+ previousHasReachedThreshold = hasReachedThreshold
+
+ return IntSize(width = width, height = height)
+ }
+
+ /**
+ * Animate a size up to [size], so that it is equal to 0f when distance is 0f and equal to
+ * [size] when `distance >= threshold`, taking the [trackingRatio] into account.
+ */
+ @OptIn(ExperimentalAnimatableApi::class)
+ private fun animateSize(
+ size: Float,
+ distance: Float,
+ threshold: Float,
+ transitionScope: CoroutineScope,
+ animation: DeferredTargetAnimation<Float, AnimationVector1D>,
+ ): Float {
+ val trackingSize = distance.fastCoerceAtMost(threshold) / threshold * size * trackingRatio
+ val springTarget =
+ if (distance >= threshold) {
+ size * (1f - trackingRatio)
+ } else {
+ 0f
+ }
+ val springSize = animation.updateTarget(springTarget, transitionScope, spec)
+ return trackingSize + springSize
+ }
+}
+
+@OptIn(ExperimentalAnimatableApi::class)
+private class ContainerRevealAlphaTransformation(
+ private val spec: FiniteAnimationSpec<Float>,
+ private val progressThreshold: Float,
+) : CustomPropertyTransformation<Float> {
+ override val property = PropertyTransformation.Property.Alpha
+ private val alphaAnimation = DeferredTargetAnimation(Float.VectorConverter)
+
+ override fun PropertyTransformationScope.transform(
+ content: ContentKey,
+ element: ElementKey,
+ transition: TransitionState.Transition,
+ transitionScope: CoroutineScope,
+ ): Float {
+ return alphaAnimation.updateTarget(targetAlpha(transition, content), transitionScope, spec)
+ }
+
+ private fun targetAlpha(transition: TransitionState.Transition, content: ContentKey): Float {
+ if (transition.isUserInputOngoing) {
+ if (transition !is TransitionState.HasOverscrollProperties) {
+ error(
+ "Unsupported transition driven by user input but that does not have " +
+ "overscroll properties: $transition"
+ )
+ }
+
+ val bouncingContent = transition.bouncingContent
+ return if (bouncingContent != null) {
+ if (bouncingContent == content) 1f else 0f
+ } else {
+ if (transition.progressTo(content) > 0f) 1f else 0f
+ }
+ }
+
+ // The transition was committed (the user released their finger), so the alpha depends on
+ // whether we are animating towards the content (showing the container) or away from it
+ // (hiding the container).
+ val isShowingContainer =
+ when (content) {
+ is SceneKey -> transition.currentScene == content
+ is OverlayKey -> transition.currentOverlays.contains(content)
+ }
+
+ return if (isShowingContainer || transition.progressTo(content) >= progressThreshold) {
+ 1f
+ } else {
+ 0f
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
index 0ddeb7c7445f..6575068201d8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
@@ -19,16 +19,17 @@ package com.android.compose.animation.scene.transformation
import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.content.state.TransitionState
/** Anchor the size of an element to the size of another element. */
-internal class AnchoredSize(
- override val matcher: ElementMatcher,
+internal class AnchoredSize
+private constructor(
private val anchor: ElementKey,
private val anchorWidth: Boolean,
private val anchorHeight: Boolean,
-) : PropertyTransformation<IntSize> {
+) : InterpolatedPropertyTransformation<IntSize> {
+ override val property = PropertyTransformation.Property.Size
+
override fun PropertyTransformationScope.transform(
content: ContentKey,
element: ElementKey,
@@ -59,4 +60,12 @@ internal class AnchoredSize(
anchorSizeIn(transition.fromContent)
}
}
+
+ class Factory(
+ private val anchor: ElementKey,
+ private val anchorWidth: Boolean,
+ private val anchorHeight: Boolean,
+ ) : Transformation.Factory {
+ override fun create(): Transformation = AnchoredSize(anchor, anchorWidth, anchorHeight)
+ }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
index 47508b41633c..890902b7ab67 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
@@ -19,14 +19,13 @@ package com.android.compose.animation.scene.transformation
import androidx.compose.ui.geometry.Offset
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.content.state.TransitionState
/** Anchor the translation of an element to another element. */
-internal class AnchoredTranslate(
- override val matcher: ElementMatcher,
- private val anchor: ElementKey,
-) : PropertyTransformation<Offset> {
+internal class AnchoredTranslate private constructor(private val anchor: ElementKey) :
+ InterpolatedPropertyTransformation<Offset> {
+ override val property = PropertyTransformation.Property.Offset
+
override fun PropertyTransformationScope.transform(
content: ContentKey,
element: ElementKey,
@@ -56,6 +55,10 @@ internal class AnchoredTranslate(
Offset(idleValue.x + offset.x, idleValue.y + offset.y)
}
}
+
+ class Factory(private val anchor: ElementKey) : Transformation.Factory {
+ override fun create(): Transformation = AnchoredTranslate(anchor)
+ }
}
internal fun throwMissingAnchorException(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
index 8488ae5178b0..347f1c325058 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
@@ -19,7 +19,6 @@ package com.android.compose.animation.scene.transformation
import androidx.compose.ui.geometry.Offset
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.Scale
import com.android.compose.animation.scene.content.state.TransitionState
@@ -27,12 +26,14 @@ import com.android.compose.animation.scene.content.state.TransitionState
* Scales the draw size of an element. Note this will only scale the draw inside of an element,
* therefore it won't impact layout of elements around it.
*/
-internal class DrawScale(
- override val matcher: ElementMatcher,
+internal class DrawScale
+private constructor(
private val scaleX: Float,
private val scaleY: Float,
- private val pivot: Offset = Offset.Unspecified,
-) : PropertyTransformation<Scale> {
+ private val pivot: Offset,
+) : InterpolatedPropertyTransformation<Scale> {
+ override val property = PropertyTransformation.Property.Scale
+
override fun PropertyTransformationScope.transform(
content: ContentKey,
element: ElementKey,
@@ -41,4 +42,9 @@ internal class DrawScale(
): Scale {
return Scale(scaleX, scaleY, pivot)
}
+
+ class Factory(private val scaleX: Float, private val scaleY: Float, private val pivot: Offset) :
+ Transformation.Factory {
+ override fun create(): Transformation = DrawScale(scaleX, scaleY, pivot)
+ }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
index 884aae4b8b1a..f8e6dc09ce75 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
@@ -20,15 +20,14 @@ import androidx.compose.ui.geometry.Offset
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.content.state.TransitionState
/** Translate an element from an edge of the layout. */
-internal class EdgeTranslate(
- override val matcher: ElementMatcher,
- private val edge: Edge,
- private val startsOutsideLayoutBounds: Boolean = true,
-) : PropertyTransformation<Offset> {
+internal class EdgeTranslate
+private constructor(private val edge: Edge, private val startsOutsideLayoutBounds: Boolean) :
+ InterpolatedPropertyTransformation<Offset> {
+ override val property = PropertyTransformation.Property.Offset
+
override fun PropertyTransformationScope.transform(
content: ContentKey,
element: ElementKey,
@@ -67,4 +66,9 @@ internal class EdgeTranslate(
}
}
}
+
+ class Factory(private val edge: Edge, private val startsOutsideLayoutBounds: Boolean) :
+ Transformation.Factory {
+ override fun create(): Transformation = EdgeTranslate(edge, startsOutsideLayoutBounds)
+ }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
index ef769e7d0c19..d92419ef368d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
@@ -18,11 +18,12 @@ package com.android.compose.animation.scene.transformation
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.content.state.TransitionState
/** Fade an element in or out. */
-internal class Fade(override val matcher: ElementMatcher) : PropertyTransformation<Float> {
+internal object Fade : InterpolatedPropertyTransformation<Float> {
+ override val property = PropertyTransformation.Property.Alpha
+
override fun PropertyTransformationScope.transform(
content: ContentKey,
element: ElementKey,
@@ -33,4 +34,8 @@ internal class Fade(override val matcher: ElementMatcher) : PropertyTransformati
// fading out, which is `0` in both cases.
return 0f
}
+
+ object Factory : Transformation.Factory {
+ override fun create(): Transformation = Fade
+ }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
index ef3654b65b0a..5d31fd9ca196 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
@@ -19,7 +19,6 @@ package com.android.compose.animation.scene.transformation
import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.content.state.TransitionState
import kotlin.math.roundToInt
@@ -27,11 +26,10 @@ import kotlin.math.roundToInt
* Scales the size of an element. Note that this makes the element resize every frame and will
* therefore impact the layout of other elements.
*/
-internal class ScaleSize(
- override val matcher: ElementMatcher,
- private val width: Float = 1f,
- private val height: Float = 1f,
-) : PropertyTransformation<IntSize> {
+internal class ScaleSize private constructor(private val width: Float, private val height: Float) :
+ InterpolatedPropertyTransformation<IntSize> {
+ override val property = PropertyTransformation.Property.Size
+
override fun PropertyTransformationScope.transform(
content: ContentKey,
element: ElementKey,
@@ -43,4 +41,9 @@ internal class ScaleSize(
height = (idleValue.height * height).roundToInt(),
)
}
+
+ class Factory(private val width: Float = 1f, private val height: Float = 1f) :
+ Transformation.Factory {
+ override fun create(): Transformation = ScaleSize(width, height)
+ }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 74a3ead3fbd7..e0b42189854a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -18,7 +18,9 @@ package com.android.compose.animation.scene.transformation
import androidx.compose.animation.core.Easing
import androidx.compose.animation.core.LinearEasing
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.util.fastCoerceAtLeast
import androidx.compose.ui.util.fastCoerceAtMost
@@ -27,30 +29,65 @@ import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.ElementStateScope
+import com.android.compose.animation.scene.Scale
import com.android.compose.animation.scene.content.state.TransitionState
+import kotlinx.coroutines.CoroutineScope
/** A transformation applied to one or more elements during a transition. */
sealed interface Transformation {
- /**
- * The matcher that should match the element(s) to which this transformation should be applied.
- */
- val matcher: ElementMatcher
-
- /*
- * Reverse this transformation. This is called when we use Transition(from = A, to = B) when
- * animating from B to A and there is no Transition(from = B, to = A) defined.
- */
- fun reversed(): Transformation = this
+ fun interface Factory {
+ fun create(): Transformation
+ }
}
-internal class SharedElementTransformation(
- override val matcher: ElementMatcher,
+// Important: SharedElementTransformation must be a data class because we check that we don't
+// provide 2 different transformations for the same element in Element.kt
+internal data class SharedElementTransformation(
internal val enabled: Boolean,
internal val elevateInContent: ContentKey?,
-) : Transformation
+) : Transformation {
+ class Factory(
+ internal val matcher: ElementMatcher,
+ internal val enabled: Boolean,
+ internal val elevateInContent: ContentKey?,
+ ) : Transformation.Factory {
+ override fun create(): Transformation {
+ return SharedElementTransformation(enabled, elevateInContent)
+ }
+ }
+}
+
+/**
+ * A transformation that changes the value of an element [Property], like its [size][Property.Size]
+ * or [offset][Property.Offset].
+ */
+sealed interface PropertyTransformation<T> : Transformation {
+ /** The property to which this transformation is applied. */
+ val property: Property<T>
+
+ sealed class Property<T> {
+ /** The size of an element. */
+ data object Size : Property<IntSize>()
+
+ /** The offset (position) of an element. */
+ data object Offset : Property<androidx.compose.ui.geometry.Offset>()
+
+ /** The alpha of an element. */
+ data object Alpha : Property<Float>()
+
+ /**
+ * The drawing scale of an element. Animating the scale does not have any effect on the
+ * layout.
+ */
+ data object Scale : Property<com.android.compose.animation.scene.Scale>()
+ }
+}
-/** A transformation that changes the value of an element property, like its size or offset. */
-interface PropertyTransformation<T> : Transformation {
+/**
+ * A transformation to a target/transformed value that is automatically interpolated using the
+ * transition progress and transformation range.
+ */
+interface InterpolatedPropertyTransformation<T> : PropertyTransformation<T> {
/**
* Return the transformed value for the given property, i.e.:
* - the value at progress = 0% for elements that are entering the layout (i.e. elements in the
@@ -58,8 +95,8 @@ interface PropertyTransformation<T> : Transformation {
* - the value at progress = 100% for elements that are leaving the layout (i.e. elements in the
* content we are transitioning from).
*
- * The returned value will be interpolated using the [transition] progress and [idleValue], the
- * value of the property when we are idle.
+ * The returned value will be automatically interpolated using the [transition] progress, the
+ * transformation range and [idleValue], the value of the property when we are idle.
*/
fun PropertyTransformationScope.transform(
content: ContentKey,
@@ -69,13 +106,40 @@ interface PropertyTransformation<T> : Transformation {
): T
}
+interface CustomPropertyTransformation<T> : PropertyTransformation<T> {
+ /**
+ * Return the value that the property should have in the current frame for the given [content]
+ * and [element].
+ *
+ * This transformation can use [transitionScope] to launch animations associated to
+ * [transition], which will not finish until at least one animation/job is still running in the
+ * scope.
+ *
+ * Important: Make sure to never launch long-running jobs in [transitionScope], otherwise
+ * [transition] will never be considered as finished.
+ */
+ fun PropertyTransformationScope.transform(
+ content: ContentKey,
+ element: ElementKey,
+ transition: TransitionState.Transition,
+ transitionScope: CoroutineScope,
+ ): T
+}
+
interface PropertyTransformationScope : Density, ElementStateScope {
/** The current [direction][LayoutDirection] of the layout. */
val layoutDirection: LayoutDirection
}
+/** Defines the transformation-type to be applied to all elements matching [matcher]. */
+internal class TransformationMatcher(
+ val matcher: ElementMatcher,
+ val factory: Transformation.Factory,
+ val range: TransformationRange?,
+)
+
/** A pair consisting of a [transformation] and optional [range]. */
-class TransformationWithRange<out T : Transformation>(
+internal data class TransformationWithRange<out T : Transformation>(
val transformation: T,
val range: TransformationRange?,
) {
@@ -87,7 +151,7 @@ class TransformationWithRange<out T : Transformation>(
}
/** The progress-based range of a [PropertyTransformation]. */
-data class TransformationRange(val start: Float, val end: Float, val easing: Easing) {
+internal data class TransformationRange(val start: Float, val end: Float, val easing: Easing) {
constructor(
start: Float? = null,
end: Float? = null,
@@ -101,7 +165,7 @@ data class TransformationRange(val start: Float, val end: Float, val easing: Eas
}
/** Reverse this range. */
- fun reversed() =
+ internal fun reversed() =
TransformationRange(start = reverseBound(end), end = reverseBound(start), easing = easing)
/** Get the progress of this range given the global [transitionProgress]. */
@@ -128,6 +192,6 @@ data class TransformationRange(val start: Float, val end: Float, val easing: Eas
}
companion object {
- const val BoundUnspecified = Float.MIN_VALUE
+ internal const val BoundUnspecified = Float.MIN_VALUE
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
index 356ed9969458..2f4d5bff8b41 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
@@ -19,18 +19,15 @@ package com.android.compose.animation.scene.transformation
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.OverscrollScope
import com.android.compose.animation.scene.content.state.TransitionState
-internal class Translate(
- override val matcher: ElementMatcher,
- private val x: Dp = 0.dp,
- private val y: Dp = 0.dp,
-) : PropertyTransformation<Offset> {
+internal class Translate private constructor(private val x: Dp, private val y: Dp) :
+ InterpolatedPropertyTransformation<Offset> {
+ override val property = PropertyTransformation.Property.Offset
+
override fun PropertyTransformationScope.transform(
content: ContentKey,
element: ElementKey,
@@ -39,13 +36,19 @@ internal class Translate(
): Offset {
return Offset(idleValue.x + x.toPx(), idleValue.y + y.toPx())
}
+
+ class Factory(private val x: Dp, private val y: Dp) : Transformation.Factory {
+ override fun create(): Transformation = Translate(x, y)
+ }
}
-internal class OverscrollTranslate(
- override val matcher: ElementMatcher,
- val x: OverscrollScope.() -> Float = { 0f },
- val y: OverscrollScope.() -> Float = { 0f },
-) : PropertyTransformation<Offset> {
+internal class OverscrollTranslate
+private constructor(
+ private val x: OverscrollScope.() -> Float,
+ private val y: OverscrollScope.() -> Float,
+) : InterpolatedPropertyTransformation<Offset> {
+ override val property = PropertyTransformation.Property.Offset
+
private val cachedOverscrollScope = CachedOverscrollScope()
override fun PropertyTransformationScope.transform(
@@ -63,6 +66,13 @@ internal class OverscrollTranslate(
return Offset(x = value.x + overscrollScope.x(), y = value.y + overscrollScope.y())
}
+
+ class Factory(
+ private val x: OverscrollScope.() -> Float,
+ private val y: OverscrollScope.() -> Float,
+ ) : Transformation.Factory {
+ override fun create(): Transformation = OverscrollTranslate(x, y)
+ }
}
/**
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt
index 2b33224022fc..c6912d5e4ad2 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt
@@ -145,7 +145,7 @@ internal suspend fun <T : ContentKey> animateProgress(
cancelSpec: AnimationSpec<Float>?,
animationScope: CoroutineScope? = null,
) {
- fun animateOffset(targetContent: T, spec: AnimationSpec<Float>?) {
+ suspend fun animateOffset(targetContent: T, spec: AnimationSpec<Float>?) {
if (state.transitionState != animation.contentTransition || animation.isAnimatingOffset()) {
return
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index 20a0b390a037..3f182363e20c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -365,12 +365,16 @@ private class OnStopScopeImpl(private val controller: ScrollController) : OnStop
flingBehavior: FlingBehavior,
): Float {
return with(flingBehavior) {
- object : ScrollScope {
- override fun scrollBy(pixels: Float): Float {
- return controller.onScroll(pixels, NestedScrollSource.SideEffect)
+ val remainingVelocity =
+ object : ScrollScope {
+ override fun scrollBy(pixels: Float): Float {
+ return controller.onScroll(pixels, NestedScrollSource.SideEffect)
+ }
}
- }
- .performFling(initialVelocity)
+ .performFling(initialVelocity)
+
+ // returns the consumed velocity
+ initialVelocity - remainingVelocity
}
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 7e6f3a88fab1..a1077cf95133 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -45,6 +45,8 @@ import com.android.compose.test.runMonotonicClockTest
import com.android.compose.test.transition
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import org.junit.Test
import org.junit.runner.RunWith
@@ -133,8 +135,8 @@ class DraggableHandlerTest {
)
.apply { setContentsAndLayoutTargetSizeForTest(LAYOUT_SIZE) }
- val draggableHandler = layoutImpl.draggableHandler(Orientation.Vertical)
- val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal)
+ val draggableHandler = layoutImpl.verticalDraggableHandler
+ val horizontalDraggableHandler = layoutImpl.horizontalDraggableHandler
var pointerInfoOwner: () -> PointersInfo = { pointersDown() }
@@ -143,8 +145,7 @@ class DraggableHandlerTest {
isExternalOverscrollGesture: Boolean = false,
) =
NestedScrollHandlerImpl(
- layoutImpl = layoutImpl,
- orientation = draggableHandler.orientation,
+ draggableHandler = draggableHandler,
topOrLeftBehavior = nestedScrollBehavior,
bottomOrRightBehavior = nestedScrollBehavior,
isExternalOverscrollGesture = { isExternalOverscrollGesture },
@@ -267,7 +268,7 @@ class DraggableHandlerTest {
) {
val velocityConsumed = onDragStoppedAnimateLater(velocity, canChangeScene)
onAnimationStart()
- onAnimationEnd(velocityConsumed.invoke())
+ onAnimationEnd(velocityConsumed.await())
}
suspend fun DragController.onDragStoppedAnimateNow(
@@ -286,8 +287,10 @@ class DraggableHandlerTest {
fun DragController.onDragStoppedAnimateLater(
velocity: Float,
canChangeScene: Boolean = true,
- ): SuspendedValue<Float> {
- return onStop(velocity, canChangeScene)
+ ): Deferred<Float> {
+ val velocityConsumed = testScope.async { onStop(velocity, canChangeScene) }
+ testScope.testScheduler.runCurrent()
+ return velocityConsumed
}
fun NestedScrollConnection.scroll(
@@ -645,7 +648,7 @@ class DraggableHandlerTest {
mutableUserActionsA = emptyMap()
mutableUserActionsB = emptyMap()
- // start accelaratedScroll and scroll over to B -> null
+ // start acceleratedScroll and scroll over to B -> null
val dragController2 = onDragStartedImmediately()
dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = 0f)
dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = 0f)
@@ -1113,6 +1116,7 @@ class DraggableHandlerTest {
// Freeze the transition.
val transition = transitionState as Transition
transition.freezeAndAnimateToCurrentState()
+ runCurrent()
assertTransition(isUserInputOngoing = false)
advanceUntilIdle()
assertIdle(SceneC)
@@ -1280,14 +1284,13 @@ class DraggableHandlerTest {
// Release the finger.
dragController.onDragStoppedAnimateNow(
velocity = -velocityThreshold,
- onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB) },
+ onAnimationStart = {
+ // Given that we are at progress >= 100% and that the overscroll on scene B is doing
+ // nothing, we are already idle.
+ assertIdle(SceneB)
+ },
expectedConsumedVelocity = 0f,
)
-
- // Exhaust all coroutines *without advancing the clock*. Given that we are at progress >=
- // 100% and that the overscroll on scene B is doing nothing, we are already idle.
- runCurrent()
- assertIdle(SceneB)
}
@Test
@@ -1531,7 +1534,7 @@ class DraggableHandlerTest {
fun interceptingTransitionKeepsDistance() = runGestureTest {
var swipeDistance = 75f
layoutState.transitions = transitions {
- from(SceneA, to = SceneB) { distance = UserActionDistance { _, _ -> swipeDistance } }
+ from(SceneA, to = SceneB) { distance = UserActionDistance { _, _, _ -> swipeDistance } }
}
// Start transition.
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
index b87cc5c88335..3622369b8ff9 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
@@ -132,6 +132,9 @@ class InterruptionHandlerTest {
assertThat(state.currentTransitions)
.comparingElementsUsing(FromToCurrentTriple)
.containsExactly(
+ // Initial transition, A => B.
+ Triple(SceneA, SceneB, SceneB),
+
// Initial transition reversed, B back to A.
Triple(SceneA, SceneB, SceneA),
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index 09b59394724d..b4c8ad7c3327 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -35,6 +35,7 @@ import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onAllNodesWithText
@@ -404,4 +405,40 @@ class MovableElementTest {
rule.waitForIdle()
rule.onNodeWithTag(fooParentInOverlayTag).assertSizeIsEqualTo(fooSize)
}
+
+ @Test
+ fun movableElementInOverlayShouldBeComposed() {
+ val fooKey = MovableElementKey("foo", contents = setOf(OverlayA))
+ val fooContentTag = "fooContentTag"
+
+ @Composable
+ fun ContentScope.MovableFoo(modifier: Modifier = Modifier) {
+ MovableElement(fooKey, modifier) {
+ content { Box(Modifier.testTag(fooContentTag).size(100.dp)) }
+ }
+ }
+
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ initialScene = SceneA,
+ initialOverlays = setOf(OverlayA),
+ )
+ }
+
+ val scope =
+ rule.setContentAndCreateMainScope {
+ SceneTransitionLayout(state) {
+ scene(SceneA) { Box(Modifier.fillMaxSize()) }
+ overlay(OverlayA) { MovableFoo() }
+ overlay(OverlayB) { Box(Modifier.size(50.dp)) }
+ }
+ }
+
+ rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp)
+
+ // Show overlay B. This shouldn't have any impact on Foo that should still be composed in A.
+ scope.launch { state.startTransition(transition(SceneA, OverlayB)) }
+ rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index 5ec74f8d2260..cb3e433ec4a5 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -72,9 +72,13 @@ class MultiPointerDraggableTest {
return delta
}
- override fun onStop(velocity: Float, canChangeContent: Boolean): SuspendedValue<Float> {
+ override suspend fun onStop(velocity: Float, canChangeContent: Boolean): Float {
onStop.invoke(velocity)
- return { velocity }
+ return velocity
+ }
+
+ override fun onCancel(canChangeContent: Boolean) {
+ error("MultiPointerDraggable never calls onCancel()")
}
}
@@ -593,7 +597,7 @@ class MultiPointerDraggableTest {
}
}
- fun continueDraggingDown() {
+ fun dragDown() {
rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
}
@@ -603,11 +607,78 @@ class MultiPointerDraggableTest {
assertThat(started).isFalse()
swipeConsume = true
- continueDraggingDown()
+ // Drag in same direction
+ dragDown()
assertThat(capturedChange).isNotNull()
capturedChange = null
- continueDraggingDown()
+ dragDown()
+ assertThat(capturedChange).isNull()
+
+ assertThat(started).isTrue()
+ }
+
+ @Test
+ fun multiPointerSwipeDetectorInteractionZeroOffsetFromStartPosition() {
+ val size = 200f
+ val middle = Offset(size / 2f, size / 2f)
+
+ var started = false
+
+ var capturedChange: PointerInputChange? = null
+ var swipeConsume = false
+
+ var touchSlop = 0f
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ Box(
+ Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
+ .nestedScrollDispatcher()
+ .multiPointerDraggable(
+ orientation = Orientation.Vertical,
+ startDragImmediately = { false },
+ swipeDetector =
+ object : SwipeDetector {
+ override fun detectSwipe(change: PointerInputChange): Boolean {
+ capturedChange = change
+ return swipeConsume
+ }
+ },
+ onDragStarted = { _, _ ->
+ started = true
+ SimpleDragController(
+ onDrag = { /* do nothing */ },
+ onStop = { /* do nothing */ },
+ )
+ },
+ dispatcher = defaultDispatcher,
+ )
+ ) {}
+ }
+
+ fun startDraggingDown() {
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(0f, touchSlop))
+ }
+ }
+
+ fun dragUp() {
+ rule.onRoot().performTouchInput { moveBy(Offset(0f, -touchSlop)) }
+ }
+
+ startDraggingDown()
+ assertThat(capturedChange).isNotNull()
+ capturedChange = null
+ assertThat(started).isFalse()
+
+ swipeConsume = true
+ // Drag in the opposite direction
+ dragUp()
+ assertThat(capturedChange).isNotNull()
+ capturedChange = null
+
+ dragUp()
assertThat(capturedChange).isNull()
assertThat(started).isTrue()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 2b7090876bad..79ca891babd1 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -23,6 +23,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestOverlays.OverlayA
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
@@ -35,12 +36,15 @@ import com.android.compose.test.runMonotonicClockTest
import com.android.compose.test.transition
import com.google.common.truth.Truth.assertThat
import kotlin.coroutines.cancellation.CancellationException
+import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Rule
@@ -149,7 +153,7 @@ class SceneTransitionLayoutStateTest {
// Default transition from A to B.
assertThat(state.setTargetScene(SceneB, animationScope = this)).isNotNull()
- assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
+ assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(1)
// Go back to A.
state.setTargetScene(SceneA, animationScope = this)
@@ -162,7 +166,7 @@ class SceneTransitionLayoutStateTest {
state.setTargetScene(SceneB, animationScope = this, transitionKey = transitionkey)
)
.isNotNull()
- assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
+ assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2)
}
@Test
@@ -185,6 +189,25 @@ class SceneTransitionLayoutStateTest {
}
@Test
+ fun snapToIdleIfClose_snapToStart_overlays() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+ state.startTransitionImmediately(
+ animationScope = backgroundScope,
+ transition(SceneA, OverlayA, isEffectivelyShown = { false }, progress = { 0.2f }),
+ )
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+ assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Go to the initial scene if it is close to 0.
+ assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+ assertThat(state.isTransitioning()).isFalse()
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA))
+ }
+
+ @Test
fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
state.startTransitionImmediately(
@@ -204,6 +227,25 @@ class SceneTransitionLayoutStateTest {
}
@Test
+ fun snapToIdleIfClose_snapToEnd_overlays() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+ state.startTransitionImmediately(
+ animationScope = backgroundScope,
+ transition(SceneA, OverlayA, isEffectivelyShown = { true }, progress = { 0.8f }),
+ )
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+ assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Go to the final scene if it is close to 1.
+ assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+ assertThat(state.isTransitioning()).isFalse()
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA, setOf(OverlayA)))
+ }
+
+ @Test
fun snapToIdleIfClose_multipleTransitions() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
@@ -601,4 +643,73 @@ class SceneTransitionLayoutStateTest {
runBlocking { state.startTransition(transition) }
}
}
+
+ @Test
+ fun transitionFinishedWhenScopeIsEmpty() = runTest {
+ val state = MutableSceneTransitionLayoutState(SceneA)
+
+ // Start a transition.
+ val transition = transition(from = SceneA, to = SceneB)
+ state.startTransitionImmediately(backgroundScope, transition)
+ assertThat(state.transitionState).isSceneTransition()
+
+ // Start a job in the transition scope.
+ val jobCompletable = CompletableDeferred<Unit>()
+ transition.coroutineScope.launch { jobCompletable.await() }
+
+ // Finish the transition (i.e. make its #run() method return). The transition should not be
+ // considered as finished yet given that there is a job still running in its scope.
+ transition.finish()
+ runCurrent()
+ assertThat(state.transitionState).isSceneTransition()
+
+ // Finish the job in the scope. Now the transition should be considered as finished.
+ jobCompletable.complete(Unit)
+ runCurrent()
+ assertThat(state.transitionState).isIdle()
+ }
+
+ @Test
+ fun transitionScopeIsCancelledWhenTransitionIsForceFinished() = runTest {
+ val state = MutableSceneTransitionLayoutState(SceneA)
+
+ // Start a transition.
+ val transition = transition(from = SceneA, to = SceneB)
+ state.startTransitionImmediately(backgroundScope, transition)
+ assertThat(state.transitionState).isSceneTransition()
+
+ // Start a job in the transition scope that never finishes.
+ val job = transition.coroutineScope.launch { awaitCancellation() }
+
+ // Force snap state to SceneB to force finish all current transitions.
+ state.snapToScene(SceneB)
+ assertThat(state.transitionState).isIdle()
+ assertThat(job.isCancelled).isTrue()
+ }
+
+ @Test
+ fun badTransitionSpecThrowsMeaningfulMessageWhenStartingTransition() {
+ val state =
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ transitions {
+ // This transition definition is bad because they both match when transitioning
+ // from A to B.
+ from(SceneA) {}
+ to(SceneB) {}
+ },
+ )
+
+ val exception =
+ assertThrows(IllegalStateException::class.java) {
+ runBlocking { state.startTransition(transition(from = SceneA, to = SceneB)) }
+ }
+
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Found multiple transition specs for transition SceneKey(debugName=SceneA) => " +
+ "SceneKey(debugName=SceneB)"
+ )
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 97a96a4333cb..b3a3261122a8 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -55,7 +55,6 @@ import androidx.compose.ui.test.swipeRight
import androidx.compose.ui.test.swipeUp
import androidx.compose.ui.test.swipeWithVelocity
import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -672,12 +671,12 @@ class SwipeToSceneTest {
}
assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
- assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
+ assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(1)
// Move the pointer up to swipe to scene B using the new transition.
rule.onRoot().performTouchInput { moveBy(Offset(0f, -1.dp.toPx()), delayMillis = 1_000) }
assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
- assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
+ assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2)
}
@Test
@@ -685,7 +684,8 @@ class SwipeToSceneTest {
val swipeDistance =
object : UserActionDistance {
override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
+ fromContent: ContentKey,
+ toContent: ContentKey,
orientation: Orientation,
): Float {
// Foo is going to have a vertical offset of 50dp. Let's make the swipe distance
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index d31711496ff0..70f2ff80f9d7 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -22,17 +22,23 @@ import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.ui.unit.IntSize
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
import com.android.compose.animation.scene.transformation.OverscrollTranslate
+import com.android.compose.animation.scene.transformation.PropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformationScope
+import com.android.compose.animation.scene.transformation.TransformationMatcher
import com.android.compose.animation.scene.transformation.TransformationRange
-import com.android.compose.animation.scene.transformation.TransformationWithRange
import com.android.compose.test.transition
import com.google.common.truth.Correspondence
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Test
@@ -98,7 +104,7 @@ class TransitionDslTest {
val transitions = transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } }
val transformations =
- transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+ transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
assertThat(transformations.size).isEqualTo(1)
assertThat(transformations.single().range).isEqualTo(null)
}
@@ -121,7 +127,7 @@ class TransitionDslTest {
}
val transformations =
- transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+ transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
@@ -152,7 +158,7 @@ class TransitionDslTest {
}
val transformations =
- transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+ transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
@@ -180,7 +186,7 @@ class TransitionDslTest {
}
val transformations =
- transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+ transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
@@ -210,7 +216,7 @@ class TransitionDslTest {
// to B we defined.
val transitionSpec = transitions.transitionSpec(from = SceneB, to = SceneA, key = null)
- val transformations = transitionSpec.transformationSpec(aToB()).transformations
+ val transformations = transitionSpec.transformationSpec(aToB()).transformationMatchers
assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -220,7 +226,7 @@ class TransitionDslTest {
)
val previewTransformations =
- transitionSpec.previewTransformationSpec(aToB())?.transformations
+ transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers
assertThat(previewTransformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -250,7 +256,7 @@ class TransitionDslTest {
key = TransitionKey.PredictiveBack,
)
- val transformations = transitionSpec.transformationSpec(aToB()).transformations
+ val transformations = transitionSpec.transformationSpec(aToB()).transformationMatchers
assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -260,7 +266,7 @@ class TransitionDslTest {
)
val previewTransformations =
- transitionSpec.previewTransformationSpec(aToB())?.transformations
+ transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers
assertThat(previewTransformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -311,7 +317,7 @@ class TransitionDslTest {
val overscrollSpec = transitions.overscrollSpecs.single()
val transformation =
- overscrollSpec.transformationSpec.transformations.single().transformation
+ overscrollSpec.transformationSpec.transformationMatchers.single().factory.create()
assertThat(transformation).isInstanceOf(OverscrollTranslate::class.java)
}
@@ -319,7 +325,7 @@ class TransitionDslTest {
fun overscrollSpec_for_overscrollDisabled() {
val transitions = transitions { overscrollDisabled(SceneA, Orientation.Vertical) }
val overscrollSpec = transitions.overscrollSpecs.single()
- assertThat(overscrollSpec.transformationSpec.transformations).isEmpty()
+ assertThat(overscrollSpec.transformationSpec.transformationMatchers).isEmpty()
}
@Test
@@ -343,9 +349,36 @@ class TransitionDslTest {
assertThat(transitionPassedToBuilder).isSameInstanceAs(transition)
}
+ @Test
+ fun customTransitionsAreNotSupportedInRanges() = runTest {
+ val transitions = transitions {
+ from(SceneA, to = SceneB) {
+ fractionRange {
+ transformation(TestElements.Foo) {
+ object : CustomPropertyTransformation<IntSize> {
+ override val property = PropertyTransformation.Property.Size
+
+ override fun PropertyTransformationScope.transform(
+ content: ContentKey,
+ element: ElementKey,
+ transition: TransitionState.Transition,
+ transitionScope: CoroutineScope,
+ ): IntSize = IntSize.Zero
+ }
+ }
+ }
+ }
+ }
+
+ val state = MutableSceneTransitionLayoutState(SceneA, transitions)
+ assertThrows(IllegalStateException::class.java) {
+ runBlocking { state.startTransition(transition(from = SceneA, to = SceneB)) }
+ }
+ }
+
companion object {
private val TRANSFORMATION_RANGE =
- Correspondence.transforming<TransformationWithRange<*>, TransformationRange?>(
+ Correspondence.transforming<TransformationMatcher, TransformationRange?>(
{ it?.range },
"has range equal to",
)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
index 313379f4c74b..0adb4809dd2d 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
@@ -157,7 +157,7 @@ abstract class BaseTransitionSubject<T : TransitionState.Transition>(
check("isUserInputOngoing").that(actual.isUserInputOngoing).isEqualTo(isUserInputOngoing)
}
- fun hasOverscrollSpec(): OverscrollSpec {
+ internal fun hasOverscrollSpec(): OverscrollSpec {
check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNotNull()
return actual.currentOverscrollSpec!!
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt
new file mode 100644
index 000000000000..444ec4ead561
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2024 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.compose.animation.scene.transformation
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.testTransition
+import com.android.compose.test.assertSizeIsEqualTo
+import kotlinx.coroutines.CoroutineScope
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class CustomTransformationTest {
+ @get:Rule val rule = createComposeRule()
+
+ @Test
+ fun customSize() {
+ /** A size transformation that adds [add] to the size of the transformed element(s). */
+ class AddSizeTransformation(private val add: Dp) : CustomPropertyTransformation<IntSize> {
+ override val property = PropertyTransformation.Property.Size
+
+ override fun PropertyTransformationScope.transform(
+ content: ContentKey,
+ element: ElementKey,
+ transition: TransitionState.Transition,
+ transitionScope: CoroutineScope,
+ ): IntSize {
+ val idleSize = checkNotNull(element.targetSize(content))
+ val progress = 1f - transition.progressTo(content)
+ val addPx = (add * progress).roundToPx()
+ return IntSize(width = idleSize.width + addPx, height = idleSize.height + addPx)
+ }
+ }
+
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.element(TestElements.Foo).size(40.dp, 20.dp)) },
+ toSceneContent = {},
+ transition = {
+ spec = tween(16 * 4, easing = LinearEasing)
+
+ // Add 80dp to the width and height of Foo.
+ transformation(TestElements.Foo) { AddSizeTransformation(80.dp) }
+ },
+ ) {
+ before { onElement(TestElements.Foo).assertSizeIsEqualTo(40.dp, 20.dp) }
+ at(0) { onElement(TestElements.Foo).assertSizeIsEqualTo(40.dp, 20.dp) }
+ at(16) { onElement(TestElements.Foo).assertSizeIsEqualTo(60.dp, 40.dp) }
+ at(32) { onElement(TestElements.Foo).assertSizeIsEqualTo(80.dp, 60.dp) }
+ at(48) { onElement(TestElements.Foo).assertSizeIsEqualTo(100.dp, 80.dp) }
+ after { onElement(TestElements.Foo).assertDoesNotExist() }
+ }
+ }
+
+ @Test
+ fun customOffset() {
+ /** An offset transformation that adds [add] to the offset of the transformed element(s). */
+ class AddOffsetTransformation(private val add: Dp) : CustomPropertyTransformation<Offset> {
+ override val property = PropertyTransformation.Property.Offset
+
+ override fun PropertyTransformationScope.transform(
+ content: ContentKey,
+ element: ElementKey,
+ transition: TransitionState.Transition,
+ transitionScope: CoroutineScope,
+ ): Offset {
+ val idleOffset = checkNotNull(element.targetOffset(content))
+ val progress = 1f - transition.progressTo(content)
+ val addPx = (add * progress).toPx()
+ return Offset(x = idleOffset.x + addPx, y = idleOffset.y + addPx)
+ }
+ }
+
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.element(TestElements.Foo)) },
+ toSceneContent = {},
+ transition = {
+ spec = tween(16 * 4, easing = LinearEasing)
+
+ // Add 80dp to the offset of Foo.
+ transformation(TestElements.Foo) { AddOffsetTransformation(80.dp) }
+ },
+ ) {
+ before { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(0.dp, 0.dp) }
+ at(0) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(0.dp, 0.dp) }
+ at(16) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(20.dp, 20.dp) }
+ at(32) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(40.dp, 40.dp) }
+ at(48) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(60.dp, 60.dp) }
+ after { onElement(TestElements.Foo).assertDoesNotExist() }
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
index 91079b89a56c..28ea2d239b54 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
@@ -53,7 +53,8 @@ class PriorityNestedScrollConnectionTest {
object : FlingBehavior {
override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
scrollBy(initialVelocity)
- return initialVelocity / 2f
+ // returns the remaining velocity: 1/3 remained + 2/3 consumed
+ return initialVelocity / 3f
}
}
@@ -207,11 +208,13 @@ class PriorityNestedScrollConnectionTest {
val consumed = scrollConnection.onPreFling(available = Velocity(2f, 2f))
- assertThat(lastStop).isEqualTo(2f)
+ val initialVelocity = 2f
+ assertThat(lastStop).isEqualTo(initialVelocity)
// flingToScroll should try to scroll the content, customFlingBehavior uses the velocity.
assertThat(lastScroll).isEqualTo(2f)
- // customFlingBehavior returns half of the vertical velocity.
- assertThat(consumed).isEqualTo(Velocity(0f, 1f))
+ val remainingVelocity = initialVelocity / 3f
+ // customFlingBehavior returns 2/3 of the vertical velocity.
+ assertThat(consumed).isEqualTo(Velocity(0f, initialVelocity - remainingVelocity))
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml b/packages/SystemUI/customization/res/values-land/dimens.xml
index 4bd9ca049f55..50f220c882bd 100644
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml
+++ b/packages/SystemUI/customization/res/values-land/dimens.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
@@ -15,8 +14,6 @@
~ limitations under the License.
-->
-<network-security-config>
- <domain-config cleartextTrafficPermitted="true">
- <domain includeSubdomains="true">localhost</domain>
- </domain-config>
-</network-security-config>
+<resources>
+ <dimen name="lock_icon_margin_bottom">24dp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml
index 651e401681c6..876028195ff3 100644
--- a/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml
@@ -16,4 +16,6 @@
<resources>
<dimen name="keyguard_smartspace_top_offset">0dp</dimen>
+ <dimen name="status_view_margin_horizontal">8dp</dimen>
+ <dimen name="lock_icon_margin_bottom">60dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw600dp/dimens.xml b/packages/SystemUI/customization/res/values-sw600dp/dimens.xml
index 10e630d44488..37cd590b979e 100644
--- a/packages/SystemUI/customization/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/customization/res/values-sw600dp/dimens.xml
@@ -17,4 +17,5 @@
<resources>
<!-- For portrait direction in unfold foldable device, we don't need keyguard_smartspace_top_offset-->
<dimen name="keyguard_smartspace_top_offset">0dp</dimen>
+ <dimen name="status_view_margin_horizontal">62dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 000000000000..c1cf42c4b0f0
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="status_view_margin_horizontal">24dp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml
new file mode 100644
index 000000000000..54dbeaa1a3dd
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="status_view_margin_horizontal">124dp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml
index 7feea6e5e8dd..2bb5541f4b0a 100644
--- a/packages/SystemUI/customization/res/values/dimens.xml
+++ b/packages/SystemUI/customization/res/values/dimens.xml
@@ -33,10 +33,13 @@
<dimen name="small_clock_height">114dp</dimen>
<dimen name="small_clock_padding_top">28dp</dimen>
<dimen name="clock_padding_start">28dp</dimen>
+ <dimen name="weather_date_icon_padding">28dp</dimen>
<!-- When large clock is showing, offset the smartspace by this amount -->
<dimen name="keyguard_smartspace_top_offset">12dp</dimen>
<!--Dimens used in both lockscreen preview and smartspace -->
<dimen name="date_weather_view_height">24dp</dimen>
<dimen name="enhanced_smartspace_height">104dp</dimen>
+ <dimen name="status_view_margin_horizontal">0dp</dimen>
+ <dimen name="lock_icon_margin_bottom">74dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 9877406eeac2..801a2d6170cc 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -34,6 +34,7 @@ import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GlyphCallback
import com.android.systemui.animation.TextAnimator
+import com.android.systemui.animation.TypefaceVariantCacheImpl
import com.android.systemui.customization.R
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.core.LogcatOnlyMessageBuffer
@@ -98,7 +99,8 @@ constructor(
@VisibleForTesting
var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = { layout, invalidateCb ->
- TextAnimator(layout, NUM_CLOCK_FONT_ANIMATION_STEPS, invalidateCb)
+ val cache = TypefaceVariantCacheImpl(layout.paint.typeface, NUM_CLOCK_FONT_ANIMATION_STEPS)
+ TextAnimator(layout, cache, invalidateCb)
}
// Used by screenshot tests to provide stability
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt
deleted file mode 100644
index 2a2d33308d12..000000000000
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2024 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.shared.clocks
-
-import android.content.Context
-import android.content.res.Resources
-import android.graphics.Typeface
-import android.graphics.drawable.Drawable
-import android.util.TypedValue
-import com.android.internal.policy.SystemBarUtils
-import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
-import com.android.systemui.monet.Style as MonetStyle
-import java.io.IOException
-
-class AssetLoader
-private constructor(
- private val pluginCtx: Context,
- private val sysuiCtx: Context,
- private val baseDir: String,
- var seedColor: Int?,
- var overrideChroma: Float?,
- val typefaceCache: TypefaceCache,
- messageBuffer: MessageBuffer,
-) {
- val logger = Logger(messageBuffer, TAG)
- private val resources =
- listOf(
- Pair(pluginCtx.resources, pluginCtx.packageName),
- Pair(sysuiCtx.resources, sysuiCtx.packageName),
- )
-
- constructor(
- pluginCtx: Context,
- sysuiCtx: Context,
- baseDir: String,
- messageBuffer: MessageBuffer,
- ) : this(
- pluginCtx,
- sysuiCtx,
- baseDir,
- seedColor = null,
- overrideChroma = null,
- typefaceCache =
- TypefaceCache(messageBuffer) {
- // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
- return@TypefaceCache Typeface.create("google-sans-flex-clock", Typeface.NORMAL)
- },
- messageBuffer = messageBuffer,
- )
-
- fun listAssets(path: String): List<String> {
- return pluginCtx.resources.assets.list("$baseDir$path")?.toList() ?: emptyList()
- }
-
- fun tryReadString(resStr: String): String? = tryRead(resStr, ::readString)
-
- fun readString(resStr: String): String {
- val resPair = resolveResourceId(resStr)
- if (resPair == null) {
- throw IOException("Failed to parse string: $resStr")
- }
-
- val (res, id) = resPair
- return res.getString(id)
- }
-
- fun readFontAsset(resStr: String): Typeface = typefaceCache.getTypeface(resStr)
-
- fun tryReadTextAsset(path: String?): String? = tryRead(path, ::readTextAsset)
-
- fun readTextAsset(path: String): String {
- return pluginCtx.resources.assets.open("$baseDir$path").use { stream ->
- val buffer = ByteArray(stream.available())
- stream.read(buffer)
- String(buffer)
- }
- }
-
- fun tryReadDrawableAsset(path: String?): Drawable? = tryRead(path, ::readDrawableAsset)
-
- fun readDrawableAsset(path: String): Drawable {
- var result: Drawable?
-
- if (path.startsWith("@")) {
- val pair = resolveResourceId(path)
- if (pair == null) {
- throw IOException("Failed to parse $path to an id")
- }
- val (res, id) = pair
- result = res.getDrawable(id)
- } else if (path.endsWith("xml")) {
- // TODO(b/248609434): Support xml files in assets
- throw IOException("Cannot load xml files from assets")
- } else {
- // Attempt to load as if it's a bitmap and directly loadable
- result =
- pluginCtx.resources.assets.open("$baseDir$path").use { stream ->
- Drawable.createFromResourceStream(
- pluginCtx.resources,
- TypedValue(),
- stream,
- null,
- )
- }
- }
-
- return result ?: throw IOException("Failed to load: $baseDir$path")
- }
-
- fun parseResourceId(resStr: String): Triple<String?, String, String> {
- if (!resStr.startsWith("@")) {
- throw IOException("Invalid resource id: $resStr; Must start with '@'")
- }
-
- // Parse out resource string
- val parts = resStr.drop(1).split('/', ':')
- return when (parts.size) {
- 2 -> Triple(null, parts[0], parts[1])
- 3 -> Triple(parts[0], parts[1], parts[2])
- else -> throw IOException("Failed to parse resource string: $resStr")
- }
- }
-
- fun resolveResourceId(resStr: String): Pair<Resources, Int>? {
- val (packageName, category, name) = parseResourceId(resStr)
- return resolveResourceId(packageName, category, name)
- }
-
- fun resolveResourceId(
- packageName: String?,
- category: String,
- name: String,
- ): Pair<Resources, Int>? {
- for ((res, ctxPkgName) in resources) {
- val result = res.getIdentifier(name, category, packageName ?: ctxPkgName)
- if (result != 0) {
- return Pair(res, result)
- }
- }
- return null
- }
-
- private fun <TArg : Any, TRes : Any> tryRead(arg: TArg?, fn: (TArg) -> TRes): TRes? {
- try {
- if (arg == null) {
- return null
- }
- return fn(arg)
- } catch (ex: IOException) {
- logger.w("Failed to read $arg", ex)
- return null
- }
- }
-
- fun assetExists(path: String): Boolean {
- try {
- if (path.startsWith("@")) {
- val pair = resolveResourceId(path)
- return pair != null
- } else {
- val stream = pluginCtx.resources.assets.open("$baseDir$path")
- if (stream == null) {
- return false
- }
-
- stream.close()
- return true
- }
- } catch (ex: IOException) {
- return false
- }
- }
-
- fun copy(messageBuffer: MessageBuffer? = null): AssetLoader =
- AssetLoader(
- pluginCtx,
- sysuiCtx,
- baseDir,
- seedColor,
- overrideChroma,
- typefaceCache,
- messageBuffer ?: logger.buffer,
- )
-
- fun setSeedColor(seedColor: Int?, style: MonetStyle?) {
- this.seedColor = seedColor
- }
-
- fun getClockPaddingStart(): Int {
- val result = resolveResourceId(null, "dimen", "clock_padding_start")
- if (result != null) {
- val (res, id) = result
- return res.getDimensionPixelSize(id)
- }
- return -1
- }
-
- fun getStatusBarHeight(): Int {
- val display = pluginCtx.getDisplayNoVerify()
- if (display != null) {
- return SystemBarUtils.getStatusBarHeight(pluginCtx.resources, display.cutout)
- }
-
- logger.w("No display available; falling back to android.R.dimen.status_bar_height")
- val statusBarHeight = resolveResourceId("android", "dimen", "status_bar_height")
- if (statusBarHeight != null) {
- val (res, resId) = statusBarHeight
- return res.getDimensionPixelSize(resId)
- }
-
- throw Exception("Could not fetch StatusBarHeight")
- }
-
- fun getResourcesId(name: String): Int = getResource("id", name) { _, id -> id }
-
- fun getDimen(name: String): Int = getResource("dimen", name, Resources::getDimensionPixelSize)
-
- fun getString(name: String): String = getResource("string", name, Resources::getString)
-
- private fun <T> getResource(
- category: String,
- name: String,
- getter: (res: Resources, id: Int) -> T,
- ): T {
- val result = resolveResourceId(null, category, name)
- if (result != null) {
- val (res, id) = result
- if (id == -1) throw Exception("Cannot find id of $id from $TAG")
- return getter(res, id)
- }
- throw Exception("Cannot find id of $name from $TAG")
- }
-
- companion object {
- private val TAG = AssetLoader::class.simpleName!!
- }
-}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
index 4ed8fd8f631d..d0a32dcf9865 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
@@ -16,12 +16,9 @@
package com.android.systemui.shared.clocks
-import android.content.Context
-import android.content.res.Resources
import android.graphics.Rect
import androidx.annotation.VisibleForTesting
import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.clocks.AlarmData
import com.android.systemui.plugins.clocks.ClockAnimations
import com.android.systemui.plugins.clocks.ClockEvents
@@ -37,31 +34,22 @@ import java.util.Locale
import java.util.TimeZone
class ComposedDigitalLayerController(
- private val ctx: Context,
- private val resources: Resources,
- private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+ private val clockCtx: ClockContext,
private val layer: ComposedDigitalHandLayer,
- messageBuffer: MessageBuffer,
) : SimpleClockLayerController {
- private val logger = Logger(messageBuffer, ComposedDigitalLayerController::class.simpleName!!)
+ private val logger =
+ Logger(clockCtx.messageBuffer, ComposedDigitalLayerController::class.simpleName!!)
val layerControllers = mutableListOf<SimpleClockLayerController>()
val dozeState = DefaultClockController.AnimationState(1F)
- override val view = FlexClockView(ctx, assets, messageBuffer)
+ override val view = FlexClockView(clockCtx)
init {
layer.digitalLayers.forEach {
- val childView = SimpleDigitalClockTextView(ctx, messageBuffer)
+ val childView = SimpleDigitalClockTextView(clockCtx)
val controller =
- SimpleDigitalHandLayerController(
- ctx,
- resources,
- assets,
- it as DigitalHandLayer,
- childView,
- messageBuffer,
- )
+ SimpleDigitalHandLayerController(clockCtx, it as DigitalHandLayer, childView)
view.addView(childView)
layerControllers.add(controller)
@@ -156,8 +144,9 @@ class ComposedDigitalLayerController(
val color =
when {
theme.seedColor != null -> theme.seedColor!!
- theme.isDarkTheme -> resources.getColor(android.R.color.system_accent1_100)
- else -> resources.getColor(android.R.color.system_accent2_600)
+ theme.isDarkTheme ->
+ clockCtx.resources.getColor(android.R.color.system_accent1_100)
+ else -> clockCtx.resources.getColor(android.R.color.system_accent2_600)
}
view.updateColor(color)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index be4ebdfcb992..e8987257bb47 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -15,10 +15,10 @@ package com.android.systemui.shared.clocks
import android.content.Context
import android.content.res.Resources
+import android.graphics.Typeface
import android.view.LayoutInflater
import com.android.systemui.customization.R
-import com.android.systemui.log.core.LogLevel
-import com.android.systemui.log.core.LogcatOnlyMessageBuffer
+import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFontAxis
import com.android.systemui.plugins.clocks.ClockFontAxisSetting
@@ -33,6 +33,15 @@ import com.android.systemui.shared.clocks.view.VerticalAlignment
private val TAG = DefaultClockProvider::class.simpleName
const val DEFAULT_CLOCK_ID = "DEFAULT"
+data class ClockContext(
+ val context: Context,
+ val resources: Resources,
+ val settings: ClockSettings,
+ val typefaceCache: TypefaceCache,
+ val messageBuffers: ClockMessageBuffers,
+ val messageBuffer: MessageBuffer,
+)
+
/** Provides the default system clock */
class DefaultClockProvider(
val ctx: Context,
@@ -55,18 +64,23 @@ class DefaultClockProvider(
}
return if (isClockReactiveVariantsEnabled) {
- val buffer =
- messageBuffers?.infraMessageBuffer ?: LogcatOnlyMessageBuffer(LogLevel.INFO)
- val assets = AssetLoader(ctx, ctx, "clocks/", buffer)
- assets.setSeedColor(settings.seedColor, null)
+ val buffers = messageBuffers ?: ClockMessageBuffers(LogUtil.DEFAULT_MESSAGE_BUFFER)
val fontAxes = ClockFontAxis.merge(FlexClockController.FONT_AXES, settings.axes)
+ val clockSettings = settings.copy(axes = fontAxes.map { it.toSetting() })
+ val typefaceCache =
+ TypefaceCache(buffers.infraMessageBuffer, NUM_CLOCK_FONT_ANIMATION_STEPS) {
+ FLEX_TYPEFACE
+ }
FlexClockController(
- ctx,
- resources,
- settings.copy(axes = fontAxes.map { it.toSetting() }),
- assets,
+ ClockContext(
+ ctx,
+ resources,
+ clockSettings,
+ typefaceCache,
+ buffers,
+ buffers.infraMessageBuffer,
+ ),
FLEX_DESIGN,
- messageBuffers,
)
} else {
DefaultClockController(
@@ -99,6 +113,8 @@ class DefaultClockProvider(
}
companion object {
+ const val NUM_CLOCK_FONT_ANIMATION_STEPS = 30
+
// TODO(b/364681643): Variations for retargetted DIGITAL_CLOCK_FLEX
val LEGACY_FLEX_LS_VARIATION =
listOf(
@@ -116,6 +132,11 @@ class DefaultClockProvider(
ClockFontAxisSetting("slnt", 0f),
)
+ val FLEX_TYPEFACE by lazy {
+ // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
+ Typeface.create("google-sans-flex-clock", Typeface.NORMAL)
+ }
+
val FLEX_DESIGN = run {
val largeLayer =
listOf(
@@ -139,7 +160,7 @@ class DefaultClockProvider(
alignment =
DigitalAlignment(
HorizontalAlignment.CENTER,
- VerticalAlignment.CENTER,
+ VerticalAlignment.BASELINE,
),
dateTimeFormat = "hh",
),
@@ -158,7 +179,7 @@ class DefaultClockProvider(
alignment =
DigitalAlignment(
HorizontalAlignment.CENTER,
- VerticalAlignment.CENTER,
+ VerticalAlignment.BASELINE,
),
dateTimeFormat = "hh",
),
@@ -177,7 +198,7 @@ class DefaultClockProvider(
alignment =
DigitalAlignment(
HorizontalAlignment.CENTER,
- VerticalAlignment.CENTER,
+ VerticalAlignment.BASELINE,
),
dateTimeFormat = "mm",
),
@@ -196,7 +217,7 @@ class DefaultClockProvider(
alignment =
DigitalAlignment(
HorizontalAlignment.CENTER,
- VerticalAlignment.CENTER,
+ VerticalAlignment.BASELINE,
),
dateTimeFormat = "mm",
),
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index 6c627e27a19b..c7a3f63e92e7 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -16,8 +16,6 @@
package com.android.systemui.shared.clocks
-import android.content.Context
-import android.content.res.Resources
import com.android.systemui.customization.R
import com.android.systemui.plugins.clocks.AlarmData
import com.android.systemui.plugins.clocks.AxisType
@@ -26,8 +24,6 @@ import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockEvents
import com.android.systemui.plugins.clocks.ClockFontAxis
import com.android.systemui.plugins.clocks.ClockFontAxisSetting
-import com.android.systemui.plugins.clocks.ClockMessageBuffers
-import com.android.systemui.plugins.clocks.ClockSettings
import com.android.systemui.plugins.clocks.ThemeConfig
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.plugins.clocks.ZenData
@@ -38,42 +34,28 @@ import java.util.TimeZone
/** Controller for the default flex clock */
class FlexClockController(
- private val ctx: Context,
- private val resources: Resources,
- private val settings: ClockSettings,
- private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+ private val clockCtx: ClockContext,
val design: ClockDesign, // TODO(b/364680879): Remove when done inlining
- val messageBuffers: ClockMessageBuffers?,
) : ClockController {
- override val smallClock = run {
- val buffer = messageBuffers?.smallClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
+ override val smallClock =
FlexClockFaceController(
- ctx,
- resources,
- assets.copy(messageBuffer = buffer),
+ clockCtx.copy(messageBuffer = clockCtx.messageBuffers.smallClockMessageBuffer),
design.small ?: design.large!!,
- false,
- buffer,
+ isLargeClock = false,
)
- }
- override val largeClock = run {
- val buffer = messageBuffers?.largeClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
+ override val largeClock =
FlexClockFaceController(
- ctx,
- resources,
- assets.copy(messageBuffer = buffer),
+ clockCtx.copy(messageBuffer = clockCtx.messageBuffers.largeClockMessageBuffer),
design.large ?: design.small!!,
- true,
- buffer,
+ isLargeClock = true,
)
- }
override val config: ClockConfig by lazy {
ClockConfig(
DEFAULT_CLOCK_ID,
- resources.getString(R.string.clock_default_name),
- resources.getString(R.string.clock_default_description),
+ clockCtx.resources.getString(R.string.clock_default_name),
+ clockCtx.resources.getString(R.string.clock_default_description),
isReactiveToTone = true,
)
}
@@ -125,8 +107,8 @@ class FlexClockController(
}
override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) {
- val theme = ThemeConfig(isDarkTheme, assets.seedColor)
- events.onFontAxesChanged(settings.axes)
+ val theme = ThemeConfig(isDarkTheme, clockCtx.settings.seedColor)
+ events.onFontAxesChanged(clockCtx.settings.axes)
smallClock.run {
events.onThemeChanged(theme)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
index ee21ea6ee126..a8890e6aa934 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
@@ -16,15 +16,12 @@
package com.android.systemui.shared.clocks
-import android.content.Context
-import android.content.res.Resources
import android.graphics.Rect
import android.view.Gravity
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import com.android.systemui.customization.R
-import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.clocks.AlarmData
import com.android.systemui.plugins.clocks.ClockAnimations
import com.android.systemui.plugins.clocks.ClockEvents
@@ -45,22 +42,19 @@ import kotlin.math.max
// TODO(b/364680879): Merge w/ ComposedDigitalLayerController
class FlexClockFaceController(
- ctx: Context,
- private val resources: Resources,
- val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+ clockCtx: ClockContext,
face: ClockFace,
private val isLargeClock: Boolean,
- messageBuffer: MessageBuffer,
) : ClockFaceController {
override val view: View
get() = layerController.view
override val config = ClockFaceConfig(hasCustomPositionUpdatedAnimation = true)
- override var theme = ThemeConfig(true, assets.seedColor)
+ override var theme = ThemeConfig(true, clockCtx.settings.seedColor)
private val keyguardLargeClockTopMargin =
- resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin)
+ clockCtx.resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin)
val layerController: SimpleClockLayerController
val timespecHandler = DigitalTimespecHandler(DigitalTimespec.TIME_FULL_FORMAT, "hh:mm")
@@ -72,23 +66,10 @@ class FlexClockFaceController(
layerController =
if (isLargeClock) {
- ComposedDigitalLayerController(
- ctx,
- resources,
- assets,
- layer as ComposedDigitalHandLayer,
- messageBuffer,
- )
+ ComposedDigitalLayerController(clockCtx, layer as ComposedDigitalHandLayer)
} else {
- val childView = SimpleDigitalClockTextView(ctx, messageBuffer)
- SimpleDigitalHandLayerController(
- ctx,
- resources,
- assets,
- layer as DigitalHandLayer,
- childView,
- messageBuffer,
- )
+ val childView = SimpleDigitalClockTextView(clockCtx)
+ SimpleDigitalHandLayerController(clockCtx, layer as DigitalHandLayer, childView)
}
layerController.view.layoutParams = lp
}
@@ -97,7 +78,7 @@ class FlexClockFaceController(
private fun offsetGlyphsForStepClockAnimation(
clockStartLeft: Int,
direction: Int,
- fraction: Float
+ fraction: Float,
) {
(view as? FlexClockView)?.offsetGlyphsForStepClockAnimation(
clockStartLeft,
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
index 143b28f1e82b..ebac4b24732b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -16,8 +16,6 @@
package com.android.systemui.shared.clocks
-import android.content.Context
-import android.content.res.Resources
import android.graphics.Rect
import android.view.View
import android.view.ViewGroup
@@ -25,7 +23,6 @@ import android.widget.RelativeLayout
import androidx.annotation.VisibleForTesting
import com.android.systemui.customization.R
import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.clocks.AlarmData
import com.android.systemui.plugins.clocks.ClockAnimations
import com.android.systemui.plugins.clocks.ClockEvents
@@ -42,14 +39,11 @@ import java.util.TimeZone
private val TAG = SimpleDigitalHandLayerController::class.simpleName!!
open class SimpleDigitalHandLayerController<T>(
- private val ctx: Context,
- private val resources: Resources,
- private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+ private val clockCtx: ClockContext,
private val layer: DigitalHandLayer,
override val view: T,
- messageBuffer: MessageBuffer,
) : SimpleClockLayerController where T : View, T : SimpleDigitalClockView {
- private val logger = Logger(messageBuffer, TAG)
+ private val logger = Logger(clockCtx.messageBuffer, TAG)
val timespec = DigitalTimespecHandler(layer.timespec, layer.dateTimeFormat)
@VisibleForTesting
@@ -75,12 +69,12 @@ open class SimpleDigitalHandLayerController<T>(
layer.alignment.verticalAlignment?.let { view.verticalAlignment = it }
layer.alignment.horizontalAlignment?.let { view.horizontalAlignment = it }
}
- view.applyStyles(assets, layer.style, layer.aodStyle)
+ view.applyStyles(layer.style, layer.aodStyle)
view.id =
- ctx.resources.getIdentifier(
+ clockCtx.resources.getIdentifier(
generateDigitalLayerIdString(layer),
"id",
- ctx.getPackageName(),
+ clockCtx.context.getPackageName(),
)
}
@@ -306,8 +300,9 @@ open class SimpleDigitalHandLayerController<T>(
val color =
when {
theme.seedColor != null -> theme.seedColor!!
- theme.isDarkTheme -> resources.getColor(android.R.color.system_accent1_100)
- else -> resources.getColor(android.R.color.system_accent2_600)
+ theme.isDarkTheme ->
+ clockCtx.resources.getColor(android.R.color.system_accent1_100)
+ else -> clockCtx.resources.getColor(android.R.color.system_accent2_600)
}
view.updateColor(color)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TypefaceCache.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TypefaceCache.kt
index f5a9375122b5..9e3f6d9677df 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TypefaceCache.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TypefaceCache.kt
@@ -17,13 +17,18 @@
package com.android.systemui.shared.clocks
import android.graphics.Typeface
+import com.android.systemui.animation.FontCacheImpl
import com.android.systemui.animation.TypefaceVariantCache
import com.android.systemui.log.core.Logger
import com.android.systemui.log.core.MessageBuffer
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference
-class TypefaceCache(messageBuffer: MessageBuffer, val typefaceFactory: (String) -> Typeface) {
+class TypefaceCache(
+ messageBuffer: MessageBuffer,
+ val animationFrameCount: Int,
+ val typefaceFactory: (String) -> Typeface,
+) {
private val logger = Logger(messageBuffer, this::class.simpleName!!)
private data class CacheKey(val res: String, val fvar: String?)
@@ -44,6 +49,7 @@ class TypefaceCache(messageBuffer: MessageBuffer, val typefaceFactory: (String)
// result, once a typeface is no longer being used, it is unlikely to be recreated immediately.
private val cache = mutableMapOf<CacheKey, WeakTypefaceRef>()
private val queue = ReferenceQueue<Typeface>()
+ private val fontCache = FontCacheImpl(animationFrameCount)
fun getTypeface(res: String): Typeface {
checkQueue()
@@ -62,6 +68,9 @@ class TypefaceCache(messageBuffer: MessageBuffer, val typefaceFactory: (String)
fun getVariantCache(res: String): TypefaceVariantCache {
val baseTypeface = getTypeface(res)
return object : TypefaceVariantCache {
+ override val fontCache = this@TypefaceCache.fontCache
+ override val animationFrameCount = this@TypefaceCache.animationFrameCount
+
override fun getTypefaceForVariant(fvar: String?): Typeface? {
checkQueue()
val key = CacheKey(res, fvar)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
index b09332f34e99..d4eb7677c757 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
@@ -16,24 +16,23 @@
package com.android.systemui.shared.clocks.view
-import android.content.Context
import android.graphics.Canvas
import android.graphics.Point
import android.view.View
import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.clocks.AlarmData
import com.android.systemui.plugins.clocks.ClockFontAxisSetting
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.ClockContext
import com.android.systemui.shared.clocks.LogUtil
import java.util.Locale
// TODO(b/364680879): Merge w/ only subclass FlexClockView
-abstract class DigitalClockFaceView(ctx: Context, messageBuffer: MessageBuffer) : FrameLayout(ctx) {
- protected val logger = Logger(messageBuffer, this::class.simpleName!!)
+abstract class DigitalClockFaceView(clockCtx: ClockContext) : FrameLayout(clockCtx.context) {
+ protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!)
get() = field ?: LogUtil.FALLBACK_INIT_LOGGER
abstract var digitalClockTextViewMap: MutableMap<Int, SimpleDigitalClockTextView>
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index 593eba9d05cc..faef18c1e85a 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
@@ -16,31 +16,34 @@
package com.android.systemui.shared.clocks.view
-import android.content.Context
import android.graphics.Canvas
import android.graphics.Point
+import android.icu.text.NumberFormat
import android.util.MathUtils.constrainedMap
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import com.android.app.animation.Interpolators
import com.android.systemui.customization.R
-import com.android.systemui.log.core.MessageBuffer
-import com.android.systemui.shared.clocks.AssetLoader
+import com.android.systemui.shared.clocks.ClockContext
import com.android.systemui.shared.clocks.DigitTranslateAnimator
+import java.util.Locale
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
fun clamp(value: Float, minVal: Float, maxVal: Float): Float = max(min(value, maxVal), minVal)
-class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: MessageBuffer) :
- DigitalClockFaceView(context, messageBuffer) {
+class FlexClockView(clockCtx: ClockContext) : DigitalClockFaceView(clockCtx) {
override var digitalClockTextViewMap = mutableMapOf<Int, SimpleDigitalClockTextView>()
- val digitLeftTopMap = mutableMapOf<Int, Point>()
- var maxSingleDigitSize = Point(-1, -1)
- val lockscreenTranslate = Point(0, 0)
- var aodTranslate = Point(0, 0)
+ private val digitLeftTopMap = mutableMapOf<Int, Point>()
+
+ private var maxSingleDigitSize = Point(-1, -1)
+ private val lockscreenTranslate = Point(0, 0)
+ private var aodTranslate = Point(0, 0)
+
+ // Does the current language have mono vertical size when displaying numerals
+ private var isMonoVerticalNumericLineSpacing = true
init {
setWillNotDraw(false)
@@ -49,6 +52,7 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
)
+ updateLocale(Locale.getDefault())
}
private val digitOffsets = mutableMapOf<Int, Float>()
@@ -61,12 +65,19 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me
protected override fun calculateSize(widthMeasureSpec: Int, heightMeasureSpec: Int): Point {
maxSingleDigitSize = Point(-1, -1)
+ val bottomLocation: (textView: SimpleDigitalClockTextView) -> Int = { textView ->
+ if (isMonoVerticalNumericLineSpacing) {
+ maxSingleDigitSize.y
+ } else {
+ (textView.paint.fontMetrics.descent - textView.paint.fontMetrics.ascent).toInt()
+ }
+ }
+
digitalClockTextViewMap.forEach { (_, textView) ->
textView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
maxSingleDigitSize.x = max(maxSingleDigitSize.x, textView.measuredWidth)
- maxSingleDigitSize.y = max(maxSingleDigitSize.y, textView.measuredHeight)
+ maxSingleDigitSize.y = max(bottomLocation(textView), textView.measuredHeight)
}
- val textView = digitalClockTextViewMap[R.id.HOUR_FIRST_DIGIT]!!
aodTranslate = Point(0, 0)
return Point(
((maxSingleDigitSize.x + abs(aodTranslate.x)) * 2),
@@ -106,6 +117,11 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me
}
}
+ override fun onLocaleChanged(locale: Locale) {
+ updateLocale(locale)
+ requestLayout()
+ }
+
override fun animateDoze(isDozing: Boolean, isAnimated: Boolean) {
dozeControlState.animateDoze = {
super.animateDoze(isDozing, isAnimated)
@@ -166,6 +182,18 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me
}
}
+ private fun updateLocale(locale: Locale) {
+ isMonoVerticalNumericLineSpacing =
+ !NON_MONO_VERTICAL_NUMERIC_LINE_SPACING_LANGUAGES.any {
+ val newLocaleNumberFormat =
+ NumberFormat.getInstance(locale).format(FORMAT_NUMBER.toLong())
+ val nonMonoVerticalNumericLineSpaceNumberFormat =
+ NumberFormat.getInstance(Locale.forLanguageTag(it))
+ .format(FORMAT_NUMBER.toLong())
+ newLocaleNumberFormat == nonMonoVerticalNumericLineSpaceNumberFormat
+ }
+ }
+
/**
* Offsets the textViews of the clock for the step clock animation.
*
@@ -264,10 +292,18 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me
// Constants for the animation
private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED
+ private const val FORMAT_NUMBER = 1234567890
+
// Total available transition time for each digit, taking into account the step. If step is
// 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7.
private const val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1)
+ // Add language tags below that do not have vertically mono spaced numerals
+ private val NON_MONO_VERTICAL_NUMERIC_LINE_SPACING_LANGUAGES =
+ setOf(
+ "my", // Burmese
+ )
+
// Use the sign of targetTranslation to control the direction of digit translation
fun updateDirectionalTargetTranslate(id: Int, targetTranslation: Point): Point {
val outPoint = Point(targetTranslation)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index 5c84f2d04ccc..cef24e99084e 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -17,7 +17,6 @@
package com.android.systemui.shared.clocks.view
import android.annotation.SuppressLint
-import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
@@ -37,13 +36,10 @@ import android.view.animation.Interpolator
import android.widget.TextView
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.TextAnimator
-import com.android.systemui.animation.TypefaceVariantCache
import com.android.systemui.customization.R
import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.clocks.ClockFontAxisSetting
-import com.android.systemui.shared.clocks.AssetLoader
-import com.android.systemui.shared.clocks.ClockAnimation
+import com.android.systemui.shared.clocks.ClockContext
import com.android.systemui.shared.clocks.DigitTranslateAnimator
import com.android.systemui.shared.clocks.DimensionParser
import com.android.systemui.shared.clocks.FontTextStyle
@@ -57,18 +53,15 @@ import kotlin.math.min
private val TAG = SimpleDigitalClockTextView::class.simpleName!!
@SuppressLint("AppCompatCustomView")
-open class SimpleDigitalClockTextView(
- ctx: Context,
- messageBuffer: MessageBuffer,
- attrs: AttributeSet? = null,
-) : TextView(ctx, attrs), SimpleDigitalClockView {
+open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSet? = null) :
+ TextView(clockCtx.context, attrs), SimpleDigitalClockView {
val lockScreenPaint = TextPaint()
override lateinit var textStyle: FontTextStyle
lateinit var aodStyle: FontTextStyle
private var lsFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_LS_VARIATION)
private var aodFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_AOD_VARIATION)
- private val parser = DimensionParser(ctx)
+ private val parser = DimensionParser(clockCtx.context)
var maxSingleDigitHeight = -1
var maxSingleDigitWidth = -1
var digitTranslateAnimator: DigitTranslateAnimator? = null
@@ -91,33 +84,21 @@ open class SimpleDigitalClockTextView(
private val prevTextBounds = Rect()
// targetTextBounds holds the state we are interpolating to
private val targetTextBounds = Rect()
- protected val logger = Logger(messageBuffer, this::class.simpleName!!)
+ protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!)
get() = field ?: LogUtil.FALLBACK_INIT_LOGGER
private var aodDozingInterpolator: Interpolator? = null
@VisibleForTesting lateinit var textAnimator: TextAnimator
- lateinit var typefaceCache: TypefaceVariantCache
- private set
-
- private fun setTypefaceCache(value: TypefaceVariantCache) {
- typefaceCache = value
- if (this::textAnimator.isInitialized) {
- textAnimator.typefaceCache = value
- }
- }
+ private val typefaceCache = clockCtx.typefaceCache.getVariantCache("")
@VisibleForTesting
var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = { layout, invalidateCb ->
- TextAnimator(layout, ClockAnimation.NUM_CLOCK_FONT_ANIMATION_STEPS, invalidateCb).also {
- if (this::typefaceCache.isInitialized) {
- it.typefaceCache = typefaceCache
- }
- }
+ TextAnimator(layout, typefaceCache, invalidateCb)
}
- override var verticalAlignment: VerticalAlignment = VerticalAlignment.CENTER
+ override var verticalAlignment: VerticalAlignment = VerticalAlignment.BASELINE
override var horizontalAlignment: HorizontalAlignment = HorizontalAlignment.LEFT
override var isAnimationEnabled = true
override var dozeFraction: Float = 0F
@@ -258,7 +239,7 @@ open class SimpleDigitalClockTextView(
-translation.y.toFloat(),
(-translation.x + measuredWidth).toFloat(),
(-translation.y + measuredHeight).toFloat(),
- Paint().also { it.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) },
+ PORTER_DUFF_XFER_MODE_PAINT,
)
canvas.restore()
canvas.restore()
@@ -403,7 +384,7 @@ open class SimpleDigitalClockTextView(
// translation of reference point of text
// used for translation when calling textInterpolator
- fun getLocalTranslation(): Point {
+ private fun getLocalTranslation(): Point {
val viewHeight = if (isVertical) measuredWidth else measuredHeight
val interpolatedTextBounds = updateInterpolatedTextBounds()
val localTranslation = Point(0, 0)
@@ -429,17 +410,18 @@ open class SimpleDigitalClockTextView(
correctedBaseline
}
VerticalAlignment.BASELINE -> {
- localTranslation.y = -lockScreenPaint.strokeWidth.toInt()
+ // account for max bottom distance of font, so clock doesn't collide with elements
+ localTranslation.y =
+ -lockScreenPaint.strokeWidth.toInt() - paint.fontMetrics.descent.toInt()
}
}
return updateXtranslation(localTranslation, interpolatedTextBounds)
}
- override fun applyStyles(assets: AssetLoader, textStyle: TextStyle, aodStyle: TextStyle?) {
+ override fun applyStyles(textStyle: TextStyle, aodStyle: TextStyle?) {
this.textStyle = textStyle as FontTextStyle
val typefaceName = "fonts/" + textStyle.fontFamily
- setTypefaceCache(assets.typefaceCache.getVariantCache(typefaceName))
lockScreenPaint.strokeJoin = Paint.Join.ROUND
lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation)
textStyle.fontFeatureSettings?.let {
@@ -550,7 +532,9 @@ open class SimpleDigitalClockTextView(
}
companion object {
- val AOD_STROKE_WIDTH = "2dp"
+ private val PORTER_DUFF_XFER_MODE_PAINT =
+ Paint().also { it.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) }
+
val AOD_COLOR = Color.WHITE
val OPTICAL_SIZE_AXIS = ClockFontAxisSetting("opsz", 144f)
val DEFAULT_LS_VARIATION =
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt
index 3d2ed4a1ef40..e8be28fb8df2 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt
@@ -18,7 +18,6 @@ package com.android.systemui.shared.clocks.view
import androidx.annotation.VisibleForTesting
import com.android.systemui.plugins.clocks.ClockFontAxisSetting
-import com.android.systemui.shared.clocks.AssetLoader
import com.android.systemui.shared.clocks.TextStyle
interface SimpleDigitalClockView {
@@ -29,7 +28,7 @@ interface SimpleDigitalClockView {
val textStyle: TextStyle
@VisibleForTesting var isAnimationEnabled: Boolean
- fun applyStyles(assets: AssetLoader, textStyle: TextStyle, aodStyle: TextStyle?)
+ fun applyStyles(textStyle: TextStyle, aodStyle: TextStyle?)
fun applyTextSize(targetFontSizePx: Float?, constrainedByHeight: Boolean = false)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt
index 57a67973f34f..85bdf9264467 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt
@@ -28,7 +28,7 @@ import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.navigationbar.NavigationBarController
import com.android.systemui.settings.FakeDisplayTracker
-import com.android.systemui.shade.data.repository.FakeShadePositionRepository
+import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository
import com.android.systemui.statusbar.policy.KeyguardStateController
import java.util.concurrent.Executor
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -62,7 +62,7 @@ class KeyguardDisplayManagerTest : SysuiTestCase() {
mock(ConnectedDisplayKeyguardPresentation::class.java)
@Mock private val deviceStateHelper = mock(DeviceStateHelper::class.java)
@Mock private val keyguardStateController = mock(KeyguardStateController::class.java)
- private val shadePositionRepository = FakeShadePositionRepository()
+ private val shadePositionRepository = FakeShadeDisplayRepository()
private val mainExecutor = Executor { it.run() }
private val backgroundExecutor = Executor { it.run() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/BatteryMeterDrawableTest.java
index d6a5b4b11521..d6a5b4b11521 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/BatteryMeterDrawableTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/BootCompleteCacheTest.kt
index 0a9ce6854ca8..0a9ce6854ca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/BootCompleteCacheTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
index a23e82918845..a23e82918845 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
index a01fecaaaefe..a01fecaaaefe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FakeCameraProtectionLoader.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/FakeCameraProtectionLoader.kt
index 6cb77cff4404..6cb77cff4404 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/FakeCameraProtectionLoader.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/FakeCameraProtectionLoader.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
index fb60ba381c40..fb60ba381c40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManagerTest.kt
index b7b98d41da93..9f9245c39e5f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManagerTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.accessibility.extradim
+import android.os.Handler
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -25,8 +26,10 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.eq
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@@ -43,21 +46,30 @@ class ExtraDimDialogManagerTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var dialogProvider: Provider<ExtraDimDialogDelegate>
@Mock private lateinit var dialogTransitionAnimator: DialogTransitionAnimator
+ @Mock private lateinit var mainHandler: Handler
+ @Captor private lateinit var runnableCaptor: ArgumentCaptor<Runnable>
@Before
fun setUp() {
extraDimDialogManager =
- ExtraDimDialogManager(dialogProvider, activityStarter, dialogTransitionAnimator)
+ ExtraDimDialogManager(
+ dialogProvider,
+ activityStarter,
+ dialogTransitionAnimator,
+ mainHandler,
+ )
}
@Test
fun dismissKeyguardIfNeededAndShowDialog_executeRunnableDismissingKeyguard() {
extraDimDialogManager.dismissKeyguardIfNeededAndShowDialog()
+ verify(mainHandler).post(runnableCaptor.capture())
+ runnableCaptor.value.run()
verify(activityStarter)
.executeRunnableDismissingKeyguard(
any(),
/* cancelAction= */ eq(null),
- /* dismissShade= */ eq(false),
+ /* dismissShade= */ eq(true),
/* afterKeyguardGone= */ eq(true),
/* deferred= */ eq(false),
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index fcb433b5db4e..9d471f45a293 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -45,9 +45,9 @@ import android.os.Handler;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.testing.TestableLooper;
+import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
import android.widget.Space;
import android.widget.Spinner;
@@ -166,6 +166,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
when(mCachedDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true);
when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
when(mCachedDevice.isConnectedHapClientDevice()).thenReturn(true);
+ when(mCachedDevice.getDrawableWithDescription()).thenReturn(new Pair<>(mDrawable, ""));
when(mHearingDeviceItem.getCachedBluetoothDevice()).thenReturn(mCachedDevice);
mContext.setMockPackageManager(mPackageManager);
@@ -217,6 +218,18 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
@Test
@EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS)
+ public void showDialog_noLiveCaption_noRelatedToolsInConfig_relatedToolLayoutGone() {
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_quickSettingsHearingDevicesRelatedToolName, new String[]{});
+
+ setUpPairNewDeviceDialog();
+ mDialog.show();
+
+ assertToolsUi(0);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS)
public void showDialog_hasLiveCaption_noRelatedToolsInConfig_showOneRelatedTool() {
when(mPackageManager.queryIntentActivities(
eq(LIVE_CAPTION_INTENT), anyInt())).thenReturn(
@@ -227,8 +240,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
setUpPairNewDeviceDialog();
mDialog.show();
- LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog);
- assertThat(countChildWithoutSpace(relatedToolsView)).isEqualTo(1);
+ assertToolsUi(1);
}
@Test
@@ -251,8 +263,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
setUpPairNewDeviceDialog();
mDialog.show();
- LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog);
- assertThat(countChildWithoutSpace(relatedToolsView)).isEqualTo(2);
+ assertToolsUi(2);
}
@Test
@@ -263,8 +274,8 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
setUpDeviceListDialog();
mDialog.show();
- Spinner spinner = (Spinner) getPresetSpinner(mDialog);
- assertThat(spinner.getVisibility()).isEqualTo(View.GONE);
+ ViewGroup presetLayout = getPresetLayout(mDialog);
+ assertThat(presetLayout.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -276,8 +287,9 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
setUpDeviceListDialog();
mDialog.show();
- Spinner spinner = (Spinner) getPresetSpinner(mDialog);
- assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+ ViewGroup presetLayout = getPresetLayout(mDialog);
+ assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ Spinner spinner = getPresetSpinner(mDialog);
assertThat(spinner.getSelectedItemPosition()).isEqualTo(0);
}
@@ -292,8 +304,9 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
mDialogDelegate.onActiveDeviceChanged(mCachedDevice, BluetoothProfile.LE_AUDIO);
mTestableLooper.processAllMessages();
- Spinner spinner = (Spinner) getPresetSpinner(mDialog);
- assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+ ViewGroup presetLayout = getPresetLayout(mDialog);
+ assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ Spinner spinner = getPresetSpinner(mDialog);
assertThat(spinner.getSelectedItemPosition()).isEqualTo(0);
}
@@ -359,14 +372,23 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
return dialog.requireViewById(R.id.pair_new_device_button);
}
- private View getRelatedToolsView(SystemUIDialog dialog) {
- return dialog.requireViewById(R.id.related_tools_container);
+ private ViewGroup getToolsContainer(SystemUIDialog dialog) {
+ return dialog.requireViewById(R.id.tools_container);
+ }
+
+ private ViewGroup getToolsLayout(SystemUIDialog dialog) {
+ return dialog.requireViewById(R.id.tools_layout);
}
- private View getPresetSpinner(SystemUIDialog dialog) {
+ private Spinner getPresetSpinner(SystemUIDialog dialog) {
return dialog.requireViewById(R.id.preset_spinner);
}
+ private ViewGroup getPresetLayout(SystemUIDialog dialog) {
+ return dialog.requireViewById(R.id.preset_layout);
+ }
+
+
private int countChildWithoutSpace(ViewGroup viewGroup) {
int spaceCount = 0;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
@@ -377,6 +399,15 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
return viewGroup.getChildCount() - spaceCount;
}
+ private void assertToolsUi(int childCount) {
+ ViewGroup toolsContainer = getToolsContainer(mDialog);
+ assertThat(countChildWithoutSpace(toolsContainer)).isEqualTo(childCount);
+
+ int targetVisibility = childCount == 0 ? View.GONE : View.VISIBLE;
+ ViewGroup toolsLayout = getToolsLayout(mDialog);
+ assertThat(toolsLayout.getVisibility()).isEqualTo(targetVisibility);
+ }
+
@After
public void reset() {
if (mDialogDelegate != null) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
index 4809d0e4838f..d6db34949c2e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
@@ -48,6 +48,11 @@ class BackAnimationSpecTest : SysuiTestCase() {
)
assertBackTransformation(
backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 1f, progressY = 0f, edge = BackEvent.EDGE_NONE),
+ expected = BackTransformation(translateX = 0f, translateY = 0f, scale = minScale),
+ )
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
backInput = BackInput(progressX = 1f, progressY = 1f, edge = BackEvent.EDGE_LEFT),
expected = BackTransformation(translateX = -maxX, translateY = -maxY, scale = minScale),
)
@@ -77,7 +82,7 @@ class BackAnimationSpecTest : SysuiTestCase() {
translateX = Float.NaN,
translateY = Float.NaN,
scale = 1f,
- scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER
+ scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER,
),
)
assertBackTransformation(
@@ -88,7 +93,7 @@ class BackAnimationSpecTest : SysuiTestCase() {
translateX = Float.NaN,
translateY = Float.NaN,
scale = minScale,
- scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER
+ scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER,
),
)
assertBackTransformation(
@@ -99,7 +104,7 @@ class BackAnimationSpecTest : SysuiTestCase() {
translateX = Float.NaN,
translateY = Float.NaN,
scale = minScale,
- scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER
+ scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER,
),
)
assertBackTransformation(
@@ -110,7 +115,18 @@ class BackAnimationSpecTest : SysuiTestCase() {
translateX = Float.NaN,
translateY = Float.NaN,
scale = minScale,
- scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER
+ scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER,
+ ),
+ )
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 1f, progressY = 1f, edge = BackEvent.EDGE_NONE),
+ expected =
+ BackTransformation(
+ translateX = Float.NaN,
+ translateY = Float.NaN,
+ scale = minScale,
+ scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER,
),
)
}
@@ -131,7 +147,7 @@ private fun assertBackTransformation(
/* swipeEdge = */ backInput.edge,
),
progressY = backInput.progressY,
- result = actual
+ result = actual,
)
val tolerance = 0f
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
index 72163e4d7710..f82c8b0e56e0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
@@ -31,7 +31,8 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.whenever
@@ -62,7 +63,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
private val testScope = kosmos.testScope
private val clock = FakeSystemClock()
private val userRepository = FakeUserRepository()
- private val mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
+ private val mobileConnectionsRepository = kosmos.mobileConnectionsRepository
private lateinit var underTest: AuthenticationRepository
@@ -110,7 +111,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
.isEqualTo(AuthenticationMethodModel.None)
currentSecurityMode = KeyguardSecurityModel.SecurityMode.SimPin
- mobileConnectionsRepository.isAnySimSecure.value = true
+ mobileConnectionsRepository.fake.isAnySimSecure.value = true
assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Sim)
assertThat(underTest.getAuthenticationMethod()).isEqualTo(AuthenticationMethodModel.Sim)
}
@@ -199,7 +200,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
}
private fun setSecurityModeAndDispatchBroadcast(
- securityMode: KeyguardSecurityModel.SecurityMode,
+ securityMode: KeyguardSecurityModel.SecurityMode
) {
currentSecurityMode = securityMode
dispatchBroadcast()
@@ -208,23 +209,15 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
private fun dispatchBroadcast() {
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
- Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED)
+ Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
)
}
companion object {
private val USER_INFOS =
listOf(
- UserInfo(
- /* id= */ 100,
- /* name= */ "First user",
- /* flags= */ 0,
- ),
- UserInfo(
- /* id= */ 101,
- /* name= */ "Second user",
- /* flags= */ 0,
- ),
+ UserInfo(/* id= */ 100, /* name= */ "First user", /* flags= */ 0),
+ UserInfo(/* id= */ 101, /* name= */ "Second user", /* flags= */ 0),
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
index 13f2c7212e36..4e64c50a3253 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
@@ -17,22 +17,23 @@
package com.android.systemui.biometrics.domain.interactor
import android.graphics.Rect
-import android.hardware.fingerprint.FingerprintManager
import android.view.MotionEvent
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.authController
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,29 +45,25 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class UdfpsOverlayInteractorTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
- private lateinit var testScope: TestScope
+ private val kosmos = testKosmos()
- @Mock private lateinit var fingerprintManager: FingerprintManager
- @Mock private lateinit var authController: AuthController
+ private val testScope: TestScope = kosmos.testScope
+
+ private val authController: AuthController = kosmos.authController
@Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback>
@Mock private lateinit var udfpsOverlayParams: UdfpsOverlayParams
@Mock private lateinit var overlayBounds: Rect
- @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
private lateinit var underTest: UdfpsOverlayInteractor
- @Before
- fun setUp() {
- testScope = TestScope(StandardTestDispatcher())
- }
-
@Test
fun testShouldInterceptTouch() =
testScope.runTest {
@@ -107,15 +104,26 @@ class UdfpsOverlayInteractorTest : SysuiTestCase() {
assertThat(udfpsOverlayParams()).isEqualTo(firstParams)
}
+ @Test
+ fun testPaddingIsNeverNegative() =
+ testScope.runTest {
+ context.orCreateTestableResources.addOverride(R.dimen.pixel_pitch, 60.0f)
+ createUdfpsOverlayInteractor()
+ val padding by collectLastValue(underTest.iconPadding)
+ runCurrent()
+
+ verify(authController).addCallback(authControllerCallback.capture())
+
+ // Simulate the first empty udfps overlay params value.
+ authControllerCallback.value.onUdfpsLocationChanged(UdfpsOverlayParams())
+ runCurrent()
+
+ assertThat(padding).isEqualTo(0)
+ context.orCreateTestableResources.removeOverride(R.dimen.pixel_pitch)
+ }
+
private fun createUdfpsOverlayInteractor() {
- underTest =
- UdfpsOverlayInteractor(
- context,
- authController,
- selectedUserInteractor,
- fingerprintManager,
- testScope.backgroundScope
- )
+ underTest = kosmos.udfpsOverlayInteractor
testScope.runCurrent()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
index beb816cae095..32606e09a1ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.bluetooth.qsdialog
import android.bluetooth.BluetoothDevice
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.LeAudioProfile
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
@@ -48,7 +48,7 @@ import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@OptIn(ExperimentalCoroutinesApi::class)
class AudioSharingDialogViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
index 25f956574274..25f956574274 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
index c9e88136e4a0..acfe9dd45f75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
@@ -17,8 +17,8 @@ package com.android.systemui.bluetooth.qsdialog
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothLeBroadcastMetadata
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
@@ -46,7 +46,7 @@ import org.mockito.kotlin.whenever
@ExperimentalCoroutinesApi
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class AudioSharingRepositoryTest : SysuiTestCase() {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt
index f06b105a9e26..cee17c32925e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt
@@ -18,7 +18,9 @@ package com.android.systemui.bluetooth.qsdialog
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
+import android.graphics.drawable.Drawable
import android.testing.TestableLooper
+import android.util.Pair
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -64,6 +66,7 @@ class BluetoothDeviceMetadataInteractorTest : SysuiTestCase() {
@Mock private lateinit var bluetoothDevice1: BluetoothDevice
@Mock private lateinit var cachedDevice2: CachedBluetoothDevice
@Mock private lateinit var bluetoothDevice2: BluetoothDevice
+ @Mock private lateinit var drawable: Drawable
@Captor
private lateinit var argumentCaptor: ArgumentCaptor<BluetoothAdapter.OnMetadataChangedListener>
private lateinit var interactor: BluetoothDeviceMetadataInteractor
@@ -77,12 +80,14 @@ class BluetoothDeviceMetadataInteractorTest : SysuiTestCase() {
whenever(cachedDevice1.name).thenReturn(DEVICE_NAME)
whenever(cachedDevice1.address).thenReturn(DEVICE_ADDRESS)
whenever(cachedDevice1.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+ whenever(cachedDevice1.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
whenever(bluetoothDevice1.address).thenReturn(DEVICE_ADDRESS)
whenever(cachedDevice2.device).thenReturn(bluetoothDevice2)
whenever(cachedDevice2.name).thenReturn(DEVICE_NAME)
whenever(cachedDevice2.address).thenReturn(DEVICE_ADDRESS)
whenever(cachedDevice2.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+ whenever(cachedDevice2.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
whenever(bluetoothDevice2.address).thenReturn(DEVICE_ADDRESS)
interactor = bluetoothDeviceMetadataInteractor
@@ -175,14 +180,14 @@ class BluetoothDeviceMetadataInteractorTest : SysuiTestCase() {
.addOnMetadataChangedListener(
eq(bluetoothDevice1),
any(),
- argumentCaptor.capture()
+ argumentCaptor.capture(),
)
val listener = argumentCaptor.value
listener.onMetadataChanged(
bluetoothDevice1,
BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY,
- ByteArray(0)
+ ByteArray(0),
)
assertThat(update).isEqualTo(Unit)
}
@@ -203,14 +208,14 @@ class BluetoothDeviceMetadataInteractorTest : SysuiTestCase() {
.addOnMetadataChangedListener(
eq(bluetoothDevice1),
any(),
- argumentCaptor.capture()
+ argumentCaptor.capture(),
)
val listener = argumentCaptor.value
listener.onMetadataChanged(
bluetoothDevice1,
BluetoothDevice.METADATA_MODEL_NAME,
- ByteArray(0)
+ ByteArray(0),
)
assertThat(update).isNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
index 993cac721f48..993cac721f48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
index 566cd70598de..10bf5233e61e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
@@ -35,7 +35,8 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
import com.android.systemui.telephony.data.repository.fakeTelephonyRepository
import com.android.systemui.testKosmos
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
@@ -78,7 +79,7 @@ class BouncerActionButtonInteractorTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
- mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
+ mobileConnectionsRepository = kosmos.mobileConnectionsRepository.fake
overrideResource(R.string.lockscreen_emergency_call, MESSAGE_EMERGENCY_CALL)
overrideResource(R.string.lockscreen_return_to_call, MESSAGE_RETURN_TO_CALL)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
index 7cdfb0eb2451..2d093bf1630b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
@@ -25,16 +25,17 @@ import com.android.systemui.brightness.domain.interactor.brightnessPolicyEnforce
import com.android.systemui.brightness.domain.interactor.screenBrightnessInteractor
import com.android.systemui.brightness.shared.model.GammaBrightness
import com.android.systemui.brightness.shared.model.LinearBrightness
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
-import com.android.systemui.kosmos.brightnessWarningToast
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.res.R
import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor
+import com.android.systemui.settings.brightness.ui.brightnessWarningToast
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -61,6 +62,7 @@ class BrightnessSliderViewModelTest : SysuiTestCase() {
brightnessPolicyEnforcementInteractor,
sliderHapticsViewModelFactory,
brightnessMirrorShowingInteractor,
+ falsingInteractor,
supportsMirroring = true,
brightnessWarningToast,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index 1e8651683ec1..e5f0d7c6bf37 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -19,13 +19,13 @@ package com.android.systemui.communal
import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.internal.logging.uiEventLogger
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
@@ -38,6 +38,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dock.dockManager
import com.android.systemui.dock.fakeDockManager
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -47,6 +48,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notificationShadeWindowController
import com.android.systemui.statusbar.phone.centralSurfaces
import com.android.systemui.statusbar.phone.centralSurfacesOptional
@@ -65,12 +68,29 @@ import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.whenever
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(ParameterizedAndroidJunit4::class)
@EnableFlags(FLAG_COMMUNAL_HUB)
-class CommunalSceneStartableTest : SysuiTestCase() {
+class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase() {
+
+ companion object {
+ private const val SCREEN_TIMEOUT = 1000
+
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
+
private val kosmos = testKosmos()
private lateinit var underTest: CommunalSceneStartable
@@ -95,7 +115,6 @@ class CommunalSceneStartableTest : SysuiTestCase() {
keyguardInteractor = keyguardInteractor,
systemSettings = fakeSettings,
notificationShadeWindowController = notificationShadeWindowController,
- featureFlagsClassic = kosmos.fakeFeatureFlagsClassic,
applicationScope = applicationCoroutineScope,
bgScope = applicationCoroutineScope,
mainDispatcher = testDispatcher,
@@ -114,7 +133,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun keyguardGoesAway_whenLaunchingEditMode_doNotForceBlankScene() =
with(kosmos) {
testScope.runTest {
@@ -135,7 +154,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun keyguardGoesAway_whenLaunchingWidget_doNotForceBlankScene() =
with(kosmos) {
testScope.runTest {
@@ -156,7 +175,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun keyguardGoesAway_whenNotLaunchingWidget_forceBlankScene() =
with(kosmos) {
testScope.runTest {
@@ -177,7 +196,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun keyguardGoesAway_whenInEditMode_doesNotChangeScene() =
with(kosmos) {
testScope.runTest {
@@ -198,6 +217,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
@Ignore("Ignored until custom animations are implemented in b/322787129")
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun deviceDocked_forceCommunalScene() =
with(kosmos) {
testScope.runTest {
@@ -215,7 +235,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun occluded_forceBlankScene() =
with(kosmos) {
testScope.runTest {
@@ -235,7 +255,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun occluded_doesNotForceBlankSceneIfLaunchingActivityOverLockscreen() =
with(kosmos) {
testScope.runTest {
@@ -255,7 +275,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun deviceDocked_doesNotForceCommunalIfTransitioningFromCommunal() =
with(kosmos) {
testScope.runTest {
@@ -273,7 +293,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun deviceAsleep_forceBlankSceneAfterTimeout() =
with(kosmos) {
testScope.runTest {
@@ -295,7 +315,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun deviceAsleep_wakesUpBeforeTimeout_noChangeInScene() =
with(kosmos) {
testScope.runTest {
@@ -325,6 +345,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
@Ignore("Ignored until custom animations are implemented in b/322787129")
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun dockingOnLockscreen_forcesCommunal() =
with(kosmos) {
testScope.runTest {
@@ -347,6 +368,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
@Ignore("Ignored until custom animations are implemented in b/322787129")
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun dockingOnLockscreen_doesNotForceCommunalIfDreamStarts() =
with(kosmos) {
testScope.runTest {
@@ -377,6 +399,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun hubTimeout_whenDreaming_goesToBlank() =
with(kosmos) {
testScope.runTest {
@@ -394,6 +417,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun hubTimeout_notDreaming_staysOnCommunal() =
with(kosmos) {
testScope.runTest {
@@ -409,6 +433,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun hubTimeout_dreamStopped_staysOnCommunal() =
with(kosmos) {
testScope.runTest {
@@ -432,6 +457,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun hubTimeout_dreamStartedHalfway_goesToCommunal() =
with(kosmos) {
testScope.runTest {
@@ -454,6 +480,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun hubTimeout_dreamAfterInitialTimeout_goesToBlank() =
with(kosmos) {
testScope.runTest {
@@ -474,6 +501,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun hubTimeout_userActivityTriggered_resetsTimeout() =
with(kosmos) {
testScope.runTest {
@@ -501,6 +529,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun hubTimeout_screenTimeoutChanged() =
with(kosmos) {
testScope.runTest {
@@ -526,7 +555,163 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
- @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ fun hubTimeout_withSceneContainer_whenDreaming_goesToBlank() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is dreaming and on communal.
+ updateDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ fun hubTimeout_withSceneContainer_notDreaming_staysOnCommunal() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is not dreaming and on communal.
+ updateDreaming(false)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ // Scene stays as Communal
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ fun hubTimeout_withSceneContainer_dreamStopped_staysOnCommunal() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is dreaming and on communal.
+ updateDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Dream stops, timeout is cancelled and device stays on hub, because the regular
+ // screen timeout will take effect at this point.
+ updateDreaming(false)
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ fun hubTimeout_withSceneContainer_dreamStartedHalfway_goesToCommunal() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is on communal, but not dreaming.
+ updateDreaming(false)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Wait a bit, but not long enough to timeout, then start dreaming.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ updateDreaming(true)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Device times out after one screen timeout interval, dream doesn't reset timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ fun hubTimeout_withSceneContainer_dreamAfterInitialTimeout_goesToBlank() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is on communal.
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ // Device stays on the hub after the timeout since we're not dreaming.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Start dreaming.
+ updateDreaming(true)
+
+ // Hub times out immediately.
+ assertThat(scene).isEqualTo(Scenes.Dream)
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ fun hubTimeout_withSceneContainer_userActivityTriggered_resetsTimeout() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is dreaming and on communal.
+ updateDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+
+ // Send user interaction to reset timeout.
+ communalInteractor.signalUserInteraction()
+
+ // If user activity didn't reset timeout, we would have gone back to Blank by now.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Timeout happens one interval after the user interaction.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ fun hubTimeout_withSceneContainer_screenTimeoutChanged() =
+ with(kosmos) {
+ testScope.runTest {
+ fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
+
+ // Device is dreaming and on communal.
+ updateDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
+ assertThat(uiEventLoggerFake.logs.first().eventId)
+ .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
+ }
+ }
+
+ @Test
+ @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_SCENE_CONTAINER)
fun transitionFromDozingToGlanceableHub_forcesCommunal() =
with(kosmos) {
testScope.runTest {
@@ -558,8 +743,4 @@ class CommunalSceneStartableTest : SysuiTestCase() {
fakeKeyguardRepository.setDreaming(dreaming)
runCurrent()
}
-
- companion object {
- private const val SCREEN_TIMEOUT = 1000
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt
index 82918a569990..af2d7e45ee5f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt
@@ -47,20 +47,14 @@ class CommunalMetricsLoggerTest : SysuiTestCase() {
@Test
fun logAddWidget_componentNotLoggable_doNotLog() {
- underTest.logAddWidget(
- componentName = "com.green.package/my_test_widget",
- rank = 1,
- )
+ underTest.logAddWidget(componentName = "com.green.package/my_test_widget", rank = 1)
verify(statsLogProxy, never())
- .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt())
+ .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
}
@Test
fun logAddWidget_componentLoggable_logAddEvent() {
- underTest.logAddWidget(
- componentName = "com.blue.package/my_test_widget",
- rank = 1,
- )
+ underTest.logAddWidget(componentName = "com.blue.package/my_test_widget", rank = 1)
verify(statsLogProxy)
.writeCommunalHubWidgetEventReported(
SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__ADD,
@@ -71,20 +65,14 @@ class CommunalMetricsLoggerTest : SysuiTestCase() {
@Test
fun logRemoveWidget_componentNotLoggable_doNotLog() {
- underTest.logRemoveWidget(
- componentName = "com.yellow.package/my_test_widget",
- rank = 2,
- )
+ underTest.logRemoveWidget(componentName = "com.yellow.package/my_test_widget", rank = 2)
verify(statsLogProxy, never())
- .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt())
+ .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
}
@Test
fun logRemoveWidget_componentLoggable_logRemoveEvent() {
- underTest.logRemoveWidget(
- componentName = "com.red.package/my_test_widget",
- rank = 2,
- )
+ underTest.logRemoveWidget(componentName = "com.red.package/my_test_widget", rank = 2)
verify(statsLogProxy)
.writeCommunalHubWidgetEventReported(
SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__REMOVE,
@@ -95,20 +83,14 @@ class CommunalMetricsLoggerTest : SysuiTestCase() {
@Test
fun logTapWidget_componentNotLoggable_doNotLog() {
- underTest.logTapWidget(
- componentName = "com.yellow.package/my_test_widget",
- rank = 2,
- )
+ underTest.logTapWidget(componentName = "com.yellow.package/my_test_widget", rank = 2)
verify(statsLogProxy, never())
- .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt())
+ .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
}
@Test
fun logTapWidget_componentLoggable_logRemoveEvent() {
- underTest.logTapWidget(
- componentName = "com.red.package/my_test_widget",
- rank = 2,
- )
+ underTest.logTapWidget(componentName = "com.red.package/my_test_widget", rank = 2)
verify(statsLogProxy)
.writeCommunalHubWidgetEventReported(
SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__TAP,
@@ -140,4 +122,43 @@ class CommunalMetricsLoggerTest : SysuiTestCase() {
)
assertThat(statsEvents).hasSize(1)
}
+
+ @Test
+ fun logResizeWidget_componentNotLoggable_doNotLog() {
+ underTest.logResizeWidget(
+ componentName = "com.green.package/my_test_widget",
+ rank = 1,
+ spanY = 2,
+ )
+ verify(statsLogProxy, never())
+ .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
+ }
+
+ @Test
+ fun logResizeWidget_componentLoggable_logResizeEvent() {
+ underTest.logResizeWidget(
+ componentName = "com.blue.package/my_test_widget",
+ rank = 1,
+ spanY = 2,
+ )
+ verify(statsLogProxy)
+ .writeCommunalHubWidgetEventReported(
+ SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__RESIZE,
+ "com.blue.package/my_test_widget",
+ rank = 1,
+ spanY = 2,
+ )
+ }
+
+ @Test
+ fun logResizeWidget_defaultSpanY_usesDefaultValue() {
+ underTest.logResizeWidget(componentName = "com.blue.package/my_test_widget", rank = 1)
+ verify(statsLogProxy)
+ .writeCommunalHubWidgetEventReported(
+ SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__RESIZE,
+ "com.blue.package/my_test_widget",
+ rank = 1,
+ spanY = 0,
+ )
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt
index baeb2dd5aa96..0084e18f519f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt
@@ -16,38 +16,64 @@
package com.android.systemui.communal.ui.viewmodel
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class CommunalTransitionViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class CommunalTransitionViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
+
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private val communalSceneRepository = kosmos.fakeCommunalSceneRepository
+ private val sceneInteractor = kosmos.sceneInteractor
private val underTest: CommunalTransitionViewModel by lazy {
kosmos.communalTransitionViewModel
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun testIsUmoOnCommunalDuringTransitionBetweenLockscreenAndGlanceableHub() =
testScope.runTest {
@@ -61,6 +87,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() {
assertThat(isUmoOnCommunal).isFalse()
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun testIsUmoOnCommunalDuringTransitionBetweenDreamingAndGlanceableHub() =
testScope.runTest {
@@ -74,6 +101,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() {
assertThat(isUmoOnCommunal).isFalse()
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun testIsUmoOnCommunalDuringTransitionBetweenOccludedAndGlanceableHub() =
testScope.runTest {
@@ -87,6 +115,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() {
assertThat(isUmoOnCommunal).isFalse()
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun isUmoOnCommunal_noLongerVisible_returnsFalse() =
testScope.runTest {
@@ -103,6 +132,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() {
assertThat(isUmoOnCommunal).isFalse()
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun isUmoOnCommunal_idleOnCommunal_returnsTrue() =
testScope.runTest {
@@ -116,11 +146,25 @@ class CommunalTransitionViewModelTest : SysuiTestCase() {
assertThat(isUmoOnCommunal).isTrue()
}
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun isUmoOnCommunal_sceneContainerEnabled_idleOnCommunal_returnsTrue() =
+ testScope.runTest {
+ val isUmoOnCommunal by collectLastValue(underTest.isUmoOnCommunal)
+ assertThat(isUmoOnCommunal).isFalse()
+
+ // Change to communal scene.
+ setIdleScene(Scenes.Communal)
+
+ // isUmoOnCommunal returns true, even without any keyguard transition.
+ assertThat(isUmoOnCommunal).isTrue()
+ }
+
private suspend fun TestScope.enterCommunal(from: KeyguardState) {
keyguardTransitionRepository.sendTransitionSteps(
from = from,
to = KeyguardState.GLANCEABLE_HUB,
- testScope
+ testScope,
)
communalSceneRepository.changeScene(CommunalScenes.Communal)
runCurrent()
@@ -130,9 +174,17 @@ class CommunalTransitionViewModelTest : SysuiTestCase() {
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = to,
- testScope
+ testScope,
)
communalSceneRepository.changeScene(CommunalScenes.Blank)
runCurrent()
}
+
+ private fun setIdleScene(scene: SceneKey) {
+ sceneInteractor.changeScene(scene, "test")
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(scene))
+ sceneInteractor.setTransitionState(transitionState)
+ testScope.runCurrent()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index cecc11e5ffd4..5bbd3ffc625a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -56,6 +56,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.media.controls.ui.controller.mediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.testKosmos
@@ -133,6 +134,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
accessibilityManager,
packageManager,
WIDGET_PICKER_PACKAGE_NAME,
+ kosmos.mediaCarouselController,
)
}
@@ -353,6 +355,32 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
assertThat(event.contentDescription).isEqualTo("Test Clock widget added to lock screen")
}
+ @Test
+ fun onResizeWidget_logsMetrics() =
+ testScope.runTest {
+ val appWidgetId = 123
+ val spanY = 2
+ val widgetIdToRankMap = mapOf(appWidgetId to 1)
+ val componentName = ComponentName("test.package", "TestWidget")
+ val rank = 1
+
+ underTest.onResizeWidget(
+ appWidgetId = appWidgetId,
+ spanY = spanY,
+ widgetIdToRankMap = widgetIdToRankMap,
+ componentName = componentName,
+ rank = rank,
+ )
+
+ verify(communalInteractor).resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+ verify(metricsLogger)
+ .logResizeWidget(
+ componentName = componentName.flattenToString(),
+ rank = rank,
+ spanY = spanY,
+ )
+ }
+
private companion object {
val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
const val WIDGET_PICKER_PACKAGE_NAME = "widget_picker_package_name"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 09daa51a3b37..3eba8ff4b198 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -69,6 +69,7 @@ import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
+import com.android.systemui.media.controls.ui.controller.mediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
@@ -178,6 +179,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
mediaHost,
logcatLogBuffer("CommunalViewModelTest"),
metricsLogger,
+ kosmos.mediaCarouselController,
)
}
@@ -627,10 +629,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.setTransition(
sceneTransition = Idle(Scenes.Communal),
stateTransition =
- TransitionStep(
- from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB
- ),
+ TransitionStep(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB),
)
// Then flow is not frozen
@@ -647,10 +646,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.setTransition(
sceneTransition = Idle(Scenes.Lockscreen),
stateTransition =
- TransitionStep(
- from = KeyguardState.GLANCEABLE_HUB,
- to = KeyguardState.OCCLUDED
- ),
+ TransitionStep(from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED),
)
// Then flow is not frozen
@@ -735,10 +731,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.setTransition(
sceneTransition = Idle(Scenes.Communal),
stateTransition =
- TransitionStep(
- from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB
- ),
+ TransitionStep(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB),
)
// Widgets available
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
index ed214749d6a7..3c90c9372c27 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
@@ -67,7 +67,6 @@ public class ComplicationCollectionLiveDataTest extends SysuiTestCase {
mFeatureFlags.set(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS, true);
mStateController = new DreamOverlayStateController(
mExecutor,
- /* overlayEnabled= */ true,
mFeatureFlags,
FakeLogBuffer.Factory.Companion.create(),
new FakeWeakReferenceFactory());
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryTest.kt
new file mode 100644
index 000000000000..e17b66e90c2d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2024 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.development.data.repository
+
+import android.content.pm.UserInfo
+import android.os.Build
+import android.os.UserHandle
+import android.os.UserManager
+import android.os.userManager
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.util.settings.fakeGlobalSettings
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.test.runTest
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DevelopmentSettingRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private val underTest = kosmos.developmentSettingRepository
+
+ @Test
+ fun nonAdminUser_unrestricted_neverDevelopmentEnabled() =
+ with(kosmos) {
+ testScope.runTest {
+ val userInfo = nonAdminUserInfo
+ val settingEnabled by
+ collectLastValue(underTest.isDevelopmentSettingEnabled(userInfo))
+
+ setUserRestriction(userInfo.userHandle, restricted = false)
+
+ assertThat(settingEnabled).isFalse()
+
+ setSettingValue(false)
+ assertThat(settingEnabled).isFalse()
+
+ setSettingValue(true)
+ assertThat(settingEnabled).isFalse()
+ }
+ }
+
+ @Test
+ fun nonAdminUser_restricted_neverDevelopmentEnabled() =
+ with(kosmos) {
+ testScope.runTest {
+ val userInfo = nonAdminUserInfo
+ val settingEnabled by
+ collectLastValue(underTest.isDevelopmentSettingEnabled(userInfo))
+
+ setUserRestriction(userInfo.userHandle, restricted = true)
+
+ assertThat(settingEnabled).isFalse()
+
+ setSettingValue(false)
+ assertThat(settingEnabled).isFalse()
+
+ setSettingValue(true)
+ assertThat(settingEnabled).isFalse()
+ }
+ }
+
+ @Test
+ fun adminUser_unrestricted_defaultValueOfSetting() =
+ with(kosmos) {
+ testScope.runTest {
+ val userInfo = adminUserInfo
+ val settingEnabled by
+ collectLastValue(underTest.isDevelopmentSettingEnabled(userInfo))
+
+ setUserRestriction(userInfo.userHandle, restricted = false)
+
+ val defaultValue = Build.TYPE == "eng"
+
+ assertThat(settingEnabled).isEqualTo(defaultValue)
+ }
+ }
+
+ @Test
+ fun adminUser_unrestricted_enabledTracksSetting() =
+ with(kosmos) {
+ testScope.runTest {
+ val userInfo = adminUserInfo
+ val settingEnabled by
+ collectLastValue(underTest.isDevelopmentSettingEnabled(userInfo))
+
+ setUserRestriction(userInfo.userHandle, restricted = false)
+
+ setSettingValue(false)
+ assertThat(settingEnabled).isFalse()
+
+ setSettingValue(true)
+ assertThat(settingEnabled).isTrue()
+ }
+ }
+
+ @Test
+ fun adminUser_restricted_neverDevelopmentEnabled() =
+ with(kosmos) {
+ testScope.runTest {
+ val userInfo = adminUserInfo
+ val settingEnabled by
+ collectLastValue(underTest.isDevelopmentSettingEnabled(userInfo))
+
+ setUserRestriction(userInfo.userHandle, restricted = true)
+
+ assertThat(settingEnabled).isFalse()
+
+ setSettingValue(false)
+ assertThat(settingEnabled).isFalse()
+
+ setSettingValue(true)
+ assertThat(settingEnabled).isFalse()
+ }
+ }
+
+ private companion object {
+ const val USER_RESTRICTION = UserManager.DISALLOW_DEBUGGING_FEATURES
+ const val SETTING_NAME = Settings.Global.DEVELOPMENT_SETTINGS_ENABLED
+
+ val adminUserInfo =
+ UserInfo(
+ /* id= */ 10,
+ /* name= */ "",
+ /* flags */ UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+ )
+ val nonAdminUserInfo =
+ UserInfo(/* id= */ 11, /* name= */ "", /* flags */ UserInfo.FLAG_FULL)
+
+ fun Kosmos.setUserRestriction(userHandle: UserHandle, restricted: Boolean) {
+ userManager.stub {
+ on { hasUserRestrictionForUser(eq(USER_RESTRICTION), eq(userHandle)) } doReturn
+ restricted
+ }
+ }
+
+ fun Kosmos.setSettingValue(enabled: Boolean) {
+ fakeGlobalSettings.putInt(SETTING_NAME, if (enabled) 1 else 0)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorTest.kt
new file mode 100644
index 000000000000..f29dabe98664
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 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.development.domain.interactor
+
+import android.content.ClipData
+import android.content.ClipDescription
+import android.content.clipboardManager
+import android.content.pm.UserInfo
+import android.content.res.mainResources
+import android.os.Build
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.development.shared.model.BuildNumber
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.util.settings.fakeGlobalSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class BuildNumberInteractorTest : SysuiTestCase() {
+
+ private val kosmos =
+ testKosmos().apply {
+ fakeUserRepository.setUserInfos(listOf(adminUserInfo, nonAdminUserInfo))
+ }
+
+ private val expectedBuildNumber =
+ BuildNumber(
+ kosmos.mainResources.getString(
+ R.string.bugreport_status,
+ Build.VERSION.RELEASE_OR_CODENAME,
+ Build.ID,
+ )
+ )
+
+ private val clipLabel =
+ kosmos.mainResources.getString(
+ com.android.systemui.res.R.string.build_number_clip_data_label
+ )
+
+ private val underTest = kosmos.buildNumberInteractor
+
+ @Test
+ fun nonAdminUser_settingEnabled_buildNumberNull() =
+ with(kosmos) {
+ testScope.runTest {
+ val buildNumber by collectLastValue(underTest.buildNumber)
+
+ fakeUserRepository.setSelectedUserInfo(nonAdminUserInfo)
+ setSettingValue(true)
+
+ assertThat(buildNumber).isNull()
+ }
+ }
+
+ @Test
+ fun adminUser_buildNumberCorrect_onlyWhenSettingEnabled() =
+ with(kosmos) {
+ testScope.runTest {
+ val buildNumber by collectLastValue(underTest.buildNumber)
+
+ fakeUserRepository.setSelectedUserInfo(adminUserInfo)
+
+ setSettingValue(false)
+ assertThat(buildNumber).isNull()
+
+ setSettingValue(true)
+ assertThat(buildNumber).isEqualTo(expectedBuildNumber)
+ }
+ }
+
+ @Test
+ fun copyToClipboard() =
+ with(kosmos) {
+ testScope.runTest {
+ fakeUserRepository.setSelectedUserInfo(adminUserInfo)
+
+ underTest.copyBuildNumber()
+ runCurrent()
+
+ val argumentCaptor = argumentCaptor<ClipData>()
+
+ verify(clipboardManager).setPrimaryClip(argumentCaptor.capture())
+
+ with(argumentCaptor.firstValue) {
+ assertThat(description.label).isEqualTo(clipLabel)
+ assertThat(description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN))
+ .isTrue()
+ assertThat(itemCount).isEqualTo(1)
+ assertThat(getItemAt(0).text).isEqualTo(expectedBuildNumber.value)
+ }
+ }
+ }
+
+ private companion object {
+ const val SETTING_NAME = Settings.Global.DEVELOPMENT_SETTINGS_ENABLED
+
+ val adminUserInfo =
+ UserInfo(
+ /* id= */ 10,
+ /* name= */ "",
+ /* flags */ UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+ )
+ val nonAdminUserInfo =
+ UserInfo(/* id= */ 11, /* name= */ "", /* flags */ UserInfo.FLAG_FULL)
+
+ fun Kosmos.setSettingValue(enabled: Boolean) {
+ fakeGlobalSettings.putInt(SETTING_NAME, if (enabled) 1 else 0)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
index d90d58b8d25c..1bb5c9afdc33 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
@@ -43,7 +43,6 @@ import com.android.systemui.keyguard.data.repository.fakeTrustRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
@@ -72,7 +71,6 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
private val trustRepository by lazy { kosmos.fakeTrustRepository }
private val sceneInteractor by lazy { kosmos.sceneInteractor }
private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
- private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
private val sceneContainerStartable by lazy { kosmos.sceneContainerStartable }
private val sysuiStatusBarStateController by lazy { kosmos.sysuiStatusBarStateController }
private lateinit var underTest: DeviceEntryInteractor
@@ -437,7 +435,9 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
fun isDeviceEntered_unlockedWhileOnShade_emitsTrue() =
testScope.runTest {
val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+ val isDeviceEnteredDirectly by collectLastValue(underTest.isDeviceEnteredDirectly)
assertThat(isDeviceEntered).isFalse()
+ assertThat(isDeviceEnteredDirectly).isFalse()
val currentScene by collectLastValue(sceneInteractor.currentScene)
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
@@ -445,19 +445,20 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
switchToScene(Scenes.Shade)
assertThat(currentScene).isEqualTo(Scenes.Shade)
// Simulating a "leave it open when the keyguard is hidden" which means the bouncer will
- // be
- // shown and successful authentication should take the user back to where they are, the
- // shade scene.
+ // be shown and successful authentication should take the user back to where they are,
+ // the shade scene.
sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
switchToScene(Scenes.Bouncer)
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
assertThat(isDeviceEntered).isFalse()
+ assertThat(isDeviceEnteredDirectly).isFalse()
// Authenticate with PIN to unlock and dismiss the lockscreen:
authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
runCurrent()
assertThat(isDeviceEntered).isTrue()
+ assertThat(isDeviceEnteredDirectly).isFalse()
}
private fun TestScope.switchToScene(sceneKey: SceneKey) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
index f0d79bb83652..47cba0723804 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
@@ -568,6 +568,41 @@ class DeviceUnlockedInteractorTest : SysuiTestCase() {
assertThat(isUnlocked).isFalse()
}
+ @Test
+ fun lockNow() =
+ testScope.runTest {
+ setLockAfterScreenTimeout(5000)
+ val isUnlocked by collectLastValue(underTest.deviceUnlockStatus.map { it.isUnlocked })
+ unlockDevice()
+ assertThat(isUnlocked).isTrue()
+
+ underTest.lockNow()
+ runCurrent()
+
+ assertThat(isUnlocked).isFalse()
+ }
+
+ @Test
+ fun deviceUnlockStatus_isResetToFalse_whenDeviceGoesToSleep_fromSleepButton() =
+ testScope.runTest {
+ setLockAfterScreenTimeout(5000)
+ kosmos.fakeAuthenticationRepository.powerButtonInstantlyLocks = false
+ val deviceUnlockStatus by collectLastValue(underTest.deviceUnlockStatus)
+
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
+ assertThat(deviceUnlockStatus?.isUnlocked).isTrue()
+
+ kosmos.powerInteractor.setAsleepForTest(
+ sleepReason = PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON
+ )
+ runCurrent()
+
+ assertThat(deviceUnlockStatus?.isUnlocked).isFalse()
+ }
+
private fun TestScope.unlockDevice() {
val deviceUnlockStatus by collectLastValue(underTest.deviceUnlockStatus)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
index c39c3fe5f527..2d54337def13 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
@@ -36,6 +36,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.fakeDeviceEntryIconViewModelTransition
import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -43,6 +44,7 @@ import kotlin.test.Test
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.After
import org.junit.Before
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
@@ -84,6 +86,12 @@ class UdfpsAccessibilityOverlayViewModelTest(flags: FlagsParameterization) : Sys
@Before
fun setup() {
underTest = kosmos.deviceEntryUdfpsAccessibilityOverlayViewModel
+ overrideResource(R.integer.udfps_padding_debounce_duration, 0)
+ }
+
+ @After
+ fun teardown() {
+ mContext.orCreateTestableResources.removeOverride(R.integer.udfps_padding_debounce_duration)
}
@Test
@@ -118,6 +126,7 @@ class UdfpsAccessibilityOverlayViewModelTest(flags: FlagsParameterization) : Sys
runCurrent()
assertThat(visible).isFalse()
}
+
fun fpNotRunning_overlayNotVisible() =
testScope.runTest {
val visible by collectLastValue(underTest.visible)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
index da7a723f220e..da7a723f220e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt
new file mode 100644
index 000000000000..789178728f18
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2024 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.display.domain.interactor
+
+import android.hardware.display.defaultDisplay
+import android.hardware.display.rearDisplay
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.DeviceStateRepository
+import com.android.systemui.display.data.repository.FakeDeviceStateRepository
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.whenever
+
+/** atest RearDisplayStateInteractorTest */
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class RearDisplayStateInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val fakeDisplayRepository = FakeDisplayRepository()
+ private val fakeDeviceStateRepository = FakeDeviceStateRepository()
+ private val rearDisplayStateInteractor =
+ RearDisplayStateInteractorImpl(
+ fakeDisplayRepository,
+ fakeDeviceStateRepository,
+ kosmos.testDispatcher,
+ )
+ private val emissionTracker = EmissionTracker(rearDisplayStateInteractor, kosmos.testScope)
+
+ @Before
+ fun setup() {
+ whenever(kosmos.rearDisplay.flags).thenReturn(Display.FLAG_REAR)
+ }
+
+ @Test
+ fun enableRearDisplayWhenDisplayImmediatelyAvailable() =
+ kosmos.runTest {
+ emissionTracker.use { tracker ->
+ fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+ assertThat(tracker.enabledCount).isEqualTo(0)
+ fakeDeviceStateRepository.emit(
+ DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+ )
+
+ assertThat(tracker.enabledCount).isEqualTo(1)
+ assertThat(tracker.lastDisplay).isEqualTo(kosmos.rearDisplay)
+ }
+ }
+
+ @Test
+ fun enableAndDisableRearDisplay() =
+ kosmos.runTest {
+ emissionTracker.use { tracker ->
+ // The fake FakeDeviceStateRepository will always start with state UNKNOWN, thus
+ // triggering one initial emission
+ assertThat(tracker.disabledCount).isEqualTo(1)
+
+ fakeDeviceStateRepository.emit(
+ DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+ )
+
+ // Adding a non-rear display does not trigger an emission
+ fakeDisplayRepository.addDisplay(kosmos.defaultDisplay)
+ assertThat(tracker.enabledCount).isEqualTo(0)
+
+ // Adding a rear display triggers the emission
+ fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+ assertThat(tracker.enabledCount).isEqualTo(1)
+ assertThat(tracker.lastDisplay).isEqualTo(kosmos.rearDisplay)
+
+ fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED)
+ assertThat(tracker.disabledCount).isEqualTo(2)
+ }
+ }
+
+ @Test
+ fun enableRearDisplayShouldOnlyReactToFirstRearDisplay() =
+ kosmos.runTest {
+ emissionTracker.use { tracker ->
+ fakeDeviceStateRepository.emit(
+ DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+ )
+
+ // Adding a rear display triggers the emission
+ fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+ assertThat(tracker.enabledCount).isEqualTo(1)
+
+ // Adding additional rear displays does not trigger additional emissions
+ fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+ assertThat(tracker.enabledCount).isEqualTo(1)
+ }
+ }
+
+ @Test
+ fun rearDisplayAddedWhenNoLongerInRdm() =
+ kosmos.runTest {
+ emissionTracker.use { tracker ->
+ fakeDeviceStateRepository.emit(
+ DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+ )
+ fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED)
+
+ // Adding a rear display when no longer in the correct device state does not trigger
+ // an emission
+ fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+ assertThat(tracker.enabledCount).isEqualTo(0)
+ }
+ }
+
+ @Test
+ fun rearDisplayDisabledDoesNotSpam() =
+ kosmos.runTest {
+ emissionTracker.use { tracker ->
+ fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED)
+ assertThat(tracker.disabledCount).isEqualTo(1)
+
+ // No additional emission
+ fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.FOLDED)
+ assertThat(tracker.disabledCount).isEqualTo(1)
+ }
+ }
+
+ class EmissionTracker(rearDisplayInteractor: RearDisplayStateInteractor, scope: TestScope) :
+ AutoCloseable {
+ var enabledCount = 0
+ var disabledCount = 0
+ var lastDisplay: Display? = null
+
+ val job: Job
+
+ init {
+ val channel = Channel<RearDisplayStateInteractor.State>(Channel.UNLIMITED)
+ job =
+ scope.launch {
+ rearDisplayInteractor.state.collect {
+ channel.send(it)
+ if (it is RearDisplayStateInteractor.State.Enabled) {
+ enabledCount++
+ lastDisplay = it.innerDisplay
+ }
+ if (it is RearDisplayStateInteractor.State.Disabled) {
+ disabledCount++
+ }
+ }
+ }
+ }
+
+ override fun close() {
+ job.cancel()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeMachineTest.java
index eb72f29046aa..334718049830 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -48,10 +48,10 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
-import androidx.test.annotation.UiThreadTest;
import android.view.Display;
import androidx.annotation.NonNull;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayRegistrantTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayRegistrantTest.kt
new file mode 100644
index 000000000000..790df03e6401
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayRegistrantTest.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 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 android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.ServiceInfo
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.service.dreams.IDreamManager
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.core.FakeLogBuffer
+import com.android.systemui.shared.condition.Monitor
+import com.android.systemui.util.mockito.withArgCaptor
+import kotlin.test.Test
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.kotlin.any
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidJUnit4::class)
+class DreamOverlayRegistrantTest : SysuiTestCase() {
+ private val context = mock<Context>()
+
+ private val packageManager = mock<PackageManager>()
+
+ private val dreamManager = mock<IDreamManager>()
+
+ private val componentName = mock<ComponentName>()
+
+ private val serviceInfo = mock<ServiceInfo>()
+
+ private val monitor = mock<Monitor>()
+
+ private val logBuffer = FakeLogBuffer.Factory.Companion.create()
+
+ private lateinit var underTest: DreamOverlayRegistrant
+
+ @Before
+ fun setup() {
+ underTest =
+ DreamOverlayRegistrant(
+ context,
+ componentName,
+ monitor,
+ packageManager,
+ dreamManager,
+ logBuffer,
+ )
+
+ whenever(packageManager.getComponentEnabledSetting(eq(componentName)))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
+ whenever(
+ packageManager.getServiceInfo(
+ eq(componentName),
+ eq(PackageManager.GET_META_DATA or PackageManager.MATCH_DISABLED_COMPONENTS),
+ )
+ )
+ .thenReturn(serviceInfo)
+ whenever(
+ packageManager.setComponentEnabledSetting(
+ eq(componentName),
+ eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
+ eq(PackageManager.DONT_KILL_APP),
+ )
+ )
+ .thenAnswer {
+ setComponentEnabledState(PackageManager.COMPONENT_ENABLED_STATE_ENABLED, true)
+ }
+
+ serviceInfo.enabled = false
+ }
+
+ private fun start() {
+ underTest.start()
+ val subscription = withArgCaptor { verify(monitor).addSubscription(capture()) }
+ subscription.callback.onConditionsChanged(true)
+ }
+
+ private fun setComponentEnabledState(enabledState: Int, triggerUpdate: Boolean) {
+ whenever(packageManager.getComponentEnabledSetting(eq(componentName)))
+ .thenReturn(enabledState)
+
+ if (triggerUpdate) {
+ withArgCaptor { verify(context).registerReceiver(capture(), any()) }
+ .onReceive(context, Intent())
+ }
+ }
+
+ /** Verify overlay registered when enabled in manifest. */
+ @Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE)
+ fun testRegisteredWhenEnabledWithManifest() {
+ serviceInfo.enabled = true
+ start()
+
+ verify(dreamManager).registerDreamOverlayService(componentName)
+ }
+
+ /** Verify overlay registered for mobile hub with flag. */
+ @Test
+ @EnableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE)
+ fun testRegisteredForMobileHub() {
+ start()
+
+ verify(dreamManager).registerDreamOverlayService(componentName)
+ }
+
+ /**
+ * Make sure dream overlay not registered when not in manifest and not hub mode on mobile is not
+ * enabled.
+ */
+ @Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE)
+ fun testDisabledForMobileWithoutMobileHub() {
+ start()
+
+ verify(packageManager, never())
+ .setComponentEnabledSetting(
+ eq(componentName),
+ eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
+ eq(PackageManager.DONT_KILL_APP),
+ )
+ verify(dreamManager, never()).registerDreamOverlayService(componentName)
+ }
+
+ /** Ensure service unregistered when component is disabled at runtime. */
+ @Test
+ @EnableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE)
+ fun testUnregisteredWhenComponentDisabled() {
+ start()
+ verify(dreamManager).registerDreamOverlayService(componentName)
+ clearInvocations(dreamManager)
+ setComponentEnabledState(PackageManager.COMPONENT_ENABLED_STATE_DISABLED, true)
+ verify(dreamManager).registerDreamOverlayService(Mockito.isNull())
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index 8062358f670c..a8048793be06 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -19,7 +19,9 @@ import android.app.WindowConfiguration
import android.content.ComponentName
import android.content.Intent
import android.os.RemoteException
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
import android.service.dreams.Flags
import android.service.dreams.IDreamOverlay
import android.service.dreams.IDreamOverlayCallback
@@ -33,9 +35,7 @@ import android.view.WindowManagerImpl
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.app.viewcapture.ViewCapture
import com.android.app.viewcapture.ViewCaptureAwareWindowManager
import com.android.app.viewcapture.ViewCaptureFactory
import com.android.compose.animation.scene.ObservableTransitionState
@@ -43,14 +43,15 @@ import com.android.internal.logging.UiEventLogger
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_COMMUNAL_HUB_ON_MOBILE
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
+import com.android.systemui.ambient.touch.TouchHandler
import com.android.systemui.ambient.touch.TouchMonitor
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
import com.android.systemui.ambient.touch.scrim.ScrimController
import com.android.systemui.ambient.touch.scrim.ScrimManager
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
-import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
@@ -62,12 +63,17 @@ import com.android.systemui.complication.ComplicationLayoutEngine
import com.android.systemui.complication.dagger.ComplicationComponent
import com.android.systemui.dreams.complication.HideComplicationTouchHandler
import com.android.systemui.dreams.dagger.DreamOverlayComponent
+import com.android.systemui.dreams.touch.CommunalTouchHandler
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.gesture.domain.gestureInteractor
import com.android.systemui.kosmos.testScope
import com.android.systemui.navigationbar.gestural.domain.GestureInteractor
import com.android.systemui.navigationbar.gestural.domain.TaskInfo
import com.android.systemui.navigationbar.gestural.domain.TaskMatcher
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.touch.TouchInsetManager
import com.android.systemui.util.concurrency.FakeExecutor
@@ -81,96 +87,76 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.isNull
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.eq
import org.mockito.kotlin.firstValue
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
-import org.mockito.kotlin.times
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidJUnit4::class)
-class DreamOverlayServiceTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
private val mFakeSystemClock = FakeSystemClock()
private val mMainExecutor = FakeExecutor(mFakeSystemClock)
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- @Mock lateinit var mLifecycleOwner: DreamOverlayLifecycleOwner
-
- private lateinit var lifecycleRegistry: FakeLifecycleRegistry
-
- lateinit var mCommunalInteractor: CommunalInteractor
-
- private lateinit var mWindowParams: WindowManager.LayoutParams
-
- @Mock lateinit var mDreamOverlayCallback: IDreamOverlayCallback
-
- @Mock lateinit var mWindowManager: WindowManagerImpl
-
- @Mock lateinit var mComplicationComponentFactory: ComplicationComponent.Factory
-
- @Mock lateinit var mComplicationHostViewController: ComplicationHostViewController
-
- @Mock lateinit var mComplicationVisibilityController: ComplicationLayoutEngine
-
- @Mock
- lateinit var mDreamComplicationComponentFactory:
- com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory
-
- @Mock lateinit var mHideComplicationTouchHandler: HideComplicationTouchHandler
-
- @Mock lateinit var mDreamOverlayComponentFactory: DreamOverlayComponent.Factory
-
- @Mock lateinit var mAmbientTouchComponentFactory: AmbientTouchComponent.Factory
-
- @Mock lateinit var mDreamOverlayContainerView: DreamOverlayContainerView
-
- @Mock lateinit var mDreamOverlayContainerViewController: DreamOverlayContainerViewController
-
- @Mock lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
-
- @Mock lateinit var mTouchMonitor: TouchMonitor
-
- @Mock lateinit var mStateController: DreamOverlayStateController
-
- @Mock lateinit var mDreamOverlayContainerViewParent: ViewGroup
-
- @Mock lateinit var mTouchInsetManager: TouchInsetManager
-
- @Mock lateinit var mUiEventLogger: UiEventLogger
-
- @Mock lateinit var mScrimManager: ScrimManager
-
- @Mock lateinit var mScrimController: ScrimController
-
- @Mock lateinit var mSystemDialogsCloser: SystemDialogsCloser
-
- @Mock lateinit var mDreamOverlayCallbackController: DreamOverlayCallbackController
-
- @Mock lateinit var mLazyViewCapture: Lazy<ViewCapture>
+ private val mLifecycleOwner = mock<DreamOverlayLifecycleOwner>()
+ private val mDreamOverlayCallback = mock<IDreamOverlayCallback>()
+ private val mWindowManager = mock<WindowManagerImpl>()
+ private val mComplicationComponentFactory = mock<ComplicationComponent.Factory>()
+ private val mComplicationHostViewController = mock<ComplicationHostViewController>()
+ private val mComplicationVisibilityController = mock<ComplicationLayoutEngine>()
+ private val mDreamComplicationComponentFactory =
+ mock<com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory>()
+ private val mHideComplicationTouchHandler = mock<HideComplicationTouchHandler>()
+ private val mDreamOverlayComponentFactory = mock<DreamOverlayComponent.Factory>()
+ private val mCommunalTouchHandler = mock<CommunalTouchHandler>()
+ private val mAmbientTouchComponentFactory = mock<AmbientTouchComponent.Factory>()
+ private val mDreamOverlayContainerView = mock<DreamOverlayContainerView>()
+ private val mDreamOverlayContainerViewController =
+ mock<DreamOverlayContainerViewController> {
+ on { containerView }.thenReturn(mDreamOverlayContainerView)
+ }
+ private val mKeyguardUpdateMonitor = mock<KeyguardUpdateMonitor>()
+ private val mTouchMonitor = mock<TouchMonitor>()
+ private val mStateController = mock<DreamOverlayStateController>()
+ private val mDreamOverlayContainerViewParent = mock<ViewGroup>()
+ private val mTouchInsetManager = mock<TouchInsetManager>()
+ private val mUiEventLogger = mock<UiEventLogger>()
+ private val mScrimController = mock<ScrimController>()
+ private val mScrimManager =
+ mock<ScrimManager> { on { currentController }.thenReturn(mScrimController) }
+ private val mSystemDialogsCloser = mock<SystemDialogsCloser>()
+ private val mDreamOverlayCallbackController = mock<DreamOverlayCallbackController>()
+ private val mLazyViewCapture = lazy { viewCaptureSpy }
+
+ private val mViewCaptor = argumentCaptor<View>()
+ private val mTouchHandlersCaptor = argumentCaptor<Set<TouchHandler>>()
+
+ private val mWindowParams = WindowManager.LayoutParams()
+ private val lifecycleRegistry = FakeLifecycleRegistry(mLifecycleOwner)
+ private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository
+ private val communalRepository = kosmos.fakeCommunalSceneRepository
+ private var viewCaptureSpy = spy(ViewCaptureFactory.getInstance(context))
+ private val gestureInteractor = spy(kosmos.gestureInteractor)
+ private lateinit var mCommunalInteractor: CommunalInteractor
private lateinit var mViewCaptureAwareWindowManager: ViewCaptureAwareWindowManager
- private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
- private lateinit var communalRepository: FakeCommunalSceneRepository
- private var viewCaptureSpy = spy(ViewCaptureFactory.getInstance(context))
- private lateinit var gestureInteractor: GestureInteractor
private lateinit var environmentComponents: EnvironmentComponents
- @Captor var mViewCaptor: ArgumentCaptor<View>? = null
private lateinit var mService: DreamOverlayService
private class EnvironmentComponents(
@@ -226,6 +212,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mock<com.android.systemui.dreams.complication.dagger.ComplicationComponent>()
whenever(dreamComplicationComponent.getHideComplicationTouchHandler())
.thenReturn(mHideComplicationTouchHandler)
+ whenever(dreamOverlayComponent.communalTouchHandler).thenReturn(mCommunalTouchHandler)
whenever(dreamComplicationComponentFactory.create(any(), any()))
.thenReturn(dreamComplicationComponent)
@@ -245,15 +232,12 @@ class DreamOverlayServiceTest : SysuiTestCase() {
)
}
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
@Before
fun setup() {
- MockitoAnnotations.initMocks(this)
-
- lifecycleRegistry = FakeLifecycleRegistry(mLifecycleOwner)
- bouncerRepository = kosmos.fakeKeyguardBouncerRepository
- communalRepository = kosmos.fakeCommunalSceneRepository
- gestureInteractor = spy(kosmos.gestureInteractor)
-
environmentComponents =
setupComponentFactories(
mDreamComplicationComponentFactory,
@@ -261,12 +245,6 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mComplicationComponentFactory,
mAmbientTouchComponentFactory,
)
-
- whenever(mDreamOverlayContainerViewController.containerView)
- .thenReturn(mDreamOverlayContainerView)
- whenever(mScrimManager.getCurrentController()).thenReturn(mScrimController)
- whenever(mLazyViewCapture.value).thenReturn(viewCaptureSpy)
- mWindowParams = WindowManager.LayoutParams()
mViewCaptureAwareWindowManager =
ViewCaptureAwareWindowManager(
mWindowManager,
@@ -287,6 +265,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mKeyguardUpdateMonitor,
mScrimManager,
mCommunalInteractor,
+ kosmos.sceneInteractor,
mSystemDialogsCloser,
mUiEventLogger,
mTouchInsetManager,
@@ -368,10 +347,10 @@ class DreamOverlayServiceTest : SysuiTestCase() {
verify(mStateController).setOverlayActive(false)
verify(mStateController).setLowLightActive(false)
verify(mStateController).setEntryAnimationsFinished(false)
- verify(mStateController, Mockito.never()).setOverlayActive(true)
- verify(mUiEventLogger, Mockito.never())
+ verify(mStateController, never()).setOverlayActive(true)
+ verify(mUiEventLogger, never())
.log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START)
- verify(mDreamOverlayCallbackController, Mockito.never()).onStartDream()
+ verify(mDreamOverlayCallbackController, never()).onStartDream()
}
@Test
@@ -515,14 +494,14 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mMainExecutor.runAllReady()
// Verify view added.
- verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
+ verify(mWindowManager).addView(mViewCaptor.capture(), any())
// Service destroyed.
mService.onEndDream()
mMainExecutor.runAllReady()
// Verify view removed.
- verify(mWindowManager).removeView(mViewCaptor!!.value)
+ verify(mWindowManager).removeView(mViewCaptor.firstValue)
// Verify state correctly set.
verify(mStateController).setOverlayActive(false)
@@ -554,8 +533,8 @@ class DreamOverlayServiceTest : SysuiTestCase() {
// The overlay starts then finishes.
val inOrder = Mockito.inOrder(mWindowManager)
- inOrder.verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
- inOrder.verify(mWindowManager).removeView(mViewCaptor!!.value)
+ inOrder.verify(mWindowManager).addView(mViewCaptor.capture(), any())
+ inOrder.verify(mWindowManager).removeView(mViewCaptor.firstValue)
}
@Test
@@ -583,8 +562,8 @@ class DreamOverlayServiceTest : SysuiTestCase() {
// The overlay starts then finishes.
val inOrder = Mockito.inOrder(mWindowManager)
- inOrder.verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
- inOrder.verify(mWindowManager).removeView(mViewCaptor!!.value)
+ inOrder.verify(mWindowManager).addView(mViewCaptor.capture(), any())
+ inOrder.verify(mWindowManager).removeView(mViewCaptor.firstValue)
}
@Test
@@ -602,14 +581,14 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mMainExecutor.runAllReady()
// Verify view added.
- verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
+ verify(mWindowManager).addView(mViewCaptor.capture(), any())
// Service destroyed.
mService.onDestroy()
mMainExecutor.runAllReady()
// Verify view removed.
- verify(mWindowManager).removeView(mViewCaptor!!.value)
+ verify(mWindowManager).removeView(mViewCaptor.firstValue)
// Verify state correctly set.
verify(mKeyguardUpdateMonitor).removeCallback(any())
@@ -626,7 +605,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mMainExecutor.runAllReady()
// Verify no view is removed.
- verify(mWindowManager, Mockito.never()).removeView(any())
+ verify(mWindowManager, never()).removeView(any())
// Verify state still correctly set.
verify(mKeyguardUpdateMonitor).removeCallback(any())
@@ -652,7 +631,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
false, /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
- verify(mWindowManager, Mockito.never()).addView(any(), any())
+ verify(mWindowManager, never()).addView(any(), any())
}
@Test
@@ -660,7 +639,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
// Service destroyed before dream started.
mService.onDestroy()
mMainExecutor.runAllReady()
- verify(mWindowManager, Mockito.never()).removeView(any())
+ verify(mWindowManager, never()).removeView(any())
}
@Test
@@ -678,8 +657,8 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mMainExecutor.runAllReady()
// Verify that a new window is added.
- verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
- val windowDecorView = mViewCaptor!!.value
+ verify(mWindowManager).addView(mViewCaptor.capture(), any())
+ val windowDecorView = mViewCaptor.firstValue
// Assert that the overlay is not showing complications.
assertThat(mService.shouldShowComplications()).isFalse()
@@ -738,7 +717,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
@Test
fun testWakeUpBeforeStartDoesNothing() {
mService.onWakeUp()
- verify(mDreamOverlayContainerViewController, Mockito.never()).onWakeUp()
+ verify(mDreamOverlayContainerViewController, never()).onWakeUp()
}
@Test
@@ -768,6 +747,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
@Test
@EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_COMMUNAL_HUB)
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@kotlin.Throws(RemoteException::class)
fun testTransitionToGlanceableHub() =
testScope.runTest {
@@ -793,6 +773,35 @@ class DreamOverlayServiceTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_SCENE_CONTAINER, FLAG_COMMUNAL_HUB)
+ @kotlin.Throws(RemoteException::class)
+ fun testTransitionToGlanceableHub_sceneContainer() =
+ testScope.runTest {
+ // Inform the overlay service of dream starting. Do not show dream complications.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*isPreview*/,
+ false, /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+
+ verify(mDreamOverlayCallback).onRedirectWake(false)
+ clearInvocations(mDreamOverlayCallback)
+ kosmos.setCommunalAvailable(true)
+ mMainExecutor.runAllReady()
+ runCurrent()
+ verify(mDreamOverlayCallback).onRedirectWake(true)
+ client.onWakeRequested()
+ mMainExecutor.runAllReady()
+ runCurrent()
+ assertThat(kosmos.sceneContainerRepository.currentScene.value)
+ .isEqualTo(Scenes.Communal)
+ verify(mUiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_COMMUNAL_HUB)
@Throws(RemoteException::class)
fun testRedirectExit() =
@@ -836,8 +845,8 @@ class DreamOverlayServiceTest : SysuiTestCase() {
)
mMainExecutor.runAllReady()
- whenever(mDreamOverlayContainerViewController.isBouncerShowing()).thenReturn(true)
- mService!!.onComeToFront()
+ whenever(mDreamOverlayContainerViewController.isBouncerShowing).thenReturn(true)
+ mService.onComeToFront()
verify(mScrimController).expand(any())
}
@@ -857,7 +866,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
)
mMainExecutor.runAllReady()
- mService!!.onComeToFront()
+ mService.onComeToFront()
assertThat(communalRepository.currentScene.value).isEqualTo(CommunalScenes.Blank)
}
@@ -877,7 +886,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
)
mMainExecutor.runAllReady()
- mService!!.onComeToFront()
+ mService.onComeToFront()
verify(mSystemDialogsCloser).closeSystemDialogs()
}
@@ -911,6 +920,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
// Verifies that the touch handling lifecycle is STARTED even if the dream starts while not
// focused.
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun testLifecycle_dreamNotFocusedOnStart_isStarted() {
val transitionState: MutableStateFlow<ObservableTransitionState> =
MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank))
@@ -991,6 +1001,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED)
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun testBouncerShown_setsLifecycleState() {
val client = client
@@ -1023,7 +1034,41 @@ class DreamOverlayServiceTest : SysuiTestCase() {
assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED)
}
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun testBouncerShown_withSceneContainer_setsLifecycleState() {
+ val client = client
+
+ // Inform the overlay service of dream starting.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*isPreview*/,
+ false, /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+ assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED)
+
+ // Bouncer shows.
+ kosmos.sceneInteractor.changeScene(Scenes.Bouncer, "test")
+ testScope.runCurrent()
+ mMainExecutor.runAllReady()
+
+ // Lifecycle state goes from resumed back to started when the bouncer shows.
+ assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.STARTED)
+
+ // Bouncer closes.
+ kosmos.sceneInteractor.changeScene(Scenes.Dream, "test")
+ testScope.runCurrent()
+ mMainExecutor.runAllReady()
+
+ // Lifecycle state goes back to RESUMED.
+ assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED)
+ }
+
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun testCommunalVisible_setsLifecycleState() {
val client = client
@@ -1060,6 +1105,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
// Verifies the dream's lifecycle
@Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
fun testLifecycleStarted_whenAnyOcclusion() {
val client = client
@@ -1240,6 +1286,45 @@ class DreamOverlayServiceTest : SysuiTestCase() {
environmentComponents.verifyNoMoreInteractions()
}
+ @DisableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE)
+ @Test
+ fun testAmbientTouchHandlersRegistration_registerHideComplicationAndCommunal() {
+ val client = client
+
+ // Inform the overlay service of dream starting.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*isPreview*/,
+ false, /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+
+ verify(mAmbientTouchComponentFactory).create(any(), mTouchHandlersCaptor.capture(), any())
+ assertThat(mTouchHandlersCaptor.firstValue)
+ .containsExactly(mHideComplicationTouchHandler, mCommunalTouchHandler)
+ }
+
+ @EnableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE)
+ @Test
+ fun testAmbientTouchHandlersRegistration_v2_registerOnlyHideComplication() {
+ val client = client
+
+ // Inform the overlay service of dream starting.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*isPreview*/,
+ false, /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+
+ verify(mAmbientTouchComponentFactory).create(any(), mTouchHandlersCaptor.capture(), any())
+ assertThat(mTouchHandlersCaptor.firstValue).containsExactly(mHideComplicationTouchHandler)
+ }
+
internal class FakeLifecycleRegistry(provider: LifecycleOwner) : LifecycleRegistry(provider) {
val mLifecycles: MutableList<State> = ArrayList()
@@ -1256,5 +1341,11 @@ class DreamOverlayServiceTest : SysuiTestCase() {
ComponentName("package", "homeControlPanel")
private const val DREAM_COMPONENT = "package/dream"
private const val WINDOW_NAME = "test"
+
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_HUB).andSceneContainer()
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index b46f2aa61518..5a1d8bbb0bf1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -76,7 +76,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testStateChange_overlayActive() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(mCallback);
stateController.setOverlayActive(true);
mExecutor.runAllReady();
@@ -97,7 +97,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testCallback() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(mCallback);
// Add complication and verify callback is notified.
@@ -122,7 +122,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyOnCallbackAdd() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addComplication(mComplication);
mExecutor.runAllReady();
@@ -134,22 +134,8 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
}
@Test
- public void testNotifyOnCallbackAddOverlayDisabled() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(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 = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.setShouldShowComplications(true);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -188,7 +174,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testComplicationFilteringWhenShouldHideComplications() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.setShouldShowComplications(true);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -234,7 +220,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testComplicationWithNoTypeNotFiltered() {
final Complication complication = Mockito.mock(Complication.class);
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addComplication(complication);
mExecutor.runAllReady();
assertThat(stateController.getComplications(true).contains(complication))
@@ -244,7 +230,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testComplicationsNotShownForHomeControlPanelDream() {
final Complication complication = Mockito.mock(Complication.class);
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
// Add a complication and verify it's returned in getComplications.
stateController.addComplication(complication);
@@ -261,7 +247,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testComplicationsNotShownForLowLight() {
final Complication complication = Mockito.mock(Complication.class);
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
// Add a complication and verify it's returned in getComplications.
stateController.addComplication(complication);
@@ -277,7 +263,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyLowLightChanged() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(mCallback);
mExecutor.runAllReady();
@@ -292,7 +278,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyLowLightExit() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(mCallback);
mExecutor.runAllReady();
@@ -315,7 +301,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyEntryAnimationsFinishedChanged() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(mCallback);
mExecutor.runAllReady();
@@ -330,7 +316,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyDreamOverlayStatusBarVisibleChanged() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(mCallback);
mExecutor.runAllReady();
@@ -345,7 +331,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyHasAssistantAttentionChanged() {
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(mCallback);
mExecutor.runAllReady();
@@ -362,7 +348,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
public void testShouldShowComplicationsSetToFalse_stillShowsHomeControls_featureEnabled() {
when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true);
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.setShouldShowComplications(true);
final Complication homeControlsComplication = Mockito.mock(Complication.class);
@@ -404,7 +390,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
public void testHomeControlsDoNotShowIfNotAvailable_featureEnabled() {
when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true);
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.setShouldShowComplications(true);
final Complication homeControlsComplication = Mockito.mock(Complication.class);
@@ -435,7 +421,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
final DreamOverlayStateController.Callback callback2 = Mockito.mock(
DreamOverlayStateController.Callback.class);
- final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ final DreamOverlayStateController stateController = getDreamOverlayStateController();
stateController.addCallback(callback1);
stateController.addCallback(callback2);
mExecutor.runAllReady();
@@ -451,10 +437,9 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
assertThat(stateController.isOverlayActive()).isTrue();
}
- private DreamOverlayStateController getDreamOverlayStateController(boolean overlayEnabled) {
+ private DreamOverlayStateController getDreamOverlayStateController() {
return new DreamOverlayStateController(
mExecutor,
- overlayEnabled,
mFeatureFlags,
mLogBuffer,
mWeakReferenceFactory
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
new file mode 100644
index 000000000000..82bcecef1f70
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2024 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(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.dreams.ui.viewmodel
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
+import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableSceneContainer
+class DreamUserActionsViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private lateinit var underTest: DreamUserActionsViewModel
+
+ @Before
+ fun setUp() {
+ underTest = kosmos.dreamUserActionsViewModel
+ underTest.activateIn(testScope)
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun actions_singleShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+
+ setUpState(
+ isShadeTouchable = true,
+ isDeviceUnlocked = false,
+ shadeMode = ShadeMode.Single,
+ )
+ assertThat(actions).isNotEmpty()
+ assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+ assertThat(actions?.get(Swipe.Down))
+ .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+
+ setUpState(
+ isShadeTouchable = false,
+ isDeviceUnlocked = false,
+ shadeMode = ShadeMode.Single,
+ )
+ assertThat(actions).isEmpty()
+
+ setUpState(
+ isShadeTouchable = true,
+ isDeviceUnlocked = true,
+ shadeMode = ShadeMode.Single,
+ )
+ assertThat(actions).isNotEmpty()
+ assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+ assertThat(actions?.get(Swipe.Down))
+ .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun actions_splitShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+
+ setUpState(
+ isShadeTouchable = true,
+ isDeviceUnlocked = false,
+ shadeMode = ShadeMode.Split,
+ )
+ assertThat(actions).isNotEmpty()
+ assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+ assertThat(actions?.get(Swipe.Down))
+ .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+
+ setUpState(
+ isShadeTouchable = false,
+ isDeviceUnlocked = false,
+ shadeMode = ShadeMode.Split,
+ )
+ assertThat(actions).isEmpty()
+
+ setUpState(
+ isShadeTouchable = true,
+ isDeviceUnlocked = true,
+ shadeMode = ShadeMode.Split,
+ )
+ assertThat(actions).isNotEmpty()
+ assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+ assertThat(actions?.get(Swipe.Down))
+ .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun actions_dualShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+
+ setUpState(
+ isShadeTouchable = true,
+ isDeviceUnlocked = false,
+ shadeMode = ShadeMode.Dual,
+ )
+ assertThat(actions).isNotEmpty()
+ assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+ assertThat(actions?.get(Swipe.Down))
+ .isEqualTo(
+ UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
+ )
+
+ setUpState(
+ isShadeTouchable = false,
+ isDeviceUnlocked = false,
+ shadeMode = ShadeMode.Dual,
+ )
+ assertThat(actions).isEmpty()
+
+ setUpState(isShadeTouchable = true, isDeviceUnlocked = true, shadeMode = ShadeMode.Dual)
+ assertThat(actions).isNotEmpty()
+ assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+ assertThat(actions?.get(Swipe.Down))
+ .isEqualTo(
+ UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
+ )
+ }
+
+ private fun TestScope.setUpState(
+ isShadeTouchable: Boolean,
+ isDeviceUnlocked: Boolean,
+ shadeMode: ShadeMode,
+ ) {
+ if (isShadeTouchable) {
+ kosmos.powerInteractor.setAwakeForTest()
+ } else {
+ kosmos.powerInteractor.setAsleepForTest()
+ }
+
+ if (isDeviceUnlocked) {
+ unlockDevice()
+ } else {
+ lockDevice()
+ }
+
+ if (shadeMode == ShadeMode.Dual) {
+ assertThat(DualShade.isEnabled).isTrue()
+ } else {
+ assertThat(DualShade.isEnabled).isFalse()
+ kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode == ShadeMode.Split)
+ }
+ runCurrent()
+ }
+
+ private fun TestScope.lockDevice() {
+ val deviceUnlockStatus by
+ collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
+
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ assertThat(deviceUnlockStatus?.isUnlocked).isFalse()
+ kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+ runCurrent()
+ }
+
+ private fun TestScope.unlockDevice() {
+ val deviceUnlockStatus by
+ collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
+
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ assertThat(deviceUnlockStatus?.isUnlocked).isTrue()
+ kosmos.sceneInteractor.changeScene(Scenes.Gone, "reason")
+ runCurrent()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt
index 5efb6171cdde..f6a6e5465e1b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt
@@ -119,22 +119,6 @@ class TileHapticsViewModelTest : SysuiTestCase() {
}
@Test
- fun onLongClick_whenTileDoesNotHandleLongClick_playsFailureHaptics() =
- testScope.runTest {
- // WHEN the tile is long-clicked but the tile does not handle a long-click
- val state = QSTile.State().apply { handlesLongClick = false }
- qsTile.changeState(state)
- underTest.setTileInteractionState(
- TileHapticsViewModel.TileInteractionState.LONG_CLICKED
- )
- runCurrent()
-
- // THEN the failure token plays
- assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE)
- assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
- }
-
- @Test
fun whenLaunchingFromClick_doesNotPlayHaptics() =
testScope.runTest {
// WHEN the tile is clicked and its action state changes accordingly
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
index 366b55db4f20..329f90a1006a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
@@ -398,6 +398,16 @@ class QSLongPressEffectTest : SysuiTestCase() {
verify(controller).onTransitionAnimationCancelled(newOccludedState)
}
+ @Test
+ fun onTileLongClick_whileIdle_performsLongClick() =
+ testWhileInState(QSLongPressEffect.State.IDLE) {
+ // WHEN a long-click is detected by the view
+ val longClicks = longPressEffect.onTileLongClick()
+
+ // THEN the long click is handled
+ assertThat(longClicks).isTrue()
+ }
+
private fun testWithScope(initialize: Boolean = true, test: suspend TestScope.() -> Unit) =
with(kosmos) {
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
index 5df9b7b8d5b8..2efa2f34e394 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
@@ -85,63 +85,62 @@ class TutorialSchedulerInteractorTest : SysuiTestCase() {
@Test
fun connectKeyboard_delayElapse_launchForKeyboard() =
testScope.runTest {
- launchAndAssert(TutorialType.KEYBOARD)
-
keyboardRepository.setIsAnyKeyboardConnected(true)
advanceTimeBy(LAUNCH_DELAY)
+
+ launchAndAssert(TutorialType.KEYBOARD)
}
@Test
fun connectBothDevices_delayElapse_launchForBoth() =
testScope.runTest {
- launchAndAssert(TutorialType.BOTH)
-
keyboardRepository.setIsAnyKeyboardConnected(true)
touchpadRepository.setIsAnyTouchpadConnected(true)
advanceTimeBy(LAUNCH_DELAY)
+
+ launchAndAssert(TutorialType.BOTH)
}
@Test
fun connectBothDevice_delayNotElapse_launchNothing() =
testScope.runTest {
- launchAndAssert(TutorialType.NONE)
-
keyboardRepository.setIsAnyKeyboardConnected(true)
touchpadRepository.setIsAnyTouchpadConnected(true)
advanceTimeBy(A_SHORT_PERIOD_OF_TIME)
+
+ launchAndAssert(TutorialType.NONE)
}
@Test
fun nothingConnect_delayElapse_launchNothing() =
testScope.runTest {
- launchAndAssert(TutorialType.NONE)
-
keyboardRepository.setIsAnyKeyboardConnected(false)
touchpadRepository.setIsAnyTouchpadConnected(false)
advanceTimeBy(LAUNCH_DELAY)
+
+ launchAndAssert(TutorialType.NONE)
}
@Test
fun connectKeyboard_thenTouchpad_delayElapse_launchForBoth() =
testScope.runTest {
- launchAndAssert(TutorialType.BOTH)
-
keyboardRepository.setIsAnyKeyboardConnected(true)
advanceTimeBy(A_SHORT_PERIOD_OF_TIME)
touchpadRepository.setIsAnyTouchpadConnected(true)
advanceTimeBy(REMAINING_TIME)
+
+ launchAndAssert(TutorialType.BOTH)
}
@Test
fun connectKeyboard_thenTouchpad_removeKeyboard_delayElapse_launchNothing() =
testScope.runTest {
- launchAndAssert(TutorialType.NONE)
-
keyboardRepository.setIsAnyKeyboardConnected(true)
advanceTimeBy(A_SHORT_PERIOD_OF_TIME)
touchpadRepository.setIsAnyTouchpadConnected(true)
keyboardRepository.setIsAnyKeyboardConnected(false)
advanceTimeBy(REMAINING_TIME)
+ launchAndAssert(TutorialType.NONE)
}
private suspend fun launchAndAssert(expectedTutorial: TutorialType) =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
index 639737b37efd..76434ee54627 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
@@ -27,9 +27,11 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.domain.interactor.KeyboardTouchpadConnectionInteractor
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
@@ -66,8 +68,8 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
private val sysUiState = kosmos.sysUiState
private val touchpadRepo = PrettyFakeTouchpadRepository()
private val keyboardRepo = kosmos.keyboardRepository
- private var startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
- private val viewModel by lazy { createViewModel(startingPeripheral) }
+ private var tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
+ private val viewModel by lazy { createViewModel(tutorialScope) }
// createUnsafe so its methods don't have to be called on Main thread
private val lifecycle = LifecycleRegistry.createUnsafe(mock(LifecycleOwner::class.java))
@@ -75,7 +77,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
@get:Rule val mainDispatcherRule = MainDispatcherRule(kosmos.testDispatcher)
private fun createViewModel(
- startingPeripheral: String = INTENT_TUTORIAL_TYPE_TOUCHPAD,
+ scope: String = INTENT_TUTORIAL_SCOPE_TOUCHPAD,
hasTouchpadTutorialScreens: Boolean = true,
): KeyboardTouchpadTutorialViewModel {
val viewModel =
@@ -84,7 +86,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
KeyboardTouchpadConnectionInteractor(keyboardRepo, touchpadRepo),
hasTouchpadTutorialScreens,
mock<InputDeviceTutorialLogger>(),
- SavedStateHandle(mapOf(INTENT_TUTORIAL_TYPE_KEY to startingPeripheral))
+ SavedStateHandle(mapOf(INTENT_TUTORIAL_SCOPE_KEY to scope)),
)
lifecycle.addObserver(viewModel)
return viewModel
@@ -169,7 +171,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
@Test
fun screensOrder_whenGoingBackAndOnlyKeyboardConnected() =
testScope.runTest {
- startingPeripheral = INTENT_TUTORIAL_TYPE_KEYBOARD
+ tutorialScope = INTENT_TUTORIAL_SCOPE_KEYBOARD
val screens by collectValues(viewModel.screen)
val closeActivity by collectLastValue(viewModel.closeActivity)
peripheralsState(keyboardConnected = true, touchpadConnected = false)
@@ -185,7 +187,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
@Test
fun screensOrder_whenTouchpadConnected() =
testScope.runTest {
- startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
val screens by collectValues(viewModel.screen)
val closeActivity by collectLastValue(viewModel.closeActivity)
@@ -193,22 +195,47 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
goToNextScreen()
goToNextScreen()
- goToNextScreen()
assertThat(screens).containsExactly(BACK_GESTURE, HOME_GESTURE).inOrder()
assertThat(closeActivity).isTrue()
}
@Test
- fun screensOrder_whenKeyboardConnected() =
+ fun screensOrder_withBackGestureScope() =
testScope.runTest {
- startingPeripheral = INTENT_TUTORIAL_TYPE_KEYBOARD
+ tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
val screens by collectValues(viewModel.screen)
val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(touchpadConnected = true)
- peripheralsState(keyboardConnected = true)
+ goToNextScreen()
+
+ assertThat(screens).containsExactly(BACK_GESTURE).inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun screensOrder_withHomeGestureScope() =
+ testScope.runTest {
+ tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(touchpadConnected = true)
goToNextScreen()
+
+ assertThat(screens).containsExactly(HOME_GESTURE).inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun screensOrder_withKeyboardScope() =
+ testScope.runTest {
+ tutorialScope = INTENT_TUTORIAL_SCOPE_KEYBOARD
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(keyboardConnected = true)
+
goToNextScreen()
assertThat(screens).containsExactly(ACTION_KEY).inOrder()
@@ -218,7 +245,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
@Test
fun touchpadGesturesDisabled_onlyDuringTouchpadTutorial() =
testScope.runTest {
- startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
collectValues(viewModel.screen) // just to initialize viewModel
peripheralsState(keyboardConnected = true, touchpadConnected = true)
@@ -234,8 +261,8 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
testScope.runTest {
val viewModel =
createViewModel(
- startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD,
- hasTouchpadTutorialScreens = false
+ scope = INTENT_TUTORIAL_SCOPE_TOUCHPAD,
+ hasTouchpadTutorialScreens = false,
)
val screens by collectValues(viewModel.screen)
val closeActivity by collectLastValue(viewModel.closeActivity)
@@ -248,7 +275,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
@Test
fun touchpadGesturesDisabled_whenTutorialGoesToForeground() =
testScope.runTest {
- startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
collectValues(viewModel.screen) // just to initialize viewModel
peripheralsState(touchpadConnected = true)
@@ -260,7 +287,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
@Test
fun touchpadGesturesNotDisabled_whenTutorialGoesToBackground() =
testScope.runTest {
- startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
collectValues(viewModel.screen)
peripheralsState(touchpadConnected = true)
@@ -288,7 +315,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
private fun TestScope.peripheralsState(
keyboardConnected: Boolean = false,
- touchpadConnected: Boolean = false
+ touchpadConnected: Boolean = false,
) {
keyboardRepo.setIsAnyKeyboardConnected(keyboardConnected)
touchpadRepo.setIsAnyTouchpadConnected(touchpadConnected)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
index 8b1341114c68..8b1341114c68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
index c646d8f11706..f04540426fc1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
@@ -20,11 +20,21 @@ import android.content.Context
import android.content.Context.INPUT_SERVICE
import android.hardware.input.InputGestureData
import android.hardware.input.InputGestureData.createKeyTrigger
-import android.hardware.input.KeyGestureEvent
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
import android.hardware.input.fakeInputManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.view.KeyEvent
+import android.view.KeyEvent.KEYCODE_A
+import android.view.KeyEvent.KEYCODE_SLASH
+import android.view.KeyEvent.META_ALT_ON
+import android.view.KeyEvent.META_CAPS_LOCK_ON
+import android.view.KeyEvent.META_CTRL_ON
+import android.view.KeyEvent.META_FUNCTION_ON
+import android.view.KeyEvent.META_META_LEFT_ON
+import android.view.KeyEvent.META_META_ON
+import android.view.KeyEvent.META_SHIFT_ON
+import android.view.KeyEvent.META_SHIFT_RIGHT_ON
+import android.view.KeyEvent.META_SYM_ON
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.hardware.input.Flags.FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES
@@ -32,17 +42,16 @@ import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyboard.shortcut.customShortcutCategoriesRepository
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allCustomizableInputGesturesWithSimpleShortcutCombinations
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.customizableInputGestureWithUnknownKeyGestureType
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedShortcutCategoriesWithSimpleShortcutCombination
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.userTracker
import com.android.systemui.testKosmos
@@ -83,7 +92,7 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() {
whenever(
fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())
)
- .thenReturn(customizableInputGesturesWithSimpleShortcutCombinations)
+ .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations)
helper.toggle(deviceId = 123)
val categories by collectLastValue(repo.categories)
@@ -100,7 +109,7 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() {
whenever(
fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())
)
- .thenReturn(customizableInputGesturesWithSimpleShortcutCombinations)
+ .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations)
helper.toggle(deviceId = 123)
val categories by collectLastValue(repo.categories)
@@ -125,167 +134,147 @@ class CustomShortcutCategoriesRepositoryTest : SysuiTestCase() {
}
}
- private fun simpleInputGestureData(
- keyCode: Int = KeyEvent.KEYCODE_A,
- modifiers: Int = KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON,
- keyGestureType: Int,
- ): InputGestureData {
- val builder = InputGestureData.Builder()
- builder.setKeyGestureType(keyGestureType)
- builder.setTrigger(createKeyTrigger(keyCode, modifiers))
- return builder.build()
+ @Test
+ fun pressedKeys_isEmptyByDefault() {
+ testScope.runTest {
+ val pressedKeys by collectLastValue(repo.pressedKeys)
+ assertThat(pressedKeys).isEmpty()
+
+ helper.toggle(deviceId = 123)
+ assertThat(pressedKeys).isEmpty()
+ }
}
- private fun simpleShortcutCategory(
- category: ShortcutCategoryType,
- subcategoryLabel: String,
- shortcutLabel: String,
- ): ShortcutCategory {
- return ShortcutCategory(
- type = category,
- subCategories =
- listOf(
- ShortcutSubCategory(
- label = subcategoryLabel,
- shortcuts = listOf(simpleShortcut(shortcutLabel)),
- )
- ),
- )
+ @Test
+ fun pressedKeys_recognizesAllSupportedModifiers() {
+ testScope.runTest {
+ helper.toggle(deviceId = 123)
+ val pressedKeys by collectLastValue(repo.pressedKeys)
+ repo.updateUserKeyCombination(
+ KeyCombination(modifiers = allSupportedModifiers, keyCode = null)
+ )
+
+ assertThat(pressedKeys)
+ .containsExactly(
+ ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
+ ShortcutKey.Text("Ctrl"),
+ ShortcutKey.Text("Fn"),
+ ShortcutKey.Text("Shift"),
+ ShortcutKey.Text("Alt"),
+ ShortcutKey.Text("Sym"),
+ )
+ }
}
- private fun simpleShortcut(label: String) =
- Shortcut(
- label = label,
- commands =
- listOf(
- ShortcutCommand(
- isCustom = true,
- keys =
- listOf(
- ShortcutKey.Text("Ctrl"),
- ShortcutKey.Text("Alt"),
- ShortcutKey.Text("A"),
- ),
- )
- ),
- )
+ @Test
+ fun pressedKeys_ignoresUnsupportedModifiers() {
+ testScope.runTest {
+ helper.toggle(deviceId = 123)
+ val pressedKeys by collectLastValue(repo.pressedKeys)
+ repo.updateUserKeyCombination(
+ KeyCombination(modifiers = META_CAPS_LOCK_ON, keyCode = null)
+ )
- private val customizableInputGestureWithUnknownKeyGestureType =
- // These key gesture events are currently not supported by shortcut helper customizer
- listOf(
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS
- ),
- simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY),
- )
+ assertThat(pressedKeys).isEmpty()
+ }
+ }
+
+ @Test
+ fun pressedKeys_assertCorrectConversion() {
+ testScope.runTest {
+ helper.toggle(deviceId = 123)
+ val pressedKeys by collectLastValue(repo.pressedKeys)
+ repo.updateUserKeyCombination(
+ KeyCombination(modifiers = META_META_ON, keyCode = KEYCODE_SLASH)
+ )
+
+ assertThat(pressedKeys)
+ .containsExactly(
+ ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
+ ShortcutKey.Text("/"),
+ )
+ }
+ }
+
+ @Test
+ fun shortcutBeingCustomized_updatedOnCustomizationRequested() {
+ testScope.runTest {
+ repo.onCustomizationRequested(standardCustomizationRequestInfo)
- private val expectedShortcutCategoriesWithSimpleShortcutCombination =
- listOf(
- simpleShortcutCategory(System, "System apps", "Open assistant"),
- simpleShortcutCategory(System, "System controls", "Go to home screen"),
- simpleShortcutCategory(System, "System apps", "Open settings"),
- simpleShortcutCategory(System, "System controls", "Lock screen"),
- simpleShortcutCategory(System, "System controls", "View notifications"),
- simpleShortcutCategory(System, "System apps", "Take a note"),
- simpleShortcutCategory(System, "System controls", "Take screenshot"),
- simpleShortcutCategory(System, "System controls", "Go back"),
- simpleShortcutCategory(
- MultiTasking,
- "Split screen",
- "Switch from split screen to full screen",
- ),
- simpleShortcutCategory(
- MultiTasking,
- "Split screen",
- "Use split screen with current app on the left",
- ),
- simpleShortcutCategory(
- MultiTasking,
- "Split screen",
- "Switch to app on left or above while using split screen",
- ),
- simpleShortcutCategory(
- MultiTasking,
- "Split screen",
- "Use split screen with current app on the right",
- ),
- simpleShortcutCategory(
- MultiTasking,
- "Split screen",
- "Switch to app on right or below while using split screen",
- ),
- simpleShortcutCategory(System, "System controls", "Show shortcuts"),
- simpleShortcutCategory(System, "System controls", "View recent apps"),
- simpleShortcutCategory(AppCategories, "Applications", "Calculator"),
- simpleShortcutCategory(AppCategories, "Applications", "Calendar"),
- simpleShortcutCategory(AppCategories, "Applications", "Chrome"),
- simpleShortcutCategory(AppCategories, "Applications", "Contacts"),
- simpleShortcutCategory(AppCategories, "Applications", "Gmail"),
- simpleShortcutCategory(AppCategories, "Applications", "Maps"),
- simpleShortcutCategory(AppCategories, "Applications", "Messages"),
- simpleShortcutCategory(MultiTasking, "Recent apps", "Cycle forward through recent apps"),
+ val shortcutBeingCustomized = repo.getShortcutBeingCustomized()
+
+ assertThat(shortcutBeingCustomized).isEqualTo(standardCustomizationRequestInfo)
+ }
+ }
+
+ @Test
+ fun buildInputGestureDataForShortcutBeingCustomized_noShortcutBeingCustomized_returnsNull() {
+ testScope.runTest {
+ helper.toggle(deviceId = 123)
+ repo.updateUserKeyCombination(standardKeyCombination)
+
+ val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()
+
+ assertThat(inputGestureData).isNull()
+ }
+ }
+
+ @Test
+ fun buildInputGestureDataForShortcutBeingCustomized_noKeyCombinationSelected_returnsNull() {
+ testScope.runTest {
+ helper.toggle(deviceId = 123)
+ repo.onCustomizationRequested(standardCustomizationRequestInfo)
+
+ val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()
+
+ assertThat(inputGestureData).isNull()
+ }
+ }
+
+ @Test
+ fun buildInputGestureDataForShortcutBeingCustomized_successfullyBuildInputGestureData() {
+ testScope.runTest {
+ helper.toggle(deviceId = 123)
+ repo.onCustomizationRequested(standardCustomizationRequestInfo)
+ repo.updateUserKeyCombination(standardKeyCombination)
+ val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()
+
+ // using toString as we're testing for only structural equality not referential.
+ // inputGestureData is a java class and isEqual Tests for referential equality
+ // as well which would cause this assert to fail
+ assertThat(inputGestureData.toString()).isEqualTo(standardInputGestureData.toString())
+ }
+ }
+
+ private val standardCustomizationRequestInfo =
+ ShortcutCustomizationRequestInfo.Add(
+ label = "Open apps list",
+ categoryType = ShortcutCategoryType.System,
+ subCategoryLabel = "System controls",
)
- private val customizableInputGesturesWithSimpleShortcutCombinations =
- listOf(
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT
- ),
- simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS
- ),
- simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
- ),
- simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
- ),
- simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
- ),
- simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING
- ),
- simpleInputGestureData(
- keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
- ),
+ private val standardKeyCombination =
+ KeyCombination(
+ modifiers = META_META_ON or META_SHIFT_ON or META_META_LEFT_ON or META_SHIFT_RIGHT_ON,
+ keyCode = KEYCODE_A,
)
+
+ private val allSupportedModifiers =
+ META_META_ON or
+ META_CTRL_ON or
+ META_FUNCTION_ON or
+ META_SHIFT_ON or
+ META_ALT_ON or
+ META_SYM_ON
+
+ private val standardInputGestureData =
+ InputGestureData.Builder()
+ .setKeyGestureType(KEY_GESTURE_TYPE_ALL_APPS)
+ .setTrigger(
+ createKeyTrigger(
+ /* keycode = */ standardKeyCombination.keyCode!!,
+ /* modifierState = */ standardKeyCombination.modifiers and allSupportedModifiers,
+ )
+ )
+ .build()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index c9c39b3ebf66..a1e7ef4ac5a3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -16,11 +16,20 @@
package com.android.systemui.keyboard.shortcut.data.source
+import android.hardware.input.InputGestureData
+import android.hardware.input.InputGestureData.createKeyTrigger
+import android.hardware.input.KeyGestureEvent
import android.view.KeyEvent
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import com.android.systemui.keyboard.shortcut.shared.model.shortcut
import com.android.systemui.res.R
@@ -64,6 +73,13 @@ object TestShortcuts {
}
}
+ private val goHomeShortcutInfo =
+ KeyboardShortcutInfo(
+ /* label = */ "Go to home screen",
+ /* keycode = */ KeyEvent.KEYCODE_B,
+ /* modifiers = */ KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON,
+ )
+
private val standardShortcutInfo1 =
KeyboardShortcutInfo(
/* label = */ "Standard shortcut 1",
@@ -79,6 +95,16 @@ object TestShortcuts {
}
}
+ private val customGoHomeShortcut =
+ shortcut("Go to home screen") {
+ command {
+ key("Ctrl")
+ key("Alt")
+ key("A")
+ isCustom(true)
+ }
+ }
+
private val standardShortcutInfo2 =
KeyboardShortcutInfo(
/* label = */ "Standard shortcut 2",
@@ -123,35 +149,38 @@ object TestShortcuts {
listOf(
shortcutInfoWithRepeatedLabel,
shortcutInfoWithRepeatedLabelAlternate,
- shortcutInfoWithRepeatedLabelSecondAlternate
- )
+ shortcutInfoWithRepeatedLabelSecondAlternate,
+ ),
)
private val subCategoryWithGroupedRepeatedShortcutLabels =
ShortcutSubCategory(
label = groupWithRepeatedShortcutLabels.label!!.toString(),
- shortcuts = listOf(shortcutWithGroupedRepeatedLabel)
+ shortcuts = listOf(shortcutWithGroupedRepeatedLabel),
)
private val groupWithStandardShortcutInfo =
KeyboardShortcutGroup("Standard group", listOf(standardShortcutInfo1))
+ val groupWithGoHomeShortcutInfo =
+ KeyboardShortcutGroup("System controls", listOf(goHomeShortcutInfo))
+
private val subCategoryWithStandardShortcut =
ShortcutSubCategory(
label = groupWithStandardShortcutInfo.label!!.toString(),
- shortcuts = listOf(standardShortcut1)
+ shortcuts = listOf(standardShortcut1),
)
private val groupWithOnlyUnsupportedModifierShortcut =
KeyboardShortcutGroup(
"Group with unsupported modifiers",
- listOf(shortcutInfoWithUnsupportedModifiers)
+ listOf(shortcutInfoWithUnsupportedModifiers),
)
private val groupWithSupportedAndUnsupportedModifierShortcut =
KeyboardShortcutGroup(
"Group with mix of supported and not supported modifiers",
- listOf(standardShortcutInfo3, shortcutInfoWithUnsupportedModifiers)
+ listOf(standardShortcutInfo3, shortcutInfoWithUnsupportedModifiers),
)
private val switchToNextLanguageShortcut =
@@ -174,19 +203,19 @@ object TestShortcuts {
private val subCategoryForInputLanguageSwitchShortcuts =
ShortcutSubCategory(
"Input",
- listOf(switchToNextLanguageShortcut, switchToPreviousLanguageShortcut)
+ listOf(switchToNextLanguageShortcut, switchToPreviousLanguageShortcut),
)
private val subCategoryWithUnsupportedShortcutsRemoved =
ShortcutSubCategory(
groupWithSupportedAndUnsupportedModifierShortcut.label!!.toString(),
- listOf(standardShortcut3)
+ listOf(standardShortcut3),
)
private val standardGroup1 =
KeyboardShortcutGroup(
"Standard group 1",
- listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
+ listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3),
)
private val standardPackageName1 = "standard.app.group1"
@@ -194,38 +223,63 @@ object TestShortcuts {
private val standardAppGroup1 =
KeyboardShortcutGroup(
"Standard app group 1",
- listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
+ listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3),
)
.apply { packageName = standardPackageName1 }
+ private val standardSystemAppSubcategoryWithCustomHomeShortcut =
+ ShortcutSubCategory("System controls", listOf(customGoHomeShortcut))
+
private val standardSubCategory1 =
ShortcutSubCategory(
standardGroup1.label!!.toString(),
- listOf(standardShortcut1, standardShortcut2, standardShortcut3)
+ listOf(standardShortcut1, standardShortcut2, standardShortcut3),
)
private val standardGroup2 =
KeyboardShortcutGroup(
"Standard group 2",
- listOf(standardShortcutInfo3, standardShortcutInfo2, standardShortcutInfo1)
+ listOf(standardShortcutInfo3, standardShortcutInfo2, standardShortcutInfo1),
)
private val standardSubCategory2 =
ShortcutSubCategory(
standardGroup2.label!!.toString(),
- listOf(standardShortcut3, standardShortcut2, standardShortcut1)
+ listOf(standardShortcut3, standardShortcut2, standardShortcut1),
)
private val standardGroup3 =
KeyboardShortcutGroup(
"Standard group 3",
- listOf(standardShortcutInfo2, standardShortcutInfo1)
+ listOf(standardShortcutInfo2, standardShortcutInfo1),
)
private val standardSubCategory3 =
ShortcutSubCategory(
standardGroup3.label!!.toString(),
- listOf(standardShortcut2, standardShortcut1)
+ listOf(standardShortcut2, standardShortcut1),
+ )
+
+ private val systemSubCategoryWithGoHomeShortcuts =
+ ShortcutSubCategory(
+ label = "System controls",
+ shortcuts =
+ listOf(
+ shortcut("Go to home screen") {
+ command {
+ key("Ctrl")
+ key("Alt")
+ key("B")
+ }
+ command {
+ key("Ctrl")
+ key("Alt")
+ key("A")
+ isCustom(true)
+ }
+ }
+ ),
)
+
val imeGroups = listOf(standardGroup1, standardGroup2, standardGroup3)
val imeCategory =
ShortcutCategory(
@@ -235,8 +289,8 @@ object TestShortcuts {
subCategoryForInputLanguageSwitchShortcuts,
standardSubCategory1,
standardSubCategory2,
- standardSubCategory3
- )
+ standardSubCategory3,
+ ),
)
val currentAppGroups = listOf(standardAppGroup1)
@@ -245,15 +299,33 @@ object TestShortcuts {
val systemGroups = listOf(standardGroup3, standardGroup2, standardGroup1)
val systemCategory =
ShortcutCategory(
- type = ShortcutCategoryType.System,
- subCategories = listOf(standardSubCategory3, standardSubCategory2, standardSubCategory1)
+ type = System,
+ subCategories = listOf(standardSubCategory3, standardSubCategory2, standardSubCategory1),
+ )
+
+ val systemCategoryWithMergedGoHomeShortcut =
+ ShortcutCategory(
+ type = System,
+ subCategories = listOf(systemSubCategoryWithGoHomeShortcuts),
+ )
+
+ val systemCategoryWithCustomHomeShortcut =
+ ShortcutCategory(
+ type = System,
+ subCategories =
+ listOf(
+ standardSubCategory3,
+ standardSubCategory2,
+ standardSubCategory1,
+ standardSystemAppSubcategoryWithCustomHomeShortcut,
+ ),
)
val multitaskingGroups = listOf(standardGroup2, standardGroup1)
val multitaskingCategory =
ShortcutCategory(
- type = ShortcutCategoryType.MultiTasking,
- subCategories = listOf(standardSubCategory2, standardSubCategory1)
+ type = MultiTasking,
+ subCategories = listOf(standardSubCategory2, standardSubCategory1),
)
val groupsWithDuplicateShortcutLabels =
@@ -266,14 +338,14 @@ object TestShortcuts {
listOf(
subCategoryForInputLanguageSwitchShortcuts,
subCategoryWithGroupedRepeatedShortcutLabels,
- subCategoryWithStandardShortcut
+ subCategoryWithStandardShortcut,
)
val groupsWithUnsupportedModifier =
listOf(
groupWithStandardShortcutInfo,
groupWithOnlyUnsupportedModifierShortcut,
- groupWithSupportedAndUnsupportedModifierShortcut
+ groupWithSupportedAndUnsupportedModifierShortcut,
)
val subCategoriesWithUnsupportedModifiersRemoved =
@@ -283,8 +355,174 @@ object TestShortcuts {
listOf(
subCategoryForInputLanguageSwitchShortcuts,
subCategoryWithStandardShortcut,
- subCategoryWithUnsupportedShortcutsRemoved
+ subCategoryWithUnsupportedShortcutsRemoved,
)
val groupsWithOnlyUnsupportedModifiers = listOf(groupWithOnlyUnsupportedModifierShortcut)
+
+ private fun simpleInputGestureData(
+ keyCode: Int = KeyEvent.KEYCODE_A,
+ modifiers: Int = KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON,
+ keyGestureType: Int,
+ ): InputGestureData {
+ val builder = InputGestureData.Builder()
+ builder.setKeyGestureType(keyGestureType)
+ builder.setTrigger(createKeyTrigger(keyCode, modifiers))
+ return builder.build()
+ }
+
+ private fun simpleShortcutCategory(
+ category: ShortcutCategoryType,
+ subcategoryLabel: String,
+ shortcutLabel: String,
+ ): ShortcutCategory {
+ return ShortcutCategory(
+ type = category,
+ subCategories =
+ listOf(
+ ShortcutSubCategory(
+ label = subcategoryLabel,
+ shortcuts = listOf(simpleShortcut(shortcutLabel)),
+ )
+ ),
+ )
+ }
+
+ private fun simpleShortcut(label: String) =
+ Shortcut(
+ label = label,
+ commands =
+ listOf(
+ ShortcutCommand(
+ isCustom = true,
+ keys =
+ listOf(
+ ShortcutKey.Text("Ctrl"),
+ ShortcutKey.Text("Alt"),
+ ShortcutKey.Text("A"),
+ ),
+ )
+ ),
+ )
+
+ val customizableInputGestureWithUnknownKeyGestureType =
+ // These key gesture events are currently not supported by shortcut helper customizer
+ listOf(
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS
+ ),
+ simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY),
+ )
+
+ val expectedShortcutCategoriesWithSimpleShortcutCombination =
+ listOf(
+ simpleShortcutCategory(System, "System apps", "Open assistant"),
+ simpleShortcutCategory(System, "System controls", "Go to home screen"),
+ simpleShortcutCategory(System, "System apps", "Open settings"),
+ simpleShortcutCategory(System, "System controls", "Lock screen"),
+ simpleShortcutCategory(System, "System controls", "View notifications"),
+ simpleShortcutCategory(System, "System apps", "Take a note"),
+ simpleShortcutCategory(System, "System controls", "Take screenshot"),
+ simpleShortcutCategory(System, "System controls", "Go back"),
+ simpleShortcutCategory(
+ MultiTasking,
+ "Split screen",
+ "Switch from split screen to full screen",
+ ),
+ simpleShortcutCategory(
+ MultiTasking,
+ "Split screen",
+ "Use split screen with current app on the left",
+ ),
+ simpleShortcutCategory(
+ MultiTasking,
+ "Split screen",
+ "Switch to app on left or above while using split screen",
+ ),
+ simpleShortcutCategory(
+ MultiTasking,
+ "Split screen",
+ "Use split screen with current app on the right",
+ ),
+ simpleShortcutCategory(
+ MultiTasking,
+ "Split screen",
+ "Switch to app on right or below while using split screen",
+ ),
+ simpleShortcutCategory(System, "System controls", "Show shortcuts"),
+ simpleShortcutCategory(System, "System controls", "View recent apps"),
+ simpleShortcutCategory(AppCategories, "Applications", "Calculator"),
+ simpleShortcutCategory(AppCategories, "Applications", "Calendar"),
+ simpleShortcutCategory(AppCategories, "Applications", "Browser"),
+ simpleShortcutCategory(AppCategories, "Applications", "Contacts"),
+ simpleShortcutCategory(AppCategories, "Applications", "Email"),
+ simpleShortcutCategory(AppCategories, "Applications", "Maps"),
+ simpleShortcutCategory(AppCategories, "Applications", "SMS"),
+ simpleShortcutCategory(MultiTasking, "Recent apps", "Cycle forward through recent apps"),
+ )
+ val customInputGestureTypeHome =
+ simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+
+ val allCustomizableInputGesturesWithSimpleShortcutCombinations =
+ listOf(
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT
+ ),
+ simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS
+ ),
+ simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
+ ),
+ simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
+ ),
+ simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
+ ),
+ simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING
+ ),
+ simpleInputGestureData(
+ keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
+ ),
+ )
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
index 57c8b444b922..f7c77017e239 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
@@ -16,12 +16,24 @@
package com.android.systemui.keyboard.shortcut.domain.interactor
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.hardware.input.InputGestureData
+import android.hardware.input.fakeInputManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allCustomizableInputGesturesWithSimpleShortcutCombinations
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.customInputGestureTypeHome
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.groupWithGoHomeShortcutInfo
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.systemCategoryWithCustomHomeShortcut
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.systemCategoryWithMergedGoHomeShortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.InputMethodEditor
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
@@ -34,6 +46,8 @@ import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSourc
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.userTracker
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -42,13 +56,18 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
+ private val mockUserContext: Context = mock()
private val systemShortcutsSource = FakeKeyboardShortcutGroupsSource()
private val multitaskingShortcutsSource = FakeKeyboardShortcutGroupsSource()
+
@OptIn(ExperimentalCoroutinesApi::class)
private val kosmos =
testKosmos().also {
@@ -57,17 +76,23 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
it.shortcutHelperMultiTaskingShortcutsSource = multitaskingShortcutsSource
it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
}
+ private val fakeInputManager = kosmos.fakeInputManager
private val testScope = kosmos.testScope
- private val interactor = kosmos.shortcutHelperCategoriesInteractor
+ private lateinit var interactor: ShortcutHelperCategoriesInteractor
private val helper = kosmos.shortcutHelperTestHelper
+ private val inter by lazy { kosmos.shortcutHelperCategoriesInteractor }
@Before
fun setShortcuts() {
+ interactor = kosmos.shortcutHelperCategoriesInteractor
helper.setImeShortcuts(TestShortcuts.imeGroups)
systemShortcutsSource.setGroups(TestShortcuts.systemGroups)
multitaskingShortcutsSource.setGroups(TestShortcuts.multitaskingGroups)
+ whenever(mockUserContext.getSystemService(INPUT_SERVICE))
+ .thenReturn(fakeInputManager.inputManager)
}
@Test
@@ -120,7 +145,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
ShortcutCategory(
type = InputMethodEditor,
subCategories =
- TestShortcuts.imeSubCategoriesWithGroupedDuplicatedShortcutLabels
+ TestShortcuts.imeSubCategoriesWithGroupedDuplicatedShortcutLabels,
),
)
.inOrder()
@@ -140,7 +165,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
ShortcutCategory(
type = System,
subCategories =
- TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+ TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels,
),
TestShortcuts.multitaskingCategory,
TestShortcuts.imeCategory,
@@ -163,7 +188,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
ShortcutCategory(
type = MultiTasking,
subCategories =
- TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+ TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels,
),
TestShortcuts.imeCategory,
)
@@ -185,7 +210,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
ShortcutCategory(
type = InputMethodEditor,
subCategories =
- TestShortcuts.imeSubCategoriesWithUnsupportedModifiersRemoved
+ TestShortcuts.imeSubCategoriesWithUnsupportedModifiersRemoved,
),
)
.inOrder()
@@ -203,7 +228,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
.containsExactly(
ShortcutCategory(
type = System,
- subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+ subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved,
),
TestShortcuts.multitaskingCategory,
TestShortcuts.imeCategory,
@@ -224,7 +249,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
TestShortcuts.systemCategory,
ShortcutCategory(
type = MultiTasking,
- subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+ subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved,
),
TestShortcuts.imeCategory,
)
@@ -240,10 +265,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
helper.showFromActivity()
assertThat(categories)
- .containsExactly(
- TestShortcuts.multitaskingCategory,
- TestShortcuts.imeCategory,
- )
+ .containsExactly(TestShortcuts.multitaskingCategory, TestShortcuts.imeCategory)
.inOrder()
}
@@ -256,10 +278,63 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
helper.showFromActivity()
assertThat(categories)
+ .containsExactly(TestShortcuts.systemCategory, TestShortcuts.imeCategory)
+ .inOrder()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_KEYBOARD_SHORTCUT_HELPER_SHORTCUT_CUSTOMIZER)
+ fun categories_excludesCustomShortcutsWhenFlagIsOff() {
+ testScope.runTest {
+ setCustomInputGestures(allCustomizableInputGesturesWithSimpleShortcutCombinations)
+ helper.showFromActivity()
+ val categories by collectLastValue(interactor.shortcutCategories)
+ assertThat(categories)
.containsExactly(
TestShortcuts.systemCategory,
+ TestShortcuts.multitaskingCategory,
+ TestShortcuts.imeCategory,
+ )
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_KEYBOARD_SHORTCUT_HELPER_SHORTCUT_CUSTOMIZER)
+ fun categories_includesCustomShortcutsWhenFlagIsOn() {
+ testScope.runTest {
+ setCustomInputGestures(listOf(customInputGestureTypeHome))
+ helper.showFromActivity()
+ val categories by collectLastValue(interactor.shortcutCategories)
+ assertThat(categories)
+ .containsExactly(
+ systemCategoryWithCustomHomeShortcut,
+ TestShortcuts.multitaskingCategory,
+ TestShortcuts.imeCategory,
+ )
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_KEYBOARD_SHORTCUT_HELPER_SHORTCUT_CUSTOMIZER)
+ fun categories_correctlyMergesDefaultAndCustomShortcutsOfSameType() {
+ testScope.runTest {
+ setCustomInputGestures(listOf(customInputGestureTypeHome))
+ systemShortcutsSource.setGroups(groupWithGoHomeShortcutInfo)
+ helper.showFromActivity()
+
+ val categories by collectLastValue(interactor.shortcutCategories)
+
+ assertThat(categories)
+ .containsExactly(
+ systemCategoryWithMergedGoHomeShortcut,
+ TestShortcuts.multitaskingCategory,
TestShortcuts.imeCategory,
)
- .inOrder()
}
+ }
+
+ private fun setCustomInputGestures(customInputGestures: List<InputGestureData>) {
+ whenever(fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull()))
+ .thenReturn(customInputGestures)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt
index 1580ea5c1272..000024f9b814 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt
@@ -16,6 +16,9 @@
package com.android.systemui.keyboard.shortcut.ui
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.hardware.input.fakeInputManager
import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -36,6 +39,8 @@ import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.activityStarter
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.userTracker
import com.android.systemui.statusbar.phone.systemUIDialogFactory
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -44,6 +49,8 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -52,7 +59,7 @@ class ShortcutHelperDialogStarterTest : SysuiTestCase() {
private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
-
+ private val mockUserContext: Context = mock()
private val kosmos =
Kosmos().also {
it.testCase = this
@@ -62,8 +69,10 @@ class ShortcutHelperDialogStarterTest : SysuiTestCase() {
it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
}
+ private val inputManager = kosmos.fakeInputManager.inputManager
private val testScope = kosmos.testScope
private val testHelper = kosmos.shortcutHelperTestHelper
private val dialogFactory = kosmos.systemUIDialogFactory
@@ -85,6 +94,7 @@ class ShortcutHelperDialogStarterTest : SysuiTestCase() {
fun setUp() {
fakeSystemSource.setGroups(TestShortcuts.systemGroups)
fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
+ whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index cad22d360508..cad22d360508 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt
new file mode 100644
index 000000000000..77c615cce287
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2024 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.quickaffordance
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.communalSceneRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalEnabled
+import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.andSceneContainer
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@EnableFlags(Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON)
+@RunWith(ParameterizedAndroidJunit4::class)
+class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private lateinit var underTest: GlanceableHubQuickAffordanceConfig
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest =
+ GlanceableHubQuickAffordanceConfig(
+ context = context,
+ communalInteractor = kosmos.communalInteractor,
+ communalSceneRepository = kosmos.communalSceneRepository,
+ sceneInteractor = kosmos.sceneInteractor,
+ )
+ }
+
+ @Test
+ fun lockscreenState_whenGlanceableHubEnabled_returnsVisible() =
+ testScope.runTest {
+ kosmos.setCommunalEnabled(true)
+ runCurrent()
+
+ val lockScreenState by collectLastValue(underTest.lockScreenState)
+
+ assertTrue(lockScreenState is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
+ }
+
+ @Test
+ fun lockscreenState_whenGlanceableHubDisabled_returnsHidden() =
+ testScope.runTest {
+ kosmos.setCommunalEnabled(false)
+ val lockScreenState by collectLastValue(underTest.lockScreenState)
+ runCurrent()
+
+ assertTrue(lockScreenState is KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+ }
+
+ @Test
+ fun pickerScreenState_whenGlanceableHubEnabled_returnsDefault() =
+ testScope.runTest {
+ kosmos.setCommunalEnabled(true)
+ runCurrent()
+
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
+ }
+
+ @Test
+ fun pickerScreenState_whenGlanceableHubDisabled_returnsDisabled() =
+ testScope.runTest {
+ kosmos.setCommunalEnabled(false)
+ runCurrent()
+
+ assertThat(
+ underTest.getPickerScreenState()
+ is KeyguardQuickAffordanceConfig.PickerScreenState.Disabled
+ )
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_SCENE_CONTAINER)
+ fun onTriggered_changesSceneToCommunal() =
+ testScope.runTest {
+ underTest.onTriggered(expandable = null)
+ runCurrent()
+
+ assertThat(kosmos.communalSceneRepository.currentScene.value)
+ .isEqualTo(CommunalScenes.Communal)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_SCENE_CONTAINER)
+ fun testTransitionToGlanceableHub_sceneContainer() =
+ testScope.runTest {
+ underTest.onTriggered(expandable = null)
+ runCurrent()
+
+ assertThat(kosmos.sceneContainerRepository.currentScene.value)
+ .isEqualTo(Scenes.Communal)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf(
+ Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON
+ )
+ .andSceneContainer()
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index 032979447861..0a4198a99bba 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -32,7 +32,8 @@ import java.util.Optional
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -125,14 +126,11 @@ class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTes
)
underTest =
- HomeControlsKeyguardQuickAffordanceConfig(
- context = context,
- component = component,
- )
+ HomeControlsKeyguardQuickAffordanceConfig(context = context, component = component)
}
@Test
- fun state() = runBlockingTest {
+ fun state() = runTest(UnconfinedTestDispatcher()) {
whenever(component.isEnabled()).thenReturn(isFeatureEnabled)
whenever(controlsController.getFavorites())
.thenReturn(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 7d68cc0a3560..0003d07d1e2f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -19,19 +19,20 @@ package com.android.systemui.keyguard.data.quickaffordance
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Expandable
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
+import com.android.systemui.res.R
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,14 +55,11 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
underTest =
- HomeControlsKeyguardQuickAffordanceConfig(
- context = context,
- component = component,
- )
+ HomeControlsKeyguardQuickAffordanceConfig(context = context, component = component)
}
@Test
- fun state_whenCannotShowWhileLocked_returnsHidden() = runBlockingTest {
+ fun state_whenCannotShowWhileLocked_returnsHidden() = runTest(UnconfinedTestDispatcher()) {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
whenever(component.isEnabled()).thenReturn(true)
whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
@@ -81,7 +79,7 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun state_whenListingControllerIsMissing_returnsHidden() = runBlockingTest {
+ fun state_whenListingControllerIsMissing_returnsHidden() = runTest(UnconfinedTestDispatcher()) {
whenever(component.isEnabled()).thenReturn(true)
whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
whenever(component.getTileTitleId()).thenReturn(R.string.quick_controls_title)
@@ -100,23 +98,26 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsTrue() = runBlockingTest {
- whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
+ fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsTrue() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
- val onClickedResult = underTest.onTriggered(expandable)
+ val onClickedResult = underTest.onTriggered(expandable)
- assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
- assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked).isTrue()
- }
+ assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
+ assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked)
+ .isTrue()
+ }
@Test
- fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsFalse() = runBlockingTest {
- whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
+ fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsFalse() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
- val onClickedResult = underTest.onTriggered(expandable)
+ val onClickedResult = underTest.onTriggered(expandable)
- assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
- assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked)
- .isFalse()
- }
+ assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
+ assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked)
+ .isFalse()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index ca64cec98b2e..05a74c038cc1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -29,7 +29,7 @@ import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -56,60 +56,63 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun affordance_setsUpRegistrationAndDeliversInitialModel() = runBlockingTest {
- whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
- var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
-
- val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+ fun affordance_setsUpRegistrationAndDeliversInitialModel() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+
+ val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+ verify(controller).addCallback(callbackCaptor.capture())
+ verify(controller)
+ .registerQRCodeScannerChangeObservers(
+ QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
+ QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE,
+ )
+ assertVisibleState(latest)
- val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
- verify(controller).addCallback(callbackCaptor.capture())
- verify(controller)
- .registerQRCodeScannerChangeObservers(
- QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
- QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE
- )
- assertVisibleState(latest)
-
- job.cancel()
- verify(controller).removeCallback(callbackCaptor.value)
- }
+ job.cancel()
+ verify(controller).removeCallback(callbackCaptor.value)
+ }
@Test
- fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() = runBlockingTest {
- whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
- var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
- verify(controller).addCallback(callbackCaptor.capture())
+ fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+ val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+ verify(controller).addCallback(callbackCaptor.capture())
- whenever(controller.intent).thenReturn(INTENT_2)
- callbackCaptor.value.onQRCodeScannerActivityChanged()
+ whenever(controller.intent).thenReturn(INTENT_2)
+ callbackCaptor.value.onQRCodeScannerActivityChanged()
- assertVisibleState(latest)
+ assertVisibleState(latest)
- job.cancel()
- verify(controller).removeCallback(callbackCaptor.value)
- }
+ job.cancel()
+ verify(controller).removeCallback(callbackCaptor.value)
+ }
@Test
- fun affordance_scannerPreferenceChanged_deliversVisibleModel() = runBlockingTest {
- var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
- verify(controller).addCallback(callbackCaptor.capture())
+ fun affordance_scannerPreferenceChanged_deliversVisibleModel() =
+ runTest(UnconfinedTestDispatcher()) {
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+ val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+ verify(controller).addCallback(callbackCaptor.capture())
- whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
- callbackCaptor.value.onQRCodeScannerPreferenceChanged()
+ whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+ callbackCaptor.value.onQRCodeScannerPreferenceChanged()
- assertVisibleState(latest)
+ assertVisibleState(latest)
- job.cancel()
- verify(controller).removeCallback(callbackCaptor.value)
- }
+ job.cancel()
+ verify(controller).removeCallback(callbackCaptor.value)
+ }
@Test
- fun affordance_scannerPreferenceChanged_deliversNone() = runBlockingTest {
+ fun affordance_scannerPreferenceChanged_deliversNone() = runTest(UnconfinedTestDispatcher()) {
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
@@ -128,30 +131,29 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
fun onQuickAffordanceTriggered() {
assertThat(underTest.onTriggered(mock()))
.isEqualTo(
- OnTriggeredResult.StartActivity(
- intent = INTENT_1,
- canShowWhileLocked = true,
- )
+ OnTriggeredResult.StartActivity(intent = INTENT_1, canShowWhileLocked = true)
)
}
@Test
- fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() = runTest {
- whenever(controller.isAllowedOnLockScreen).thenReturn(true)
- whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true)
+ fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(controller.isAllowedOnLockScreen).thenReturn(true)
+ whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true)
- assertThat(underTest.getPickerScreenState())
- .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
- }
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
+ }
@Test
- fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() = runTest {
- whenever(controller.isAllowedOnLockScreen).thenReturn(true)
- whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false)
-
- assertThat(underTest.getPickerScreenState())
- .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
- }
+ fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(controller.isAllowedOnLockScreen).thenReturn(true)
+ whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false)
+
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.LockScreenState?) {
assertThat(latest)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
index 4e429c34bf2a..69fb03dc6433 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
@@ -47,7 +47,8 @@ import com.android.systemui.keyguard.data.repository.BiometricType.SIDE_FINGERPR
import com.android.systemui.keyguard.data.repository.BiometricType.UNDER_DISPLAY_FINGERPRINT
import com.android.systemui.keyguard.shared.model.DevicePosture
import com.android.systemui.res.R
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -99,7 +100,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
private lateinit var devicePostureRepository: FakeDevicePostureRepository
private lateinit var facePropertyRepository: FakeFacePropertyRepository
private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
- private val mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
+ private val mobileConnectionsRepository = kosmos.mobileConnectionsRepository
private lateinit var testDispatcher: TestDispatcher
private lateinit var testScope: TestScope
@@ -142,7 +143,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
1,
SensorStrength.STRONG,
FingerprintSensorType.UDFPS_OPTICAL,
- emptyMap()
+ emptyMap(),
)
verify(lockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture())
verify(authController, times(2)).addCallback(authControllerCallback.capture())
@@ -247,7 +248,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
private fun deviceIsInPostureThatSupportsFaceAuth() {
overrideResource(
R.integer.config_face_auth_supported_posture,
- DevicePostureController.DEVICE_POSTURE_FLIPPED
+ DevicePostureController.DEVICE_POSTURE_FLIPPED,
)
devicePostureRepository.setCurrentPosture(DevicePosture.FLIPPED)
}
@@ -459,7 +460,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
biometricsAreEnabledBySettings()
doNotDisableKeyguardAuthFeatures()
- mobileConnectionsRepository.isAnySimSecure.value = false
+ mobileConnectionsRepository.fake.isAnySimSecure.value = false
runCurrent()
val isFaceAuthEnabledAndEnrolled by
@@ -467,7 +468,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
assertThat(isFaceAuthEnabledAndEnrolled).isTrue()
- mobileConnectionsRepository.isAnySimSecure.value = true
+ mobileConnectionsRepository.fake.isAnySimSecure.value = true
runCurrent()
assertThat(isFaceAuthEnabledAndEnrolled).isFalse()
@@ -485,13 +486,13 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
doNotDisableKeyguardAuthFeatures()
faceAuthIsStrongBiometric()
biometricsAreEnabledBySettings()
- mobileConnectionsRepository.isAnySimSecure.value = false
+ mobileConnectionsRepository.fake.isAnySimSecure.value = false
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
assertThat(isFaceAuthCurrentlyAllowed).isTrue()
- mobileConnectionsRepository.isAnySimSecure.value = true
+ mobileConnectionsRepository.fake.isAnySimSecure.value = true
assertThat(isFaceAuthCurrentlyAllowed).isFalse()
}
@@ -584,7 +585,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
testScope.runTest {
overrideResource(
R.integer.config_face_auth_supported_posture,
- DevicePostureController.DEVICE_POSTURE_UNKNOWN
+ DevicePostureController.DEVICE_POSTURE_UNKNOWN,
)
createBiometricSettingsRepository()
@@ -597,7 +598,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
testScope.runTest {
overrideResource(
R.integer.config_face_auth_supported_posture,
- DevicePostureController.DEVICE_POSTURE_FLIPPED
+ DevicePostureController.DEVICE_POSTURE_FLIPPED,
)
createBiometricSettingsRepository()
@@ -749,7 +750,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
1,
SensorStrength.STRONG,
FingerprintSensorType.UDFPS_OPTICAL,
- emptyMap()
+ emptyMap(),
)
// Non strong auth is not allowed now, FP is marked strong
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
@@ -761,7 +762,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
1,
SensorStrength.CONVENIENCE,
FingerprintSensorType.UDFPS_OPTICAL,
- emptyMap()
+ emptyMap(),
)
assertThat(isFingerprintCurrentlyAllowed).isFalse()
@@ -769,7 +770,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
1,
SensorStrength.WEAK,
FingerprintSensorType.UDFPS_OPTICAL,
- emptyMap()
+ emptyMap(),
)
assertThat(isFingerprintCurrentlyAllowed).isFalse()
}
@@ -791,7 +792,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
1,
SensorStrength.STRONG,
FingerprintSensorType.UDFPS_OPTICAL,
- emptyMap()
+ emptyMap(),
)
// Non strong auth is not allowed now, FP is marked strong
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
@@ -830,7 +831,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
UserInfo(
/* id= */ PRIMARY_USER_ID,
/* name= */ "primary user",
- /* flags= */ UserInfo.FLAG_PRIMARY
+ /* flags= */ UserInfo.FLAG_PRIMARY,
)
private const val ANOTHER_USER_ID = 1
@@ -838,7 +839,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
UserInfo(
/* id= */ ANOTHER_USER_ID,
/* name= */ "another user",
- /* flags= */ UserInfo.FLAG_PRIMARY
+ /* flags= */ UserInfo.FLAG_PRIMARY,
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
index 5a597fe8e920..f537e32ac13d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
@@ -50,7 +50,6 @@ class KeyguardSmartspaceRepositoryImplTest : SysuiTestCase() {
fakeSettings.userId = fakeUserTracker.userId
underTest =
KeyguardSmartspaceRepositoryImpl(
- context = context,
secureSettings = fakeSettings,
userTracker = fakeUserTracker,
applicationScope = scope.backgroundScope,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 3d5498b61471..7a3089f33276 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -527,6 +527,29 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
assertEquals(0, steps.size)
}
+ @Test
+ fun testForceFinishCurrentTransition_noTransitionRunning_unlocksMutex() =
+ testScope.runTest {
+ val steps by collectValues(underTest.transitions.dropWhile { step -> step.from == OFF })
+ underTest.forceFinishCurrentTransition()
+
+ assertThat(steps.isEmpty())
+
+ underTest.forceFinishCurrentTransition()
+ runCurrent()
+
+ assertThat(steps.isEmpty())
+ runner.startTransition(
+ this,
+ TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, getAnimator()),
+ maxFrames = 100,
+ )
+
+ advanceTimeBy(5000L)
+
+ assertThat(steps.isNotEmpty())
+ }
+
private fun listWithStep(
step: BigDecimal,
start: BigDecimal = BigDecimal.ZERO,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt
index aee72de22a24..28ac169e2bbe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt
@@ -310,7 +310,7 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() {
// read during initialization to set up flows. Maybe there is a better way to handle that.
underTest =
KeyguardTouchHandlingInteractor(
- appContext = mContext,
+ context = mContext,
scope = testScope.backgroundScope,
transitionInteractor = kosmos.keyguardTransitionInteractor,
repository = keyguardRepository,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 2c12f8782ddc..e60a52c12c0b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -24,6 +24,7 @@ import com.android.systemui.authentication.data.repository.FakeAuthenticationRep
import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
@@ -34,10 +35,12 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.data.model.sceneStackOf
import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.Transition
-import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
@@ -85,7 +88,7 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
fun setUp() {
// lazy value needs to be called here otherwise flow collection misbehaves
underTest.value
- kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
+ kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Lockscreen))
}
@Test
@@ -967,15 +970,56 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
@Test
@EnableSceneContainer
+ fun lockscreenVisibilityWithScenes_staysTrue_despiteEnteringIndirectly() =
+ testScope.runTest {
+ val isDeviceUnlocked by
+ collectLastValue(
+ kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+ )
+ assertThat(isDeviceUnlocked).isFalse()
+
+ val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+ val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+ assertThat(lockscreenVisibility).isTrue()
+
+ kosmos.setSceneTransition(Idle(Scenes.Shade))
+ kosmos.sceneInteractor.changeScene(Scenes.Shade, "")
+ kosmos.sceneBackInteractor.onSceneChange(from = Scenes.Lockscreen, to = Scenes.Shade)
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(lockscreenVisibility).isTrue()
+ val sceneBackStack by collectLastValue(kosmos.sceneBackInteractor.backStack)
+ assertThat(sceneBackStack?.asIterable()?.toList()).isEqualTo(listOf(Scenes.Lockscreen))
+
+ val isDeviceEntered by collectLastValue(kosmos.deviceEntryInteractor.isDeviceEntered)
+ val isDeviceEnteredDirectly by
+ collectLastValue(kosmos.deviceEntryInteractor.isDeviceEnteredDirectly)
+ runCurrent()
+ assertThat(isDeviceEntered).isFalse()
+ assertThat(isDeviceEnteredDirectly).isFalse()
+
+ kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+ kosmos.sceneBackInteractor.updateBackStack { sceneStackOf(Scenes.Gone) }
+ assertThat(sceneBackStack?.asIterable()?.toList()).isEqualTo(listOf(Scenes.Gone))
+
+ assertThat(isDeviceEntered).isTrue()
+ assertThat(isDeviceEnteredDirectly).isFalse()
+ assertThat(isDeviceUnlocked).isTrue()
+ assertThat(lockscreenVisibility).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
fun sceneContainer_usingGoingAwayAnimation_duringTransitionToGone() =
testScope.runTest {
val usingKeyguardGoingAwayAnimation by
collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
- sceneTransitions.value = lsToGone
+ kosmos.setSceneTransition(lsToGone)
assertThat(usingKeyguardGoingAwayAnimation).isTrue()
- sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone))
assertThat(usingKeyguardGoingAwayAnimation).isFalse()
}
@@ -986,14 +1030,14 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
val usingKeyguardGoingAwayAnimation by
collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
- sceneTransitions.value = lsToGone
+ kosmos.setSceneTransition(lsToGone)
surfaceBehindIsAnimatingFlow.emit(true)
assertThat(usingKeyguardGoingAwayAnimation).isTrue()
- sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone))
assertThat(usingKeyguardGoingAwayAnimation).isTrue()
- sceneTransitions.value = goneToLs
+ kosmos.setSceneTransition(goneToLs)
assertThat(usingKeyguardGoingAwayAnimation).isTrue()
surfaceBehindIsAnimatingFlow.emit(false)
@@ -1003,11 +1047,6 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
companion object {
private val progress = MutableStateFlow(0f)
- private val sceneTransitions =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(Scenes.Lockscreen)
- )
-
private val lsToGone =
ObservableTransitionState.Transition(
Scenes.Lockscreen,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 92764ae94271..74a0bafda931 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -17,6 +17,10 @@
package com.android.systemui.keyguard.ui.binder
import android.app.IActivityTaskManager
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -25,8 +29,10 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransition
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
+import com.android.window.flags.Flags
import com.android.wm.shell.keyguard.KeyguardTransitions
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
@@ -41,6 +47,9 @@ import org.mockito.kotlin.any
@RunWith(AndroidJUnit4::class)
@kotlinx.coroutines.ExperimentalCoroutinesApi
class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
+
+ @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
private lateinit var underTest: WindowManagerLockscreenVisibilityManager
private lateinit var executor: FakeExecutor
@@ -68,32 +77,62 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
}
@Test
- fun testLockscreenVisible_andAodVisible() {
+ @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testLockscreenVisible_andAodVisible_without_keyguard_shell_transitions() {
underTest.setLockscreenShown(true)
- underTest.setAodVisible(true)
-
verify(activityTaskManagerService).setLockScreenShown(true, false)
+ underTest.setAodVisible(true)
verify(activityTaskManagerService).setLockScreenShown(true, true)
+
verifyNoMoreInteractions(activityTaskManagerService)
}
@Test
- fun testGoingAway_whenLockscreenVisible_thenSurfaceMadeVisible() {
+ @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testLockscreenVisible_andAodVisible_with_keyguard_shell_transitions() {
underTest.setLockscreenShown(true)
+ verify(keyguardTransitions).startKeyguardTransition(true, false)
underTest.setAodVisible(true)
+ verify(keyguardTransitions).startKeyguardTransition(true, true)
+ verifyNoMoreInteractions(keyguardTransitions)
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testGoingAway_whenLockscreenVisible_thenSurfaceMadeVisible_without_keyguard_shell_transitions() {
+ underTest.setLockscreenShown(true)
verify(activityTaskManagerService).setLockScreenShown(true, false)
+ underTest.setAodVisible(true)
verify(activityTaskManagerService).setLockScreenShown(true, true)
+
verifyNoMoreInteractions(activityTaskManagerService)
underTest.setSurfaceBehindVisibility(true)
-
verify(activityTaskManagerService).keyguardGoingAway(anyInt())
+
verifyNoMoreInteractions(activityTaskManagerService)
}
@Test
- fun testSurfaceVisible_whenLockscreenNotShowing_doesNotTriggerGoingAway() {
+ @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testGoingAway_whenLockscreenVisible_thenSurfaceMadeVisible_with_keyguard_shell_transitions() {
+ underTest.setLockscreenShown(true)
+ verify(keyguardTransitions).startKeyguardTransition(true, false)
+ underTest.setAodVisible(true)
+ verify(keyguardTransitions).startKeyguardTransition(true, true)
+
+ verifyNoMoreInteractions(keyguardTransitions)
+
+ underTest.setSurfaceBehindVisibility(true)
+ verify(keyguardTransitions).startKeyguardTransition(false, false)
+
+ verifyNoMoreInteractions(keyguardTransitions)
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testSurfaceVisible_whenLockscreenNotShowing_doesNotTriggerGoingAway_without_keyguard_shell_transitions() {
underTest.setLockscreenShown(false)
underTest.setAodVisible(false)
@@ -106,7 +145,22 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
}
@Test
- fun testAodVisible_noLockscreenShownCallYet_doesNotShowLockscreenUntilLater() {
+ @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testSurfaceVisible_whenLockscreenNotShowing_doesNotTriggerGoingAway_with_keyguard_shell_transitions() {
+ underTest.setLockscreenShown(false)
+ underTest.setAodVisible(false)
+
+ verify(keyguardTransitions).startKeyguardTransition(false, false)
+ verifyNoMoreInteractions(keyguardTransitions)
+
+ underTest.setSurfaceBehindVisibility(true)
+
+ verifyNoMoreInteractions(keyguardTransitions)
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testAodVisible_noLockscreenShownCallYet_doesNotShowLockscreenUntilLater_without_keyguard_shell_transitions() {
underTest.setAodVisible(false)
verifyNoMoreInteractions(activityTaskManagerService)
@@ -116,7 +170,19 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
}
@Test
- fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall() {
+ @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun testAodVisible_noLockscreenShownCallYet_doesNotShowLockscreenUntilLater_with_keyguard_shell_transitions() {
+ underTest.setAodVisible(false)
+ verifyNoMoreInteractions(keyguardTransitions)
+
+ underTest.setLockscreenShown(true)
+ verify(keyguardTransitions).startKeyguardTransition(true, false)
+ verifyNoMoreInteractions(activityTaskManagerService)
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall_without_keyguard_shell_transitions() {
underTest.setLockscreenShown(true)
underTest.setSurfaceBehindVisibility(true)
verify(activityTaskManagerService).keyguardGoingAway(0)
@@ -126,8 +192,27 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
}
@Test
- fun setSurfaceBehindVisibility_falseSetsLockscreenVisibility() {
+ @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall_with_keyguard_shell_transitions() {
+ underTest.setLockscreenShown(true)
+ underTest.setSurfaceBehindVisibility(true)
+ verify(keyguardTransitions).startKeyguardTransition(false, false)
+
+ underTest.setSurfaceBehindVisibility(true)
+ verifyNoMoreInteractions(keyguardTransitions)
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun setSurfaceBehindVisibility_falseSetsLockscreenVisibility_without_keyguard_shell_transitions() {
underTest.setSurfaceBehindVisibility(false)
verify(activityTaskManagerService).setLockScreenShown(eq(true), any())
}
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+ fun setSurfaceBehindVisibility_falseSetsLockscreenVisibility_with_keyguard_shell_transitions() {
+ underTest.setSurfaceBehindVisibility(false)
+ verify(keyguardTransitions).startKeyguardTransition(eq(true), any())
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
index d94c97af6f14..c0db95f9e5d2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
@@ -34,6 +34,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteract
import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import com.android.systemui.util.mockito.any
@@ -68,6 +69,7 @@ class SmartspaceSectionTest : SysuiTestCase() {
private val clockShouldBeCentered = MutableStateFlow(false)
private val hasCustomWeatherDataDisplay = MutableStateFlow(false)
private val isWeatherVisibleFlow = MutableStateFlow(false)
+ private val isShadeLayoutWide = MutableStateFlow(false)
@Before
fun setup() {
@@ -80,7 +82,7 @@ class SmartspaceSectionTest : SysuiTestCase() {
keyguardSmartspaceInteractor,
lockscreenSmartspaceController,
keyguardUnlockAnimationController,
- blueprintInteractor
+ blueprintInteractor,
)
constraintLayout = ConstraintLayout(mContext)
whenever(lockscreenSmartspaceController.buildAndConnectView(any()))
@@ -93,6 +95,7 @@ class SmartspaceSectionTest : SysuiTestCase() {
whenever(keyguardClockViewModel.clockShouldBeCentered).thenReturn(clockShouldBeCentered)
whenever(keyguardSmartspaceViewModel.isSmartspaceEnabled).thenReturn(true)
whenever(keyguardSmartspaceViewModel.isWeatherVisible).thenReturn(isWeatherVisibleFlow)
+ whenever(keyguardSmartspaceViewModel.isShadeLayoutWide).thenReturn(isShadeLayoutWide)
constraintSet = ConstraintSet()
}
@@ -125,6 +128,26 @@ class SmartspaceSectionTest : SysuiTestCase() {
}
@Test
+ fun testConstraintsWhenShadeLayoutIsNotWide() {
+ underTest.addViews(constraintLayout)
+ underTest.applyConstraints(constraintSet)
+
+ val smartspaceConstraints = constraintSet.getConstraint(smartspaceView.id)
+ assertThat(smartspaceConstraints.layout.endToEnd).isEqualTo(ConstraintSet.PARENT_ID)
+ }
+
+ @Test
+ fun testConstraintsWhenShadeLayoutIsWide() {
+ isShadeLayoutWide.value = true
+
+ underTest.addViews(constraintLayout)
+ underTest.applyConstraints(constraintSet)
+
+ val smartspaceConstraints = constraintSet.getConstraint(smartspaceView.id)
+ assertThat(smartspaceConstraints.layout.endToEnd).isEqualTo(R.id.split_shade_guideline)
+ }
+
+ @Test
fun testConstraintsWhenNotHasCustomWeatherDataDisplay() {
whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(true)
underTest.addViews(constraintLayout)
@@ -160,6 +183,7 @@ class SmartspaceSectionTest : SysuiTestCase() {
assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(GONE)
assertThat(constraintSet.getVisibility(dateView.id)).isEqualTo(VISIBLE)
}
+
@Test
fun testCustomDateWeatherVisibility() {
hasCustomWeatherDataDisplay.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
index b0959e4eea0b..d42b538cf355 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
@@ -27,10 +27,13 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepos
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -43,6 +46,16 @@ class DeviceEntryForegroundViewModelTest : SysuiTestCase() {
private val underTest: DeviceEntryForegroundViewModel =
kosmos.deviceEntryForegroundIconViewModel
+ @Before
+ fun setup() {
+ context.orCreateTestableResources.addOverride(R.integer.udfps_padding_debounce_duration, 0)
+ }
+
+ @After
+ fun teardown() {
+ context.orCreateTestableResources.removeOverride(R.integer.udfps_padding_debounce_duration)
+ }
+
@Test
fun aodIconColorWhite() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
index 0c3fcb3ef759..adce9d65cbe0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.keyguard.data.repository.keyguardSmartspaceRepositor
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -96,4 +97,26 @@ class KeyguardSmartspaceViewModelTest : SysuiTestCase() {
assertThat(isWeatherVisible).isEqualTo(false)
}
+
+ @Test
+ fun isShadeLayoutWide_withConfigTrue_true() =
+ with(kosmos) {
+ testScope.runTest {
+ val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
+ shadeRepository.setShadeLayoutWide(true)
+
+ assertThat(isShadeLayoutWide).isTrue()
+ }
+ }
+
+ @Test
+ fun isShadeLayoutWide_withConfigFalse_false() =
+ with(kosmos) {
+ testScope.runTest {
+ val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
+ shadeRepository.setShadeLayoutWide(false)
+
+ assertThat(isShadeLayoutWide).isFalse()
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
index 5c4b7432e18d..62cc76345c87 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
@@ -32,12 +32,11 @@ import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.power.data.repository.fakePowerRepository
@@ -48,7 +47,6 @@ import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys
import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.math.pow
@@ -69,12 +67,13 @@ import platform.test.runner.parameterized.Parameters
class LockscreenUserActionsViewModelTest : SysuiTestCase() {
companion object {
- private const val parameterCount = 6
+ private const val parameterCount = 7
@Parameters(
name =
"canSwipeToEnter={0}, downWithTwoPointers={1}, downFromEdge={2}," +
- " isSingleShade={3}, isCommunalAvailable={4}, isShadeTouchable={5}"
+ " isSingleShade={3}, isCommunalAvailable={4}, isShadeTouchable={5}," +
+ " isOccluded={6}"
)
@JvmStatic
fun combinations() = buildList {
@@ -87,6 +86,7 @@ class LockscreenUserActionsViewModelTest : SysuiTestCase() {
/* isSingleShade= */ combination and 8 != 0,
/* isCommunalAvailable= */ combination and 16 != 0,
/* isShadeTouchable= */ combination and 32 != 0,
+ /* isOccluded= */ combination and 64 != 0,
)
.also { check(it.size == parameterCount) }
)
@@ -116,10 +116,12 @@ class LockscreenUserActionsViewModelTest : SysuiTestCase() {
downFromEdge: Boolean,
isNarrowScreen: Boolean,
isShadeTouchable: Boolean,
+ isOccluded: Boolean,
): SceneKey? {
return when {
!isShadeTouchable -> null
- downFromEdge && isNarrowScreen -> Scenes.QuickSettings
+ downFromEdge && isNarrowScreen && !isOccluded -> Scenes.QuickSettings
+ downFromEdge && isNarrowScreen && isOccluded -> null
else -> Scenes.Shade
}
}
@@ -168,8 +170,9 @@ class LockscreenUserActionsViewModelTest : SysuiTestCase() {
@JvmField @Parameter(3) var isNarrowScreen: Boolean = true
@JvmField @Parameter(4) var isCommunalAvailable: Boolean = false
@JvmField @Parameter(5) var isShadeTouchable: Boolean = false
+ @JvmField @Parameter(6) var isOccluded: Boolean = false
- private val underTest by lazy { createLockscreenSceneViewModel() }
+ private val underTest by lazy { kosmos.lockscreenUserActionsViewModel }
@Test
@EnableFlags(Flags.FLAG_COMMUNAL_HUB)
@@ -196,6 +199,7 @@ class LockscreenUserActionsViewModelTest : SysuiTestCase() {
WakefulnessState.ASLEEP
}
)
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(onTop = isOccluded)
val userActions by collectLastValue(underTest.actions)
val downDestination =
@@ -217,6 +221,7 @@ class LockscreenUserActionsViewModelTest : SysuiTestCase() {
downFromEdge = downFromEdge,
isNarrowScreen = isNarrowScreen,
isShadeTouchable = isShadeTouchable,
+ isOccluded = isOccluded,
)
)
@@ -285,6 +290,7 @@ class LockscreenUserActionsViewModelTest : SysuiTestCase() {
WakefulnessState.ASLEEP
}
)
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(onTop = isOccluded)
val userActions by collectLastValue(underTest.actions)
@@ -354,12 +360,4 @@ class LockscreenUserActionsViewModelTest : SysuiTestCase() {
)
)
}
-
- private fun createLockscreenSceneViewModel(): LockscreenUserActionsViewModel {
- return LockscreenUserActionsViewModel(
- deviceEntryInteractor = kosmos.deviceEntryInteractor,
- communalInteractor = kosmos.communalInteractor,
- shadeInteractor = kosmos.shadeInteractor,
- )
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
index 51c852531697..51c852531697 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
index 02825a55923f..ff00bfb540c6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.mediaprojection.data.repository
import android.hardware.display.displayManager
import android.media.projection.MediaProjectionInfo
+import android.media.projection.StopReason
import android.os.Binder
import android.os.Handler
import android.os.UserHandle
@@ -339,8 +340,9 @@ class MediaProjectionManagerRepositoryTest : SysuiTestCase() {
@Test
fun stopProjecting_invokesManager() =
testScope.runTest {
- repo.stopProjecting()
+ repo.stopProjecting(StopReason.STOP_QS_TILE)
- verify(fakeMediaProjectionManager.mediaProjectionManager).stopActiveProjection()
+ verify(fakeMediaProjectionManager.mediaProjectionManager)
+ .stopActiveProjection(StopReason.STOP_QS_TILE)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
index 450aadd70171..ebc00c3897cb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.content.Intent
import android.graphics.drawable.Icon
import android.os.UserHandle
+import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.Bubbles
import java.util.Optional
import kotlinx.coroutines.CoroutineDispatcher
@@ -33,14 +34,29 @@ import kotlinx.coroutines.CoroutineDispatcher
class FakeNoteTaskBubbleController(
unUsed1: Context,
unsUsed2: CoroutineDispatcher,
- private val optionalBubbles: Optional<Bubbles>
+ private val optionalBubbles: Optional<Bubbles>,
) : NoteTaskBubblesController(unUsed1, unsUsed2) {
override suspend fun areBubblesAvailable() = optionalBubbles.isPresent
- override suspend fun showOrHideAppBubble(intent: Intent, userHandle: UserHandle, icon: Icon) {
+ override suspend fun showOrHideAppBubble(
+ intent: Intent,
+ userHandle: UserHandle,
+ icon: Icon,
+ bubbleExpandBehavior: NoteTaskBubbleExpandBehavior,
+ ) {
optionalBubbles.ifPresentOrElse(
- { bubbles -> bubbles.showOrHideAppBubble(intent, userHandle, icon) },
- { throw IllegalAccessException() }
+ { bubbles ->
+ if (
+ bubbleExpandBehavior == NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED &&
+ bubbles.isBubbleExpanded(
+ Bubble.getAppBubbleKeyForApp(intent.`package`, userHandle)
+ )
+ ) {
+ return@ifPresentOrElse
+ }
+ bubbles.showOrHideAppBubble(intent, userHandle, icon)
+ },
+ { throw IllegalAccessException() },
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
index 9ef6b9c13315..e55d6ad6c5a0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
@@ -21,9 +21,9 @@ import android.graphics.drawable.Icon
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskBubblesController.NoteTaskBubblesService
+import com.android.systemui.res.R
import com.android.wm.shell.bubbles.Bubbles
import com.google.common.truth.Truth.assertThat
import java.util.Optional
@@ -33,6 +33,9 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.whenever
/** atest SystemUITests:NoteTaskBubblesServiceTest */
@SmallTest
@@ -61,12 +64,40 @@ internal class NoteTaskBubblesServiceTest : SysuiTestCase() {
}
@Test
- fun showOrHideAppBubble() {
+ fun showOrHideAppBubble_defaultExpandBehavior_shouldCallBubblesApi() {
val intent = Intent()
val user = UserHandle.SYSTEM
val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+ val bubbleExpandBehavior = NoteTaskBubbleExpandBehavior.DEFAULT
+ whenever(bubbles.isBubbleExpanded(any())).thenReturn(false)
+
+ createServiceBinder().showOrHideAppBubble(intent, user, icon, bubbleExpandBehavior)
+
+ verify(bubbles).showOrHideAppBubble(intent, user, icon)
+ }
+
+ @Test
+ fun showOrHideAppBubble_keepIfExpanded_bubbleShown_shouldNotCallBubblesApi() {
+ val intent = Intent().apply { setPackage("test") }
+ val user = UserHandle.SYSTEM
+ val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+ val bubbleExpandBehavior = NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED
+ whenever(bubbles.isBubbleExpanded(any())).thenReturn(true)
+
+ createServiceBinder().showOrHideAppBubble(intent, user, icon, bubbleExpandBehavior)
+
+ verify(bubbles, never()).showOrHideAppBubble(intent, user, icon)
+ }
+
+ @Test
+ fun showOrHideAppBubble_keepIfExpanded_bubbleNotShown_shouldCallBubblesApi() {
+ val intent = Intent().apply { setPackage("test") }
+ val user = UserHandle.SYSTEM
+ val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+ val bubbleExpandBehavior = NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED
+ whenever(bubbles.isBubbleExpanded(any())).thenReturn(false)
- createServiceBinder().showOrHideAppBubble(intent, user, icon)
+ createServiceBinder().showOrHideAppBubble(intent, user, icon, bubbleExpandBehavior)
verify(bubbles).showOrHideAppBubble(intent, user, icon)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
index 8f4078b88fc0..d3578fb9f69b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
@@ -19,6 +19,7 @@ import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.notetask.NoteTaskEntryPoint.QS_NOTES_TILE
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -44,10 +45,19 @@ internal class NoteTaskInfoTest : SysuiTestCase() {
}
@Test
- fun launchMode_keyguardUnlocked_launchModeAppBubble() {
+ fun launchMode_keyguardUnlocked_launchModeAppBubble_withDefaultExpandBehavior() {
val underTest = DEFAULT_INFO.copy(isKeyguardLocked = false)
- assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.AppBubble)
+ assertThat(underTest.launchMode)
+ .isEqualTo(NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.DEFAULT))
+ }
+
+ @Test
+ fun launchMode_keyguardUnlocked_qsTileEntryPoint_launchModeAppBubble_withKeepIfExpandedExpandBehavior() {
+ val underTest = DEFAULT_INFO.copy(isKeyguardLocked = false, entryPoint = QS_NOTES_TILE)
+
+ assertThat(underTest.launchMode)
+ .isEqualTo(NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED))
}
private companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/power/PowerUITest.java
index 338ed7596bd6..338ed7596bd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/power/PowerUITest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 93dede5a3dae..f1f6c61a16e4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -38,7 +38,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.res.R;
import com.android.systemui.retail.data.repository.FakeRetailModeRepository;
-import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl;
+import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.utils.leaks.LeakCheckedTest;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 83f95eaf4cda..e9633f49f76d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -21,9 +21,6 @@ import static com.android.systemui.flags.SceneContainerFlagParameterizationKt.pa
import static com.google.common.truth.Truth.assertThat;
-import static kotlinx.coroutines.flow.FlowKt.asStateFlow;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -39,6 +36,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.flow.FlowKt.asStateFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
import android.content.res.Configuration;
import android.content.res.Resources;
import android.platform.test.annotations.DisableFlags;
@@ -70,9 +70,6 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
import com.android.systemui.util.animation.DisappearParameters;
-import kotlinx.coroutines.flow.MutableStateFlow;
-import kotlinx.coroutines.flow.StateFlow;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -88,6 +85,8 @@ import java.util.List;
import javax.inject.Provider;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlow;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
@@ -232,6 +231,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
@After
public void tearDown() {
+ mController.destroy();
disallowTestableLooperAsMainThread();
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index 02c5b5ad214c..96f6a622e2f3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -1,10 +1,10 @@
package com.android.systemui.qs
import android.content.res.Configuration
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
import android.testing.TestableResources
import android.view.ContextThemeWrapper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
@@ -37,8 +37,8 @@ import org.mockito.Mockito.any
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -81,37 +81,39 @@ class QSPanelControllerTest : SysuiTestCase() {
setShouldUseSplitShade(false)
whenever(qsPanel.resources).thenReturn(testableResources.resources)
whenever(qsPanel.context)
- .thenReturn( ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings))
+ .thenReturn(ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings))
whenever(qsPanel.getOrCreateTileLayout()).thenReturn(pagedTileLayout)
whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false)
whenever(qsPanel.setListening(anyBoolean())).then {
whenever(qsPanel.isListening).thenReturn(it.getArgument(0))
}
- controller = QSPanelController(
- qsPanel,
- tunerService,
- qsHost,
- qsCustomizerController,
- /* usingMediaPlayer= */ usingMediaPlayer,
- mediaHost,
- qsTileRevealControllerFactory,
- dumpManager,
- metricsLogger,
- uiEventLogger,
- qsLogger,
- brightnessControllerFactory,
- brightnessSliderFactory,
- falsingManager,
- statusBarKeyguardViewManager,
- ResourcesSplitShadeStateController(),
- longPressEffectProvider,
- mediaCarouselInteractor,
- )
+ controller =
+ QSPanelController(
+ qsPanel,
+ tunerService,
+ qsHost,
+ qsCustomizerController,
+ /* usingMediaPlayer= */ usingMediaPlayer,
+ mediaHost,
+ qsTileRevealControllerFactory,
+ dumpManager,
+ metricsLogger,
+ uiEventLogger,
+ qsLogger,
+ brightnessControllerFactory,
+ brightnessSliderFactory,
+ falsingManager,
+ statusBarKeyguardViewManager,
+ ResourcesSplitShadeStateController(),
+ longPressEffectProvider,
+ mediaCarouselInteractor,
+ )
}
@After
fun tearDown() {
+ controller.destroy()
reset(mediaHost)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index f6d57325bb1c..f6d57325bb1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSSecurityFooterTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 369bb228494c..7880aceb53be 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -34,6 +34,7 @@ import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.util.leak.RotationUtils
+import javax.inject.Provider
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -45,9 +46,8 @@ import org.mockito.Mockito.any
import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import javax.inject.Provider
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -108,6 +108,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
@After
fun tearDown() {
controller.onViewDetached()
+ controller.destroy()
}
@Test
@@ -184,7 +185,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
dumpManager,
ResourcesSplitShadeStateController(),
longPressEffectProvider,
- mediaCarouselInteractor
+ mediaCarouselInteractor,
) {
private var rotation = RotationUtils.ROTATION_NONE
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
index 03feceb7c15a..921a8a610c37 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.qs.composefragment.viewmodel
import android.app.StatusBarManager
import android.content.testableContext
+import android.graphics.Rect
import android.testing.TestableLooper.RunWithLooper
import androidx.compose.runtime.snapshots.Snapshot
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -40,9 +41,10 @@ import com.android.systemui.qs.panels.ui.viewmodel.setConfigurationForMediaInRow
import com.android.systemui.res.R
import com.android.systemui.shade.largeScreenHeaderHelper
import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.statusbar.sysuiStatusBarStateController
+import com.android.systemui.util.animation.DisappearParameters
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -375,6 +377,92 @@ class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest()
}
}
+ @Test
+ fun applyQsScrollPositionForClipping() =
+ with(kosmos) {
+ testScope.testWithinLifecycle {
+ val left = 1f
+ val top = 3f
+ val right = 5f
+ val bottom = 7f
+
+ underTest.applyNewQsScrollerBounds(left, top, right, bottom)
+
+ assertThat(qsMediaHost.currentClipping)
+ .isEqualTo(Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt()))
+ }
+ }
+
+ @Test
+ fun shouldUpdateMediaSquishiness_inSplitShadeFalse_mediaSquishinessSet() =
+ with(kosmos) {
+ testScope.testWithinLifecycle {
+ underTest.isInSplitShade = false
+ underTest.squishinessFraction = 0.3f
+
+ underTest.shouldUpdateSquishinessOnMedia = true
+ Snapshot.sendApplyNotifications()
+ runCurrent()
+
+ assertThat(underTest.qsMediaHost.squishFraction).isWithin(0.01f).of(0.3f)
+
+ underTest.shouldUpdateSquishinessOnMedia = false
+ Snapshot.sendApplyNotifications()
+ runCurrent()
+ assertThat(underTest.qsMediaHost.squishFraction).isWithin(0.01f).of(1f)
+ }
+ }
+
+ @Test
+ fun inSplitShade_differentStatusBarState_mediaSquishinessSet() =
+ with(kosmos) {
+ testScope.testWithinLifecycle {
+ underTest.isInSplitShade = true
+ underTest.squishinessFraction = 0.3f
+
+ sysuiStatusBarStateController.setState(StatusBarState.SHADE)
+ Snapshot.sendApplyNotifications()
+ runCurrent()
+ assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(0.3f)
+
+ sysuiStatusBarStateController.setState(StatusBarState.KEYGUARD)
+ runCurrent()
+ Snapshot.sendApplyNotifications()
+ runCurrent()
+ assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(1f)
+
+ sysuiStatusBarStateController.setState(StatusBarState.SHADE_LOCKED)
+ runCurrent()
+ Snapshot.sendApplyNotifications()
+ runCurrent()
+ assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(1f)
+ }
+ }
+
+ @Test
+ fun disappearParams() =
+ with(kosmos) {
+ testScope.testWithinLifecycle {
+ setMediaState(ACTIVE_MEDIA)
+
+ setConfigurationForMediaInRow(false)
+ Snapshot.sendApplyNotifications()
+ runCurrent()
+
+ assertThat(underTest.qqsMediaHost.disappearParameters)
+ .isEqualTo(disappearParamsColumn)
+ assertThat(underTest.qsMediaHost.disappearParameters)
+ .isEqualTo(disappearParamsColumn)
+
+ setConfigurationForMediaInRow(true)
+ Snapshot.sendApplyNotifications()
+ runCurrent()
+
+ assertThat(underTest.qqsMediaHost.disappearParameters).isEqualTo(disappearParamsRow)
+ assertThat(underTest.qsMediaHost.disappearParameters).isEqualTo(disappearParamsRow)
+ }
+ }
+
private fun TestScope.setMediaState(state: MediaState) {
with(kosmos) {
val activeMedia = state == ACTIVE_MEDIA
@@ -404,6 +492,26 @@ class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest()
}
private const val epsilon = 0.001f
+
+ private val disappearParamsColumn =
+ DisappearParameters().apply {
+ fadeStartPosition = 0.95f
+ disappearStart = 0f
+ disappearEnd = 0.95f
+ disappearSize.set(1f, 0f)
+ gonePivot.set(0f, 0f)
+ contentTranslationFraction.set(0f, 1f)
+ }
+
+ private val disappearParamsRow =
+ DisappearParameters().apply {
+ fadeStartPosition = 0.95f
+ disappearStart = 0f
+ disappearEnd = 0.6f
+ disappearSize.set(0f, 0.4f)
+ gonePivot.set(1f, 0f)
+ contentTranslationFraction.set(0.25f, 1f)
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
index 4acf3ee7878b..645efae16b8b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
@@ -27,7 +27,7 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class MutableSelectionStateTest : SysuiTestCase() {
- private val underTest = MutableSelectionState({}, {})
+ private val underTest = MutableSelectionState()
@Test
fun selectTile_isCorrectlySelected() {
@@ -48,120 +48,6 @@ class MutableSelectionStateTest : SysuiTestCase() {
assertThat(underTest.selection?.manual).isFalse()
}
- @Test
- fun startResize_createsResizingState() {
- assertThat(underTest.resizingState).isNull()
-
- // Resizing starts but no tile is selected
- underTest.onResizingDragStart(TileWidths(0, 0, 1))
- assertThat(underTest.resizingState).isNull()
-
- // Resizing starts with a selected tile
- underTest.select(TEST_SPEC, manual = true)
- underTest.onResizingDragStart(TileWidths(0, 0, 1))
-
- assertThat(underTest.resizingState).isNotNull()
- }
-
- @Test
- fun endResize_clearsResizingState() {
- val spec = TileSpec.create("testSpec")
-
- // Resizing starts with a selected tile
- underTest.select(spec, manual = true)
- underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
- assertThat(underTest.resizingState).isNotNull()
-
- underTest.onResizingDragEnd()
- assertThat(underTest.resizingState).isNull()
- }
-
- @Test
- fun unselect_clearsResizingState() {
- // Resizing starts with a selected tile
- underTest.select(TEST_SPEC, manual = true)
- underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
- assertThat(underTest.resizingState).isNotNull()
-
- underTest.unSelect()
- assertThat(underTest.resizingState).isNull()
- }
-
- @Test
- fun onResizingDrag_updatesResizingState() {
- // Resizing starts with a selected tile
- underTest.select(TEST_SPEC, manual = true)
- underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
- assertThat(underTest.resizingState).isNotNull()
-
- underTest.onResizingDrag(5f)
- assertThat(underTest.resizingState?.width).isEqualTo(5)
-
- underTest.onResizingDrag(2f)
- assertThat(underTest.resizingState?.width).isEqualTo(7)
-
- underTest.onResizingDrag(-6f)
- assertThat(underTest.resizingState?.width).isEqualTo(1)
- }
-
- @Test
- fun onResizingDrag_receivesResizeCallback() {
- var resized = false
- val onResize: (TileSpec) -> Unit = {
- assertThat(it).isEqualTo(TEST_SPEC)
- resized = !resized
- }
- val underTest = MutableSelectionState(onResize = onResize, {})
-
- // Resizing starts with a selected tile
- underTest.select(TEST_SPEC, true)
- underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
- assertThat(underTest.resizingState).isNotNull()
-
- // Drag under the threshold
- underTest.onResizingDrag(1f)
- assertThat(resized).isFalse()
-
- // Drag over the threshold
- underTest.onResizingDrag(5f)
- assertThat(resized).isTrue()
-
- // Drag back under the threshold
- underTest.onResizingDrag(-5f)
- assertThat(resized).isFalse()
- }
-
- @Test
- fun onResizingEnded_receivesResizeEndCallback() {
- var resizeEnded = false
- val onResizeEnd: (TileSpec) -> Unit = { resizeEnded = true }
- val underTest = MutableSelectionState({}, onResizeEnd = onResizeEnd)
-
- // Resizing starts with a selected tile
- underTest.select(TEST_SPEC, true)
- underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-
- underTest.onResizingDragEnd()
- assertThat(resizeEnded).isTrue()
- }
-
- @Test
- fun onResizingEnded_setsSelectionAutomatically() {
- val underTest = MutableSelectionState({}, {})
-
- // Resizing starts with a selected tile
- underTest.select(TEST_SPEC, manual = true)
- underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-
- // Assert the selection was manual
- assertThat(underTest.selection?.manual).isTrue()
-
- underTest.onResizingDragEnd()
-
- // Assert the selection is no longer manual due to the resizing
- assertThat(underTest.selection?.manual).isFalse()
- }
-
companion object {
private val TEST_SPEC = TileSpec.create("testSpec")
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
index 6e66783da44e..2206f4dcf5a8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
@@ -19,7 +19,9 @@ package com.android.systemui.qs.panels.ui.compose.selection
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.pipeline.shared.TileSpec
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -27,36 +29,32 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ResizingStateTest : SysuiTestCase() {
- @Test
- fun drag_updatesStateCorrectly() {
- var resized = false
- val underTest =
- ResizingState(TileWidths(base = 0, min = 0, max = 10)) { resized = !resized }
-
- assertThat(underTest.width).isEqualTo(0)
+ private val underTest =
+ ResizingState(TileSpec.create("a"), startsAsIcon = true).apply { updateAnchors(10f, 20f) }
- underTest.onDrag(2f)
- assertThat(underTest.width).isEqualTo(2)
-
- underTest.onDrag(1f)
- assertThat(underTest.width).isEqualTo(3)
- assertThat(resized).isTrue()
+ @Test
+ fun newResizingState_setInitialValueCorrectly() {
+ assertThat(underTest.anchoredDraggableState.currentValue).isEqualTo(QSDragAnchor.Icon)
+ }
- underTest.onDrag(-1f)
- assertThat(underTest.width).isEqualTo(2)
- assertThat(resized).isFalse()
+ @Test
+ fun updateAnchors_setBoundsCorrectly() {
+ assertThat(underTest.bounds).isEqualTo(10f to 20f)
}
@Test
- fun dragOutOfBounds_isClampedCorrectly() {
- val underTest = ResizingState(TileWidths(base = 0, min = 0, max = 10)) {}
+ fun dragOverThreshold_resizesToLarge() = runTest {
+ underTest.anchoredDraggableState.anchoredDrag { dragTo(16f) }
- assertThat(underTest.width).isEqualTo(0)
+ assertThat(underTest.temporaryResizeOperation.spec).isEqualTo(TileSpec.create("a"))
+ assertThat(underTest.temporaryResizeOperation.toIcon).isFalse()
+ }
- underTest.onDrag(100f)
- assertThat(underTest.width).isEqualTo(10)
+ @Test
+ fun dragUnderThreshold_staysIcon() = runTest {
+ underTest.anchoredDraggableState.anchoredDrag { dragTo(12f) }
- underTest.onDrag(-200f)
- assertThat(underTest.width).isEqualTo(0)
+ assertThat(underTest.temporaryResizeOperation.spec).isEqualTo(TileSpec.create("a"))
+ assertThat(underTest.temporaryResizeOperation.toIcon).isTrue()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt
new file mode 100644
index 000000000000..f2bfd729f74a
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.fakeFalsingManager
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class EditModeButtonViewModelTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+
+ val underTest = kosmos.editModeButtonViewModelFactory.create()
+
+ @Test
+ fun falsingFalseTap_editModeDoesntStart() =
+ kosmos.runTest {
+ val isEditing by collectLastValue(editModeViewModel.isEditing)
+
+ fakeFalsingManager.setFalseTap(true)
+
+ underTest.onButtonClick()
+ runCurrent()
+
+ assertThat(isEditing).isFalse()
+ }
+
+ @Test
+ fun falsingNotFalseTap_editModeStarted() =
+ kosmos.runTest {
+ val isEditing by collectLastValue(editModeViewModel.isEditing)
+
+ fakeFalsingManager.setFalseTap(false)
+
+ underTest.onButtonClick()
+ runCurrent()
+
+ assertThat(isEditing).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
index 6fce108f35a1..ee2a1d56937b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
@@ -19,10 +19,10 @@ package com.android.systemui.qs.tileimpl
import android.animation.AnimatorTestRule
import android.content.Context
import android.service.quicksettings.Tile
-import android.testing.AndroidTestingRunner
import android.view.ContextThemeWrapper
import android.view.View
import android.widget.ImageView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.annotation.UiThreadTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,7 +35,7 @@ import org.junit.Rule
import org.junit.runner.RunWith
/** Test for regression b/311121830 and b/323125376 */
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@UiThreadTest
@SmallTest
class QSIconViewImplTest_311121830 : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 296478be77e0..296478be77e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
index 991f78a3147c..991f78a3147c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
index ba7a65dd8e65..47bfda41c7ad 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
@@ -21,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.retail.data.repository.impl.RetailModeSettingsRepository
import com.android.systemui.util.settings.FakeGlobalSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
index b53652067755..b47dcb567135 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
@@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.retail.data.repository.FakeRetailModeRepository
+import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorTest.kt
new file mode 100644
index 000000000000..08225a7770d2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 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.scene.domain.interactor
+
+import android.app.StatusBarManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DisabledContentInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+ private val underTest = kosmos.disabledContentInteractor
+
+ @Test
+ fun isDisabled_notificationsShade() =
+ kosmos.runTest {
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NONE)
+ assertThat(underTest.isDisabled(Overlays.NotificationsShade)).isFalse()
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+ assertThat(underTest.isDisabled(Overlays.NotificationsShade)).isTrue()
+ }
+
+ @Test
+ fun isDisabled_qsShade() =
+ kosmos.runTest {
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NONE)
+ assertThat(underTest.isDisabled(Overlays.QuickSettingsShade)).isFalse()
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+ assertThat(underTest.isDisabled(Overlays.QuickSettingsShade)).isTrue()
+ }
+
+ @Test
+ fun repeatWhenDisabled() =
+ kosmos.runTest {
+ var notificationDisabledCount = 0
+ applicationCoroutineScope.launch {
+ underTest.repeatWhenDisabled(Overlays.NotificationsShade) {
+ notificationDisabledCount++
+ }
+ }
+ var qsDisabledCount = 0
+ applicationCoroutineScope.launch {
+ underTest.repeatWhenDisabled(Overlays.QuickSettingsShade) { qsDisabledCount++ }
+ }
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+ assertThat(notificationDisabledCount).isEqualTo(0)
+ assertThat(qsDisabledCount).isEqualTo(1)
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 =
+ StatusBarManager.DISABLE2_NOTIFICATION_SHADE or
+ StatusBarManager.DISABLE2_QUICK_SETTINGS
+ )
+ assertThat(notificationDisabledCount).isEqualTo(1)
+ assertThat(qsDisabledCount).isEqualTo(1)
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+ assertThat(notificationDisabledCount).isEqualTo(1)
+ assertThat(qsDisabledCount).isEqualTo(1)
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+ assertThat(notificationDisabledCount).isEqualTo(1)
+ assertThat(qsDisabledCount).isEqualTo(2)
+ }
+
+ @Test
+ fun filteredUserActions() =
+ kosmos.runTest {
+ val map =
+ mapOf<UserAction, UserActionResult>(
+ Swipe.Up to UserActionResult.ShowOverlay(Overlays.NotificationsShade),
+ Swipe.Down to UserActionResult.ShowOverlay(Overlays.QuickSettingsShade),
+ )
+ val unfiltered = MutableStateFlow(map)
+ val filtered by collectLastValue(underTest.filteredUserActions(unfiltered))
+ assertThat(filtered).isEqualTo(map)
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+ assertThat(filtered)
+ .isEqualTo(
+ mapOf(Swipe.Down to UserActionResult.ShowOverlay(Overlays.QuickSettingsShade))
+ )
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+ assertThat(filtered)
+ .isEqualTo(
+ mapOf(Swipe.Up to UserActionResult.ShowOverlay(Overlays.NotificationsShade))
+ )
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 =
+ StatusBarManager.DISABLE2_NOTIFICATION_SHADE or
+ StatusBarManager.DISABLE2_QUICK_SETTINGS
+ )
+ assertThat(filtered).isEqualTo(emptyMap<UserAction, UserActionResult>())
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
index bf97afed92f4..959081663b56 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
@@ -27,6 +27,7 @@ import com.android.compose.animation.scene.ObservableTransitionState.Transition.
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -194,6 +195,24 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() {
.isFalse()
}
+ @Test
+ fun invisibleDueToOcclusion_isDreaming_emitsTrue() =
+ testScope.runTest {
+ val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion)
+
+ // Verify that we start with unoccluded
+ assertWithMessage("Should start unoccluded").that(invisibleDueToOcclusion).isFalse()
+
+ // Start dreaming, which is an occluding activity
+ showOccludingActivity()
+ kosmos.keyguardInteractor.setDreaming(true)
+
+ // Verify not invisible when dreaming
+ assertWithMessage("Should be invisible when dreaming")
+ .that(invisibleDueToOcclusion)
+ .isTrue()
+ }
+
/** Simulates the appearance of a show-when-locked `Activity` in the foreground. */
private fun TestScope.showOccludingActivity() {
keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 7fe3d8d08afa..48edded5df18 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -18,6 +18,7 @@
package com.android.systemui.scene.domain.interactor
+import android.app.StatusBarManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
@@ -30,6 +31,8 @@ import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.Transition
@@ -43,6 +46,8 @@ import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -523,4 +528,51 @@ class SceneInteractorTest : SysuiTestCase() {
assertThat(currentScene).isEqualTo(Scenes.Gone)
}
+
+ @Test
+ fun showOverlay_overlayDisabled_doesNothing() =
+ kosmos.runTest {
+ val currentOverlays by collectLastValue(underTest.currentOverlays)
+ val disabledOverlay = Overlays.QuickSettingsShade
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+ assertThat(disabledContentInteractor.isDisabled(disabledOverlay)).isTrue()
+ assertThat(currentOverlays).doesNotContain(disabledOverlay)
+
+ underTest.showOverlay(disabledOverlay, "reason")
+
+ assertThat(currentOverlays).doesNotContain(disabledOverlay)
+ }
+
+ @Test
+ fun replaceOverlay_withDisabledOverlay_doesNothing() =
+ kosmos.runTest {
+ val currentOverlays by collectLastValue(underTest.currentOverlays)
+ val showingOverlay = Overlays.NotificationsShade
+ underTest.showOverlay(showingOverlay, "reason")
+ assertThat(currentOverlays).isEqualTo(setOf(showingOverlay))
+ val disabledOverlay = Overlays.QuickSettingsShade
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+ assertThat(disabledContentInteractor.isDisabled(disabledOverlay)).isTrue()
+
+ underTest.replaceOverlay(showingOverlay, disabledOverlay, "reason")
+
+ assertThat(currentOverlays).isEqualTo(setOf(showingOverlay))
+ }
+
+ @Test
+ fun changeScene_toDisabledScene_doesNothing() =
+ kosmos.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ val disabledScene = Scenes.Shade
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+ assertThat(disabledContentInteractor.isDisabled(disabledScene)).isTrue()
+ assertThat(currentScene).isNotEqualTo(disabledScene)
+
+ underTest.changeScene(disabledScene, "reason")
+
+ assertThat(currentScene).isNotEqualTo(disabledScene)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 152911a30524..5d49c113a539 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -44,6 +44,7 @@ import com.android.systemui.biometrics.data.repository.fingerprintPropertyReposi
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
import com.android.systemui.bouncer.shared.logging.BouncerUiEvent
import com.android.systemui.classifier.FalsingCollector
@@ -54,6 +55,8 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryHapticsInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus
import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus
import com.android.systemui.flags.EnableSceneContainer
@@ -71,12 +74,16 @@ import com.android.systemui.keyguard.data.repository.fakeTrustRepository
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.dismissCallbackRegistry
+import com.android.systemui.keyguard.domain.interactor.dozeInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.scenetransition.lockscreenSceneTransitionInteractor
import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
import com.android.systemui.power.data.repository.fakePowerRepository
@@ -97,6 +104,8 @@ import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shared.system.QuickStepContract
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
@@ -114,6 +123,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
@@ -140,6 +150,8 @@ class SceneContainerStartableTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val deviceEntryHapticsInteractor by lazy { kosmos.deviceEntryHapticsInteractor }
+ private val dozeInteractor by lazy { kosmos.dozeInteractor }
+ private val keyguardInteractor by lazy { kosmos.keyguardInteractor }
private val sceneInteractor by lazy { kosmos.sceneInteractor }
private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
@@ -370,6 +382,64 @@ class SceneContainerStartableTest : SysuiTestCase() {
}
@Test
+ fun hydrateVisibility_whileDreaming() =
+ testScope.runTest {
+ val isVisible by collectLastValue(sceneInteractor.isVisible)
+
+ // GIVEN the device is dreaming
+ val transitionState =
+ prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Dream)
+ underTest.start()
+ assertThat(isVisible).isFalse()
+ }
+
+ @Test
+ fun hydrateVisibility_onCommunalWhileOccluded() =
+ testScope.runTest {
+ val isVisible by collectLastValue(sceneInteractor.isVisible)
+
+ kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
+ true,
+ mock(),
+ )
+ prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Communal)
+ underTest.start()
+ runCurrent()
+ assertThat(isVisible).isTrue()
+ }
+
+ @Test
+ fun hydrateVisibility_inCommunalTransition() =
+ testScope.runTest {
+ val isVisible by collectLastValue(sceneInteractor.isVisible)
+
+ // GIVEN the device is dreaming
+ val transitionState =
+ prepareState(
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ isDeviceUnlocked = false,
+ initialSceneKey = Scenes.Dream,
+ )
+ underTest.start()
+ assertThat(isVisible).isFalse()
+
+ // WHEN a transition starts to the communal hub
+ sceneInteractor.changeScene(Scenes.Dream, "switching to dream for test")
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Dream,
+ toScene = Scenes.Communal,
+ currentScene = flowOf(Scenes.Dream),
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+ runCurrent()
+ // THEN scenes are visible
+ assertThat(isVisible).isTrue()
+ }
+
+ @Test
fun startsInLockscreenScene() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -640,7 +710,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
fun switchToAOD_whenAvailable_whenDeviceSleepsLocked() =
testScope.runTest {
kosmos.lockscreenSceneTransitionInteractor.start()
- val asleepState by collectLastValue(kosmos.keyguardInteractor.asleepKeyguardState)
+ val asleepState by collectLastValue(keyguardInteractor.asleepKeyguardState)
val currentTransitionInfo by
collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
val transitionState =
@@ -670,7 +740,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
fun switchToDozing_whenAodUnavailable_whenDeviceSleepsLocked() =
testScope.runTest {
kosmos.lockscreenSceneTransitionInteractor.start()
- val asleepState by collectLastValue(kosmos.keyguardInteractor.asleepKeyguardState)
+ val asleepState by collectLastValue(keyguardInteractor.asleepKeyguardState)
val currentTransitionInfo by
collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
val transitionState =
@@ -2356,6 +2426,277 @@ class SceneContainerStartableTest : SysuiTestCase() {
assertThat(isLockscreenEnabled).isTrue()
}
+ @Test
+ fun stayOnLockscreen_whenDozingStarted() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ prepareState()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ underTest.start()
+
+ // Stay on Lockscreen when dozing and dreaming
+ dozeInteractor.setIsDozing(true)
+ keyguardInteractor.setDreaming(true)
+ kosmos.fakeKeyguardRepository.setDreamingWithOverlay(false)
+ runCurrent()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun switchFromLockscreenToDream_whenDreamStarted() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ prepareState()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ underTest.start()
+
+ powerInteractor.setAwakeForTest()
+ keyguardInteractor.setDreaming(true)
+ // Move past initial delay with [KeyguardInteractor#isAbleToDream]
+ advanceTimeBy(600L)
+ runCurrent()
+ assertThat(currentScene).isEqualTo(Scenes.Dream)
+ }
+
+ @Test
+ fun switchFromDreamToLockscreen_whenLockedAndDreamStopped() =
+ testScope.runTest {
+ keyguardInteractor.setDreaming(true)
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ prepareState(initialSceneKey = Scenes.Dream)
+ assertThat(currentScene).isEqualTo(Scenes.Dream)
+ underTest.start()
+
+ keyguardInteractor.setDreaming(false)
+ runCurrent()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun switchFromDreamToGone_whenUnlockedAndDreamStopped() =
+ testScope.runTest {
+ keyguardInteractor.setDreaming(true)
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ prepareState(initialSceneKey = Scenes.Dream, isDeviceUnlocked = true)
+ assertThat(currentScene).isEqualTo(Scenes.Dream)
+ underTest.start()
+
+ keyguardInteractor.setDreaming(false)
+ runCurrent()
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
+ fun replacesLockscreenSceneOnBackStack_whenUnlockdViaAlternateBouncer_fromShade() =
+ testScope.runTest {
+ val transitionState =
+ prepareState(
+ isDeviceUnlocked = false,
+ initialSceneKey = Scenes.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ )
+ underTest.start()
+
+ val isUnlocked by
+ collectLastValue(
+ kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+ )
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val backStack by collectLastValue(sceneBackInteractor.backStack)
+ val isAlternateBouncerVisible by
+ collectLastValue(kosmos.alternateBouncerInteractor.isVisible)
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(isAlternateBouncerVisible).isFalse()
+
+ // Change to shade.
+ sceneInteractor.changeScene(Scenes.Shade, "")
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Shade)
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+ assertThat(isAlternateBouncerVisible).isFalse()
+
+ // Show the alternate bouncer.
+ kosmos.alternateBouncerInteractor.forceShow()
+ kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+ assertThat(isAlternateBouncerVisible).isTrue()
+
+ // Trigger a fingerprint unlock.
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
+ assertThat(isUnlocked).isTrue()
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Gone)
+ assertThat(isAlternateBouncerVisible).isFalse()
+ }
+
+ @Test
+ fun handleDeviceUnlockStatus_deviceLockedWhileOnDream_stayOnDream() =
+ testScope.runTest {
+ val transitionState =
+ prepareState(
+ isDeviceUnlocked = false,
+ initialSceneKey = Scenes.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ )
+ underTest.start()
+
+ val isUnlocked by
+ collectLastValue(
+ kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+ )
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+ // Unlock device.
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ assertThat(isUnlocked).isTrue()
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+
+ // Change to Dream.
+ sceneInteractor.changeScene(Scenes.Dream, "test")
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Dream)
+ runCurrent()
+ assertThat(isUnlocked).isTrue()
+ assertThat(currentScene).isEqualTo(Scenes.Dream)
+
+ // Lock device, and verify stay on dream.
+ kosmos.fakeDeviceEntryRepository.deviceUnlockStatus.value =
+ DeviceUnlockStatus(isUnlocked = false, deviceUnlockSource = null)
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Dream)
+ }
+
+ @Test
+ fun handleDeviceUnlockStatus_deviceLockedWhileOnCommunal_stayOnCommunal() =
+ testScope.runTest {
+ val transitionState =
+ prepareState(
+ isDeviceUnlocked = false,
+ initialSceneKey = Scenes.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ )
+ underTest.start()
+
+ val isUnlocked by
+ collectLastValue(
+ kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+ )
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+ // Unlock device.
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ assertThat(isUnlocked).isTrue()
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+
+ // Change to Communal.
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Communal)
+ runCurrent()
+ assertThat(isUnlocked).isTrue()
+ assertThat(currentScene).isEqualTo(Scenes.Communal)
+
+ // Lock device, and verify stay on Communal.
+ kosmos.fakeDeviceEntryRepository.deviceUnlockStatus.value =
+ DeviceUnlockStatus(isUnlocked = false, deviceUnlockSource = null)
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Communal)
+ }
+
+ @Test
+ fun replacesLockscreenSceneOnBackStack_whenFaceUnlocked_fromShade_noAlternateBouncer() =
+ testScope.runTest {
+ val transitionState =
+ prepareState(
+ isDeviceUnlocked = false,
+ initialSceneKey = Scenes.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ )
+ underTest.start()
+
+ val isUnlocked by
+ collectLastValue(
+ kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+ )
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val backStack by collectLastValue(sceneBackInteractor.backStack)
+ val isAlternateBouncerVisible by
+ collectLastValue(kosmos.alternateBouncerInteractor.isVisible)
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(isAlternateBouncerVisible).isFalse()
+
+ // Change to shade.
+ sceneInteractor.changeScene(Scenes.Shade, "")
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Shade)
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+ assertThat(isAlternateBouncerVisible).isFalse()
+
+ // Show the alternate bouncer.
+ kosmos.alternateBouncerInteractor.forceShow()
+ kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+ assertThat(isAlternateBouncerVisible).isTrue()
+
+ // Simulate race condition by hiding the alternate bouncer *before* the face unlock:
+ kosmos.alternateBouncerInteractor.hide()
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+ assertThat(isAlternateBouncerVisible).isFalse()
+
+ // Trigger a face unlock.
+ updateFaceAuthStatus(isSuccess = true)
+ runCurrent()
+ assertThat(isUnlocked).isTrue()
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Gone)
+ assertThat(isAlternateBouncerVisible).isFalse()
+ }
+
+ @Test
+ fun handleDisableFlags() =
+ kosmos.runTest {
+ underTest.start()
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ sceneInteractor.changeScene(Scenes.Shade, "reason")
+ sceneInteractor.showOverlay(Overlays.NotificationsShade, "reason")
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(currentOverlays).contains(Overlays.NotificationsShade)
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+ runCurrent()
+
+ assertThat(currentScene).isNotEqualTo(Scenes.Shade)
+ assertThat(currentOverlays).isEmpty()
+ }
+
private fun TestScope.emulateSceneTransition(
transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
toScene: SceneKey,
@@ -2592,15 +2933,16 @@ class SceneContainerStartableTest : SysuiTestCase() {
}
private fun updateFaceAuthStatus(isSuccess: Boolean) {
- if (isSuccess) {
- kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
- SuccessFaceAuthenticationStatus(
- successResult = Mockito.mock(FaceManager.AuthenticationResult::class.java)
- )
- )
- } else {
- kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
- FailedFaceAuthenticationStatus()
+ with(kosmos.fakeDeviceEntryFaceAuthRepository) {
+ isAuthenticated.value = isSuccess
+ setAuthenticationStatus(
+ if (isSuccess) {
+ SuccessFaceAuthenticationStatus(
+ successResult = Mockito.mock(FaceManager.AuthenticationResult::class.java)
+ )
+ } else {
+ FailedFaceAuthenticationStatus()
+ }
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
index a10d81f86d8e..1413204f7fed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
@@ -20,8 +20,8 @@ import android.app.PendingIntent
import android.content.Intent
import android.os.Bundle
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
import android.view.Window
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.argumentCaptor
@@ -39,7 +39,7 @@ import org.mockito.kotlin.eq
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyBlocking
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ActionExecutorTest : SysuiTestCase() {
private val scheduler = TestCoroutineScheduler()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
index c50702868025..84b7d10c42a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
@@ -21,10 +21,10 @@ import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.MATCH_ANY_USER
import android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS
-import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.IWindowManager
import android.view.WindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argThat
@@ -43,7 +43,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ScreenshotDetectionControllerTest {
@Mock lateinit var windowManager: IWindowManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index 77b5c9115295..d2eca0d95a30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -23,9 +23,9 @@ import android.content.ComponentName
import android.net.Uri
import android.os.UserHandle
import android.os.UserManager
-import android.testing.AndroidTestingRunner
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.util.ScreenshotRequest
import com.android.systemui.SysuiTestCase
@@ -49,7 +49,7 @@ import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class TakeScreenshotServiceTest : SysuiTestCase() {
private val userManager = mock<UserManager> { on { isUserUnlocked } doReturn (true) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
index 0ab4cd05fea7..0ab4cd05fea7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 01c17bd6285c..ed31f366e1d0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -148,7 +148,6 @@ import com.android.systemui.statusbar.QsFrameTranslateController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
@@ -350,6 +349,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
@Mock private KeyguardClockPositionAlgorithm mKeyguardClockPositionAlgorithm;
@Mock private NaturalScrollingSettingObserver mNaturalScrollingSettingObserver;
@Mock private LargeScreenHeaderHelper mLargeScreenHeaderHelper;
+ @Mock private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
protected final int mMaxUdfpsBurnInOffsetY = 5;
protected FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -428,7 +428,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
mKosmos.getDeviceProvisioningInteractor(),
- new FakeDisableFlagsRepository(),
+ mKosmos.getDisableFlagsInteractor(),
mDozeParameters,
mFakeKeyguardRepository,
mKeyguardTransitionInteractor,
@@ -820,6 +820,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mNotificationShadeDepthController,
mShadeHeaderController,
mStatusBarTouchableRegionManager,
+ () -> mStatusBarLongPressGestureDetector,
mKeyguardStateController,
mKeyguardBypassController,
mScrimController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 443595dbdf77..61d4c9968d49 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -126,6 +126,7 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase {
@Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
@Mock protected ShadeHeaderController mShadeHeaderController;
@Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+ @Mock protected StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
@Mock protected DozeParameters mDozeParameters;
@Mock protected KeyguardStateController mKeyguardStateController;
@Mock protected KeyguardBypassController mKeyguardBypassController;
@@ -149,7 +150,7 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase {
@Mock protected LargeScreenHeaderHelper mLargeScreenHeaderHelper;
protected FakeDisableFlagsRepository mDisableFlagsRepository =
- new FakeDisableFlagsRepository();
+ mKosmos.getFakeDisableFlagsRepository();
protected FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository();
protected FakeShadeRepository mShadeRepository = new FakeShadeRepository();
@@ -185,7 +186,7 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase {
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
mKosmos.getDeviceProvisioningInteractor(),
- mDisableFlagsRepository,
+ mKosmos.getDisableFlagsInteractor(),
mDozeParameters,
mKeyguardRepository,
keyguardTransitionInteractor,
@@ -250,6 +251,7 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase {
mNotificationShadeDepthController,
mShadeHeaderController,
mStatusBarTouchableRegionManager,
+ () -> mStatusBarLongPressGestureDetector,
mKeyguardStateController,
mKeyguardBypassController,
mScrimController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
index 46961d4db0f6..ee3f8016c410 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
@@ -19,7 +19,7 @@ package com.android.systemui.shade
import android.app.StatusBarManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelChildren
@@ -61,7 +61,7 @@ class QuickSettingsControllerImplWithCoroutinesTest : QuickSettingsControllerImp
mDisableFlagsRepository.disableFlags.value =
DisableFlagsModel(
StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_QUICK_SETTINGS
+ StatusBarManager.DISABLE2_QUICK_SETTINGS,
)
runCurrent()
@@ -76,7 +76,7 @@ class QuickSettingsControllerImplWithCoroutinesTest : QuickSettingsControllerImp
mDisableFlagsRepository.disableFlags.value =
DisableFlagsModel(
StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_NOTIFICATION_SHADE
+ StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
)
runCurrent()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 9a8df33a0276..cd55bb23c1fc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -38,11 +38,11 @@ import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextManager;
@@ -76,7 +76,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
index a9a5cac6112e..af01547be7e3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
@@ -21,7 +21,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.ShadePrimaryDisplayCommand
import com.android.systemui.statusbar.commandline.commandRegistry
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -34,13 +36,16 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
-class ShadePositionRepositoryTest : SysuiTestCase() {
+class ShadePrimaryDisplayCommandTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val commandRegistry = kosmos.commandRegistry
+ private val displayRepository = kosmos.displayRepository
+ private val shadeDisplaysRepository = ShadeDisplaysRepositoryImpl()
private val pw = PrintWriter(StringWriter())
- private val underTest = ShadePositionRepositoryImpl(commandRegistry)
+ private val underTest =
+ ShadePrimaryDisplayCommand(commandRegistry, displayRepository, shadeDisplaysRepository)
@Before
fun setUp() {
@@ -50,7 +55,7 @@ class ShadePositionRepositoryTest : SysuiTestCase() {
@Test
fun commandDisplayOverride_updatesDisplayId() =
testScope.runTest {
- val displayId by collectLastValue(underTest.displayId)
+ val displayId by collectLastValue(shadeDisplaysRepository.displayId)
assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
val newDisplayId = 2
@@ -65,7 +70,7 @@ class ShadePositionRepositoryTest : SysuiTestCase() {
@Test
fun commandShadeDisplayOverride_resetsDisplayId() =
testScope.runTest {
- val displayId by collectLastValue(underTest.displayId)
+ val displayId by collectLastValue(shadeDisplaysRepository.displayId)
assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
val newDisplayId = 2
@@ -78,4 +83,17 @@ class ShadePositionRepositoryTest : SysuiTestCase() {
commandRegistry.onShellCommand(pw, arrayOf("shade_display_override", "reset"))
assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
}
+
+ @Test
+ fun commandShadeDisplayOverride_anyExternalDisplay_notOnDefaultAnymore() =
+ testScope.runTest {
+ val displayId by collectLastValue(shadeDisplaysRepository.displayId)
+ assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
+ val newDisplayId = 2
+ displayRepository.addDisplay(displayId = newDisplayId)
+
+ commandRegistry.onShellCommand(pw, arrayOf("shade_display_override", "any_external"))
+
+ assertThat(displayId).isEqualTo(newDisplayId)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
new file mode 100644
index 000000000000..016a24acd461
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2024 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.shade.domain.interactor
+
+import android.content.Context
+import android.content.MutableContextWrapper
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.view.Display
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.FakeDisplayWindowPropertiesRepository
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository
+import com.android.systemui.statusbar.phone.ConfigurationForwarder
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.advanceUntilIdle
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verifyNoMoreInteractions
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ShadeDisplaysInteractorTest : SysuiTestCase() {
+
+ private val shadeRootview = mock<WindowRootView>()
+ private val positionRepository = FakeShadeDisplayRepository()
+ private val defaultContext = mock<Context>()
+ private val secondaryContext = mock<Context>()
+ private val contextStore = FakeDisplayWindowPropertiesRepository()
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val configurationForwarder = mock<ConfigurationForwarder>()
+ private val defaultWm = mock<WindowManager>()
+ private val secondaryWm = mock<WindowManager>()
+ private val resources = mock<Resources>()
+ private val configuration = mock<Configuration>()
+ private val display = mock<Display>()
+
+ private val interactor =
+ ShadeDisplaysInteractor(
+ Optional.of(shadeRootview),
+ positionRepository,
+ MutableContextWrapper(defaultContext),
+ resources,
+ contextStore,
+ testScope.backgroundScope,
+ configurationForwarder,
+ testScope.backgroundScope.coroutineContext,
+ )
+
+ @Before
+ fun setup() {
+ whenever(shadeRootview.display).thenReturn(display)
+ whenever(display.displayId).thenReturn(0)
+
+ whenever(resources.configuration).thenReturn(configuration)
+
+ whenever(defaultContext.displayId).thenReturn(0)
+ whenever(defaultContext.getSystemService(any())).thenReturn(defaultWm)
+ whenever(defaultContext.resources).thenReturn(resources)
+ contextStore.insert(
+ DisplayWindowProperties(
+ displayId = 0,
+ windowType = TYPE_NOTIFICATION_SHADE,
+ context = defaultContext,
+ windowManager = defaultWm,
+ layoutInflater = mock(),
+ )
+ )
+
+ whenever(secondaryContext.displayId).thenReturn(1)
+ whenever(secondaryContext.getSystemService(any())).thenReturn(secondaryWm)
+ whenever(secondaryContext.resources).thenReturn(resources)
+ contextStore.insert(
+ DisplayWindowProperties(
+ displayId = 1,
+ windowType = TYPE_NOTIFICATION_SHADE,
+ context = secondaryContext,
+ windowManager = secondaryWm,
+ layoutInflater = mock(),
+ )
+ )
+ }
+
+ @Test
+ fun start_shadeInCorrectPosition_notAddedOrRemoved() {
+ whenever(display.displayId).thenReturn(0)
+ positionRepository.setDisplayId(0)
+ interactor.start()
+ testScope.advanceUntilIdle()
+
+ verifyNoMoreInteractions(defaultWm)
+ verifyNoMoreInteractions(secondaryWm)
+ }
+
+ @Test
+ fun start_shadeInWrongPosition_changes() {
+ whenever(display.displayId).thenReturn(0)
+ positionRepository.setDisplayId(1)
+ interactor.start()
+
+ verify(defaultWm).removeView(eq(shadeRootview))
+ verify(secondaryWm).addView(eq(shadeRootview), any())
+ }
+
+ @Test
+ fun start_shadePositionChanges_removedThenAdded() {
+ whenever(display.displayId).thenReturn(0)
+ positionRepository.setDisplayId(0)
+ interactor.start()
+
+ positionRepository.setDisplayId(1)
+
+ verify(defaultWm).removeView(eq(shadeRootview))
+ verify(secondaryWm).addView(eq(shadeRootview), any())
+ }
+
+ @Test
+ fun start_shadePositionChanges_newConfigPropagated() {
+ whenever(display.displayId).thenReturn(0)
+ positionRepository.setDisplayId(0)
+ interactor.start()
+
+ positionRepository.setDisplayId(1)
+
+ verify(configurationForwarder).onConfigurationChanged(eq(configuration))
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
index 19ac0cf40160..da652c4e1b5e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
@@ -37,8 +37,8 @@ import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.shade.shadeTestUtil
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.statusbar.phone.dozeParameters
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
index b730b3703515..b730b3703515 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index fb7252b24295..60a185537b0d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar;
-import static android.app.Notification.CATEGORY_CALL;
-
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
@@ -199,19 +197,6 @@ public class StatusBarIconViewTest extends SysuiTestCase {
}
@Test
- public void testContentDescForNotification_noNotifContent() {
- Notification n = new Notification.Builder(mContext, "test")
- .setSmallIcon(0)
- .setContentTitle("hello")
- .setCategory(CATEGORY_CALL)
- .build();
- assertThat(NotificationContentDescription.contentDescForNotification(mContext, n)
- .toString()).startsWith("com.android.systemui.tests notification");
- assertThat(NotificationContentDescription.contentDescForNotification(mContext, n)
- .toString()).doesNotContain("hello");
- }
-
- @Test
@EnableFlags({Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS})
public void setIcon_withPreloaded_usesPreloaded() {
Icon mockIcon = mock(Icon.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
index 5fce08b08137..5fce08b08137 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
index 907c68440b55..cd078211f934 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
@@ -32,7 +32,7 @@ import com.android.systemui.log.LogBufferFactory
import com.android.systemui.res.R
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index c8ef663a4f81..e974c2e70f68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -30,13 +30,13 @@ import static org.mockito.Mockito.verify;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
-import android.testing.AndroidTestingRunner;
import android.util.FloatProperty;
import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.app.animation.Interpolators;
@@ -51,7 +51,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@UiThreadTest
public class PropertyAnimatorTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index e21a005b8ada..4ef9792a2ad9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -68,12 +68,12 @@ import android.platform.test.annotations.EnableFlags;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
import android.util.ArraySet;
import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
@@ -118,7 +118,7 @@ import java.util.List;
import java.util.Map;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotifCollectionTest extends SysuiTestCase {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
index 1f2925528077..544d20145db3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
+import static android.app.Notification.FLAG_PROMOTED_ONGOING;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
@@ -24,12 +25,18 @@ import static android.app.NotificationManager.IMPORTANCE_MIN;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
import android.content.Intent;
import android.graphics.Color;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -38,11 +45,14 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -136,6 +146,60 @@ public class ColorizedFgsCoordinatorTest extends SysuiTestCase {
assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
}
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+ public void testIncludePromotedOngoingInSection_flagEnabled() {
+ // GIVEN the notification has FLAG_PROMOTED_ONGOING
+ mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
+
+ // THEN the entry is in the fgs section
+ assertTrue(mFgsSection.isInSection(mEntryBuilder.build()));
+ }
+
+ @Test
+ @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+ public void testDiscludePromotedOngoingInSection_flagDisabled() {
+ // GIVEN the notification has FLAG_PROMOTED_ONGOING
+ mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
+
+ // THEN the entry is NOT in the fgs section
+ assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+ public void promoterSelectsPromotedOngoing_flagEnabled() {
+ ArgumentCaptor<NotifPromoter> captor = ArgumentCaptor.forClass(NotifPromoter.class);
+ verify(mNotifPipeline).addPromoter(captor.capture());
+ NotifPromoter promoter = captor.getValue();
+
+ // GIVEN the notification has FLAG_PROMOTED_ONGOING
+ mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
+
+ // THEN the entry is promoted to top level
+ assertTrue(promoter.shouldPromoteToTopLevel(mEntryBuilder.build()));
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+ public void promoterIgnoresNonPromotedOngoing_flagEnabled() {
+ ArgumentCaptor<NotifPromoter> captor = ArgumentCaptor.forClass(NotifPromoter.class);
+ verify(mNotifPipeline).addPromoter(captor.capture());
+ NotifPromoter promoter = captor.getValue();
+
+ // GIVEN the notification does not have FLAG_PROMOTED_ONGOING
+ mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, false);
+
+ // THEN the entry is NOT promoted to top level
+ assertFalse(promoter.shouldPromoteToTopLevel(mEntryBuilder.build()));
+ }
+
+ @Test
+ @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+ public void noPromoterAdded_flagDisabled() {
+ verify(mNotifPipeline, never()).addPromoter(any());
+ }
+
private Notification.CallStyle makeCallStyle() {
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent("action"), PendingIntent.FLAG_IMMUTABLE);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 9613f76c2b48..2c488e3a7242 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -28,7 +28,6 @@ import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -52,6 +51,7 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import com.android.systemui.testKosmos
import com.android.systemui.util.concurrency.FakeExecutor
@@ -101,7 +101,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
private val notifPipeline: NotifPipeline = mock()
private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
- private val headsUpManager: HeadsUpManagerPhone = mock()
+ private val headsUpManager: BaseHeadsUpManager = mock()
private val headsUpViewBinder: HeadsUpViewBinder = mock()
private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()
private val remoteInputManager: NotificationRemoteInputManager = mock()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
index ca75ca679c31..a70d24efada7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
@@ -28,43 +28,41 @@ import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderGroupListener
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.withArgCaptor
import org.junit.Before
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.spy
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.inOrder
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
@SmallTest
@RunWith(AndroidJUnit4::class)
class RenderStageManagerTest : SysuiTestCase() {
- @Mock private lateinit var shadeListBuilder: ShadeListBuilder
- @Mock private lateinit var onAfterRenderListListener: OnAfterRenderListListener
- @Mock private lateinit var onAfterRenderGroupListener: OnAfterRenderGroupListener
- @Mock private lateinit var onAfterRenderEntryListener: OnAfterRenderEntryListener
+ private val shadeListBuilder: ShadeListBuilder = mock()
+ private val onAfterRenderListListener: OnAfterRenderListListener = mock()
+ private val onAfterRenderGroupListener: OnAfterRenderGroupListener = mock()
+ private val onAfterRenderEntryListener: OnAfterRenderEntryListener = mock()
+ private val spyViewRenderer = spy(FakeNotifViewRenderer())
private lateinit var onRenderListListener: ShadeListBuilder.OnRenderListListener
+
private lateinit var renderStageManager: RenderStageManager
- private val spyViewRenderer = spy(FakeNotifViewRenderer())
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
renderStageManager = RenderStageManager()
renderStageManager.attach(shadeListBuilder)
- onRenderListListener = withArgCaptor {
- verify(shadeListBuilder).setOnRenderListListener(capture())
- }
+
+ val captor = argumentCaptor<ShadeListBuilder.OnRenderListListener>()
+ verify(shadeListBuilder).setOnRenderListListener(captor.capture())
+ onRenderListListener = captor.lastValue
}
private fun setUpRenderer() {
@@ -89,7 +87,7 @@ class RenderStageManagerTest : SysuiTestCase() {
verifyNoMoreInteractions(
onAfterRenderListListener,
onAfterRenderGroupListener,
- onAfterRenderEntryListener
+ onAfterRenderEntryListener,
)
}
@@ -171,7 +169,7 @@ class RenderStageManagerTest : SysuiTestCase() {
verifyNoMoreInteractions(
onAfterRenderListListener,
onAfterRenderGroupListener,
- onAfterRenderEntryListener
+ onAfterRenderEntryListener,
)
}
@@ -191,30 +189,27 @@ class RenderStageManagerTest : SysuiTestCase() {
verifyNoMoreInteractions(
onAfterRenderListListener,
onAfterRenderGroupListener,
- onAfterRenderEntryListener
+ onAfterRenderEntryListener,
)
}
- private fun listWith2Groups8Entries() = listOf(
- group(
- notif(1),
- notif(2),
- notif(3)
- ),
- notif(4),
- group(
- notif(5),
- notif(6),
- notif(7)
- ),
- notif(8)
- )
+ private fun listWith2Groups8Entries() =
+ listOf(
+ group(notif(1), notif(2), notif(3)),
+ notif(4),
+ group(notif(5), notif(6), notif(7)),
+ notif(8),
+ )
private class FakeNotifViewRenderer : NotifViewRenderer {
override fun onRenderList(notifList: List<ListEntry>) {}
+
override fun getStackController(): NotifStackController = mock()
+
override fun getGroupController(group: GroupEntry): NotifGroupController = mock()
+
override fun getRowController(entry: NotificationEntry): NotifRowController = mock()
+
override fun onDispatchComplete() {}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
index 79ff4be253e1..7eac7e86e372 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
@@ -21,8 +21,8 @@ import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
@@ -51,10 +51,7 @@ class NotificationAlertsInteractorTest : SysuiTestCase() {
fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() =
with(testComponent) {
disableFlags.disableFlags.value =
- DisableFlagsModel(
- StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_NONE,
- )
+ DisableFlagsModel(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE)
assertThat(underTest.areNotificationAlertsEnabled()).isTrue()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfoTest.java
new file mode 100644
index 000000000000..b2962eeb9001
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfoTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2024 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.statusbar.notification.row;
+
+import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
+import static android.service.notification.NotificationAssistantService.ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
+import android.service.notification.NotificationAssistantService;
+import android.service.notification.StatusBarNotification;
+import android.telecom.TelecomManager;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@TestableLooper.RunWithLooper
+public class BundleNotificationInfoTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test_package";
+ private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME;
+ private static final int TEST_UID = 1;
+ private static final String TEST_CHANNEL = "test_channel";
+ private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
+
+ private TestableLooper mTestableLooper;
+ private BundleNotificationInfo mInfo;
+ private NotificationChannel mNotificationChannel;
+ private StatusBarNotification mSbn;
+ private NotificationEntry mEntry;
+ private UiEventLoggerFake mUiEventLogger = new UiEventLoggerFake();
+
+ @Rule
+ public MockitoRule mockito = MockitoJUnit.rule();
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private INotificationManager mMockINotificationManager;
+ @Mock
+ private PackageManager mMockPackageManager;
+ @Mock
+ private OnUserInteractionCallback mOnUserInteractionCallback;
+ @Mock
+ private ChannelEditorDialogController mChannelEditorDialogController;
+ @Mock
+ private AssistantFeedbackController mAssistantFeedbackController;
+ @Mock
+ private TelecomManager mTelecomManager;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestableLooper = TestableLooper.get(this);
+
+ mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
+
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ // Inflate the layout
+ final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ mInfo = (BundleNotificationInfo) layoutInflater.inflate(R.layout.bundle_notification_info,
+ null);
+ mInfo.setGutsParent(mock(NotificationGuts.class));
+ // Our view is never attached to a window so the View#post methods in
+ // BundleNotificationInfo never get called. Setting this will skip the post and do the
+ // action immediately.
+ mInfo.mSkipPost = true;
+
+ // PackageManager must return a packageInfo and applicationInfo.
+ final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = TEST_PACKAGE_NAME;
+ when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()))
+ .thenReturn(packageInfo);
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = TEST_UID; // non-zero
+ final PackageInfo systemPackageInfo = new PackageInfo();
+ systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME;
+ when(mMockPackageManager.getPackageInfo(eq(TEST_SYSTEM_PACKAGE_NAME), anyInt()))
+ .thenReturn(systemPackageInfo);
+ when(mMockPackageManager.getPackageInfo(eq("android"), anyInt()))
+ .thenReturn(packageInfo);
+
+ // Package has one channel by default.
+ when(mMockINotificationManager.getNumNotificationChannelsForPackage(
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(1);
+
+ // Some test channels.
+ mNotificationChannel = new NotificationChannel(
+ TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
+ Notification notification = new Notification();
+ notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, applicationInfo);
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
+ notification, UserHandle.getUserHandleForUid(TEST_UID), null, 0);
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ when(mAssistantFeedbackController.isFeedbackEnabled()).thenReturn(false);
+ when(mAssistantFeedbackController.getInlineDescriptionResource(any()))
+ .thenReturn(R.string.notification_channel_summary_automatic);
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testBindNotification_setsOnClickListenerForFeedback() throws Exception {
+ // When Notification Assistant is available,
+ when(mMockINotificationManager.getAllowedNotificationAssistant()).thenReturn(
+ new ComponentName("assistantPkg", "assistantCls"));
+
+ // ...and Package manager has an intent that matches.
+ ArrayList<ResolveInfo> resolveInfos = new ArrayList<>();
+ ResolveInfo info = new ResolveInfo();
+ info.activityInfo = new ActivityInfo();
+ info.activityInfo.packageName = "assistantPkg";
+ info.activityInfo.name = "assistantCls";
+ resolveInfos.add(info);
+ when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(resolveInfos);
+
+ // And we attempt to bind the notification to the Info object
+ final CountDownLatch latch = new CountDownLatch(1);
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mOnUserInteractionCallback,
+ mChannelEditorDialogController,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ null,
+ (View v, Intent intent) -> {
+ // Assert that the intent action and package match.
+ assertEquals(intent.getAction(),
+ ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS);
+ assertEquals(intent.getPackage(), "assistantPkg");
+ latch.countDown();
+ },
+ mUiEventLogger,
+ true,
+ false,
+ true,
+ mAssistantFeedbackController,
+ mMetricsLogger);
+ // and the feedback button is clicked,
+ final View feedbackButton = mInfo.findViewById(R.id.notification_guts_bundle_feedback);
+ feedbackButton.performClick();
+
+ // then of the intents queried for is the feedback intent,
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockPackageManager, atLeastOnce()).queryIntentActivities(captor.capture(),
+ anyInt());
+ List<Intent> capturedIntents = captor.getAllValues();
+ Intent feedbackIntent = null;
+ for (int i = 0; i < capturedIntents.size(); i++) {
+ final Intent capturedIntent = capturedIntents.get(i);
+ if (capturedIntent.getAction() == ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS
+ && capturedIntent.getPackage().equals("assistantPkg")) {
+ feedbackIntent = capturedIntent;
+ }
+ }
+ assertNotNull("feedbackIntent should be not null", feedbackIntent);
+ assertEquals(mSbn.getKey(),
+ feedbackIntent.getExtra(NotificationAssistantService.EXTRA_NOTIFICATION_KEY));
+
+ // and verify that listener was triggered.
+ assertEquals(0, latch.getCount());
+ assertEquals(View.VISIBLE, feedbackButton.getVisibility());
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testBindNotification_hidesFeedbackButtonWhenNoNAS() throws Exception {
+ // When the Notification Assistant is not available
+ when(mMockINotificationManager.getAllowedNotificationAssistant()).thenReturn(null);
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mOnUserInteractionCallback,
+ mChannelEditorDialogController,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ null,
+ (View v, Intent intent) -> {
+ // Assert that the intent action and package match.
+ assertEquals(intent.getAction(),
+ ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS);
+ assertEquals(intent.getPackage(), "assistantPkg");
+ latch.countDown();
+ },
+ mUiEventLogger,
+ true,
+ false,
+ true,
+ mAssistantFeedbackController,
+ mMetricsLogger);
+
+ final View feedbackButton = mInfo.findViewById(R.id.notification_guts_bundle_feedback);
+ feedbackButton.performClick();
+ // Listener was not triggered
+ assertEquals(1, latch.getCount());
+ assertEquals(View.GONE, feedbackButton.getVisibility());
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testBindNotification_hidesFeedbackButtonWhenNoIntent() throws Exception {
+ // When the Notification Assistant is available,
+ when(mMockINotificationManager.getAllowedNotificationAssistant()).thenReturn(
+ new ComponentName("assistantPkg", "assistantCls"));
+
+ // But the intent activity is null
+ when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(null);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mOnUserInteractionCallback,
+ mChannelEditorDialogController,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ null,
+ (View v, Intent intent) -> {
+ // Assert that the intent action and package match.
+ assertEquals(intent.getAction(),
+ ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS);
+ assertEquals(intent.getPackage(), "assistantPkg");
+ latch.countDown();
+ },
+ mUiEventLogger,
+ true,
+ false,
+ true,
+ mAssistantFeedbackController,
+ mMetricsLogger);
+
+ final View feedbackButton = mInfo.findViewById(R.id.notification_guts_bundle_feedback);
+ feedbackButton.performClick();
+ // Listener was not triggered
+ assertEquals(1, latch.getCount());
+ assertEquals(View.GONE, feedbackButton.getVisibility());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
index fd4192151c57..371e1c569cef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
@@ -16,13 +16,13 @@
package com.android.systemui.statusbar.notification.row
import android.content.Context
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.util.AttributeSet
import android.view.View
import android.widget.Button
import android.widget.FrameLayout
import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED
@@ -38,7 +38,7 @@ import org.mockito.Mockito.verify
/** Tests for [NotifLayoutInflaterFactory] */
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class NotifLayoutInflaterFactoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
index a1b63b159277..b16d3ea5337b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
@@ -168,7 +168,10 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
@JvmStatic
@Parameters(name = "{0}")
fun getParams(): List<FlagsParameterization> {
- return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ return FlagsParameterization.allCombinationsOf(
+ android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI
+ )
+ .andSceneContainer()
}
}
@@ -614,6 +617,43 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
)
}
+ @Test
+ @Throws(Exception::class)
+ fun testInitializeBundleNotificationInfoView() {
+ val infoView: BundleNotificationInfo = mock()
+ val row = spy(helper.createRow())
+ val entry = row.entry
+
+ // Modify the notification entry to have a channel that is in SYSTEM_RESERVED_IDS
+ val channel = NotificationChannel(NotificationChannel.NEWS_ID, "name", 2)
+ NotificationEntryHelper.modifyRanking(entry).setChannel(channel).build()
+
+ whenever(row.isNonblockable).thenReturn(false)
+ val statusBarNotification = entry.sbn
+ // Can we change this to a call to bindGuts instead? We have the row,
+ // we need a MenuItem that we can put the infoView into.
+ gutsManager.initializeBundleNotificationInfo(row, infoView)
+
+ verify(infoView)
+ .bindNotification(
+ any<PackageManager>(),
+ any<INotificationManager>(),
+ eq(onUserInteractionCallback),
+ eq(channelEditorDialogController),
+ eq(statusBarNotification.packageName),
+ any<NotificationChannel>(),
+ eq(entry),
+ any<NotificationInfo.OnSettingsClickListener>(),
+ any<NotificationInfo.OnAppSettingsClickListener>(),
+ any<UiEventLogger>(),
+ /* isDeviceProvisioned = */ eq(false),
+ /* isNonblockable = */ eq(false),
+ /* wasShownHighPriority = */ eq(false),
+ eq(assistantFeedbackController),
+ eq(metricsLogger),
+ )
+ }
+
private fun createTestNotificationRow(): ExpandableNotificationRow {
val nb =
Notification.Builder(mContext, testNotificationChannel.id)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 3669e3d8fed1..b8745b3e95b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -21,12 +21,12 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class NotificationSectionsManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index b2a485c48860..b877456ab604 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -32,23 +32,19 @@ import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.policy.AvalancheController
-import com.android.systemui.util.mockito.mock
import com.google.common.truth.Expect
import com.google.common.truth.Truth.assertThat
-import junit.framework.Assert.assertEquals
-import junit.framework.Assert.assertFalse
-import junit.framework.Assert.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Assume
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.any
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
@@ -846,7 +842,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
val viewStart = 0f
val shelfStart = 1f
- val expandableView = mock(ExpandableView::class.java)
+ val expandableView = mock<ExpandableView>()
whenever(expandableView.isExpandAnimationRunning).thenReturn(false)
whenever(expandableView.hasExpandingChild()).thenReturn(false)
@@ -854,7 +850,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState.yTranslation = viewStart
stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
- assertFalse(expandableViewState.hidden)
+ assertThat(expandableViewState.hidden).isFalse()
}
@Test
@@ -862,7 +858,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
val shelfStart = 0f
val viewStart = 1f
- val expandableView = mock(ExpandableView::class.java)
+ val expandableView = mock<ExpandableView>()
whenever(expandableView.isExpandAnimationRunning).thenReturn(false)
whenever(expandableView.hasExpandingChild()).thenReturn(false)
@@ -870,7 +866,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState.yTranslation = viewStart
stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
- assertTrue(expandableViewState.hidden)
+ assertThat(expandableViewState.hidden).isTrue()
}
@Test
@@ -878,7 +874,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
val shelfStart = 0f
val viewStart = 1f
- val expandableView = mock(ExpandableView::class.java)
+ val expandableView = mock<ExpandableView>()
whenever(expandableView.isExpandAnimationRunning).thenReturn(true)
whenever(expandableView.hasExpandingChild()).thenReturn(true)
@@ -886,7 +882,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState.yTranslation = viewStart
stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
- assertFalse(expandableViewState.hidden)
+ assertThat(expandableViewState.hidden).isFalse()
}
@Test
@@ -898,12 +894,12 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState,
/* isShadeExpanded= */ true,
/* mustStayOnScreen= */ true,
- /* isViewEndVisible= */ true,
+ /* topVisible = */ true,
/* viewEnd= */ 0f,
- /* maxHunY= */ 10f,
+ /* hunMax = */ 10f,
)
- assertTrue(expandableViewState.headsUpIsVisible)
+ assertThat(expandableViewState.headsUpIsVisible).isTrue()
}
@Test
@@ -915,12 +911,12 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState,
/* isShadeExpanded= */ true,
/* mustStayOnScreen= */ true,
- /* isViewEndVisible= */ true,
+ /* topVisible = */ true,
/* viewEnd= */ 10f,
- /* maxHunY= */ 0f,
+ /* hunMax = */ 0f,
)
- assertFalse(expandableViewState.headsUpIsVisible)
+ assertThat(expandableViewState.headsUpIsVisible).isFalse()
}
@Test
@@ -932,12 +928,12 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState,
/* isShadeExpanded= */ false,
/* mustStayOnScreen= */ true,
- /* isViewEndVisible= */ true,
+ /* topVisible = */ true,
/* viewEnd= */ 10f,
- /* maxHunY= */ 1f,
+ /* hunMax = */ 1f,
)
- assertTrue(expandableViewState.headsUpIsVisible)
+ assertThat(expandableViewState.headsUpIsVisible).isTrue()
}
@Test
@@ -949,12 +945,12 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState,
/* isShadeExpanded= */ true,
/* mustStayOnScreen= */ false,
- /* isViewEndVisible= */ true,
+ /* topVisible = */ true,
/* viewEnd= */ 10f,
- /* maxHunY= */ 1f,
+ /* hunMax = */ 1f,
)
- assertTrue(expandableViewState.headsUpIsVisible)
+ assertThat(expandableViewState.headsUpIsVisible).isTrue()
}
@Test
@@ -966,12 +962,12 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
expandableViewState,
/* isShadeExpanded= */ true,
/* mustStayOnScreen= */ true,
- /* isViewEndVisible= */ false,
+ /* topVisible = */ false,
/* viewEnd= */ 10f,
- /* maxHunY= */ 1f,
+ /* hunMax = */ 1f,
)
- assertTrue(expandableViewState.headsUpIsVisible)
+ assertThat(expandableViewState.headsUpIsVisible).isTrue()
}
@Test
@@ -986,7 +982,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
)
// qqs (10 + 0) < viewY (50)
- assertEquals(50f, expandableViewState.yTranslation)
+ assertThat(expandableViewState.yTranslation).isEqualTo(50f)
}
@Test
@@ -1001,7 +997,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
)
// qqs (10 + 0) > viewY (-10)
- assertEquals(10f, expandableViewState.yTranslation)
+ assertThat(expandableViewState.yTranslation).isEqualTo(10f)
}
@Test
@@ -1019,7 +1015,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
// newTranslation = max(10, -100) = 10
// distToRealY = 10 - (-100f) = 110
// height = max(20 - 110, 10f)
- assertEquals(10, expandableViewState.height)
+ assertThat(expandableViewState.height).isEqualTo(10)
}
@Test
@@ -1037,7 +1033,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
// newTranslation = max(10, 5) = 10
// distToRealY = 10 - 5 = 5
// height = max(20 - 5, 10) = 15
- assertEquals(15, expandableViewState.height)
+ assertThat(expandableViewState.height).isEqualTo(15)
}
@Test
@@ -1047,9 +1043,9 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
/* hostViewHeight= */ 100f,
/* stackY= */ 110f,
/* viewMaxHeight= */ 20f,
- /* originalCornerRoundness= */ 0f,
+ /* originalCornerRadius = */ 0f,
)
- assertEquals(1f, currentRoundness)
+ assertThat(currentRoundness).isEqualTo(1f)
}
@Test
@@ -1059,9 +1055,9 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
/* hostViewHeight= */ 100f,
/* stackY= */ 90f,
/* viewMaxHeight= */ 20f,
- /* originalCornerRoundness= */ 0f,
+ /* originalCornerRadius = */ 0f,
)
- assertEquals(0.5f, currentRoundness)
+ assertThat(currentRoundness).isEqualTo(0.5f)
}
@Test
@@ -1071,9 +1067,9 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
/* hostViewHeight= */ 100f,
/* stackY= */ 0f,
/* viewMaxHeight= */ 20f,
- /* originalCornerRoundness= */ 0f,
+ /* originalCornerRadius = */ 0f,
)
- assertEquals(0f, currentRoundness)
+ assertThat(currentRoundness).isZero()
}
@Test
@@ -1083,9 +1079,9 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
/* hostViewHeight= */ 100f,
/* stackY= */ 0f,
/* viewMaxHeight= */ 20f,
- /* originalCornerRoundness= */ 1f,
+ /* originalCornerRadius = */ 1f,
)
- assertEquals(1f, currentRoundness)
+ assertThat(currentRoundness).isEqualTo(1f)
}
@Test
@@ -1105,13 +1101,14 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
/* childrenOnTop= */ 0.0f,
- /* StackScrollAlgorithmState= */ algorithmState,
+ /* algorithmState = */ algorithmState,
/* ambientState= */ ambientState,
- /* shouldElevateHun= */ true,
+ /* isTopHun = */ true,
)
// Then: full shadow would be applied
- assertEquals(px(R.dimen.heads_up_pinned_elevation), childHunView.viewState.zTranslation)
+ assertThat(childHunView.viewState.zTranslation)
+ .isEqualTo(px(R.dimen.heads_up_pinned_elevation))
}
@Test
@@ -1133,9 +1130,9 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
/* childrenOnTop= */ 0.0f,
- /* StackScrollAlgorithmState= */ algorithmState,
+ /* algorithmState = */ algorithmState,
/* ambientState= */ ambientState,
- /* shouldElevateHun= */ true,
+ /* isTopHun = */ true,
)
// Then: HUN should have shadow, but not as full size
@@ -1166,13 +1163,13 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
/* childrenOnTop= */ 0.0f,
- /* StackScrollAlgorithmState= */ algorithmState,
+ /* algorithmState = */ algorithmState,
/* ambientState= */ ambientState,
- /* shouldElevateHun= */ true,
+ /* isTopHun = */ true,
)
// Then: HUN should not have shadow
- assertEquals(0f, childHunView.viewState.zTranslation)
+ assertThat(childHunView.viewState.zTranslation).isZero()
}
@Test
@@ -1195,13 +1192,14 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
/* childrenOnTop= */ 0.0f,
- /* StackScrollAlgorithmState= */ algorithmState,
+ /* algorithmState = */ algorithmState,
/* ambientState= */ ambientState,
- /* shouldElevateHun= */ true,
+ /* isTopHun = */ true,
)
// Then: HUN should have full shadow
- assertEquals(px(R.dimen.heads_up_pinned_elevation), childHunView.viewState.zTranslation)
+ assertThat(childHunView.viewState.zTranslation)
+ .isEqualTo(px(R.dimen.heads_up_pinned_elevation))
}
@Test
@@ -1225,9 +1223,9 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
/* childrenOnTop= */ 0.0f,
- /* StackScrollAlgorithmState= */ algorithmState,
+ /* algorithmState = */ algorithmState,
/* ambientState= */ ambientState,
- /* shouldElevateHun= */ true,
+ /* isTopHun = */ true,
)
// Then: HUN should have shadow, but not as full size
@@ -1251,7 +1249,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
// Then: ambientState.pulsingRow should still be pulsingNotificationView
- assertTrue(ambientState.isPulsingRow(pulsingNotificationView))
+ assertThat(ambientState.isPulsingRow(pulsingNotificationView)).isTrue()
}
@Test
@@ -1268,7 +1266,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
// Then: ambientState.pulsingRow should record the pulsingNotificationView
- assertTrue(ambientState.isPulsingRow(pulsingNotificationView))
+ assertThat(ambientState.isPulsingRow(pulsingNotificationView)).isTrue()
}
@Test
@@ -1287,7 +1285,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
// Then: ambientState.pulsingRow should be null
- assertTrue(ambientState.isPulsingRow(null))
+ assertThat(ambientState.isPulsingRow(null)).isTrue()
}
@Test
@@ -1310,10 +1308,8 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
stackScrollAlgorithm.resetViewStates(ambientState, 0)
// Then: pulsingNotificationView should show at full height
- assertEquals(
- stackScrollAlgorithm.getMaxAllowedChildHeight(pulsingNotificationView),
- pulsingNotificationView.viewState.height,
- )
+ assertThat(pulsingNotificationView.viewState.height)
+ .isEqualTo(stackScrollAlgorithm.getMaxAllowedChildHeight(pulsingNotificationView))
// After: reset dozeAmount and expansionFraction
ambientState.dozeAmount = 0f
@@ -1418,7 +1414,7 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
yTranslation = ambientState.maxHeadsUpTranslation - height // move it to the max
}
- assertTrue(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState))
+ assertThat(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState)).isTrue()
}
@Test
@@ -1431,7 +1427,8 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
ambientState.maxHeadsUpTranslation - height - 1 // move it below the max
}
- assertFalse(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState))
+ assertThat(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState))
+ .isFalse()
}
// endregion
@@ -1579,13 +1576,13 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() {
}
private fun mockExpandableNotificationRow(): ExpandableNotificationRow {
- return mock(ExpandableNotificationRow::class.java).apply {
+ return mock<ExpandableNotificationRow>().apply {
whenever(viewState).thenReturn(ExpandableViewState())
}
}
private fun mockFooterView(height: Int): FooterView {
- return mock(FooterView::class.java).apply {
+ return mock<FooterView>().apply {
whenever(viewState).thenReturn(FooterViewState())
whenever(intrinsicHeight).thenReturn(height)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index a940ed4d70f9..f48fd3c998b1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -838,27 +838,26 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
testScope.runTest {
var notificationCount = 10
val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
- val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
+ val config by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
advanceTimeBy(50L)
showLockscreen()
shadeTestUtil.setSplitShade(false)
configurationRepository.onAnyConfigurationChange()
- assertThat(maxNotifications).isEqualTo(10)
+ assertThat(config?.maxNotifications).isEqualTo(10)
// Also updates when directly requested (as it would from NotificationStackScrollLayout)
notificationCount = 25
sharedNotificationContainerInteractor.notificationStackChanged()
advanceTimeBy(50L)
- assertThat(maxNotifications).isEqualTo(25)
+ assertThat(config?.maxNotifications).isEqualTo(25)
// Also ensure another collection starts with the same value. As an example, folding
// then unfolding will restart the coroutine and it must get the last value immediately.
- val newMaxNotifications by
- collectLastValue(underTest.getMaxNotifications(calculateSpace))
+ val newConfig by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
advanceTimeBy(50L)
- assertThat(newMaxNotifications).isEqualTo(25)
+ assertThat(newConfig?.maxNotifications).isEqualTo(25)
}
@Test
@@ -866,18 +865,18 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
testScope.runTest {
var notificationCount = 10
val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
- val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
+ val config by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
advanceTimeBy(50L)
showLockscreen()
shadeTestUtil.setSplitShade(false)
configurationRepository.onAnyConfigurationChange()
- assertThat(maxNotifications).isEqualTo(10)
+ assertThat(config?.maxNotifications).isEqualTo(10)
// Shade expanding... still 10
shadeTestUtil.setLockscreenShadeExpansion(0.5f)
- assertThat(maxNotifications).isEqualTo(10)
+ assertThat(config?.maxNotifications).isEqualTo(10)
notificationCount = 25
@@ -885,20 +884,20 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
shadeTestUtil.setLockscreenShadeTracking(true)
// Should still be 10, since the user is interacting
- assertThat(maxNotifications).isEqualTo(10)
+ assertThat(config?.maxNotifications).isEqualTo(10)
shadeTestUtil.setLockscreenShadeTracking(false)
shadeTestUtil.setLockscreenShadeExpansion(0f)
// Stopped tracking, show 25
- assertThat(maxNotifications).isEqualTo(25)
+ assertThat(config?.maxNotifications).isEqualTo(25)
}
@Test
fun maxNotificationsOnShade() =
testScope.runTest {
val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> 10 }
- val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
+ val config by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
advanceTimeBy(50L)
// Show lockscreen with shade expanded
@@ -908,7 +907,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
configurationRepository.onAnyConfigurationChange()
// -1 means No Limit
- assertThat(maxNotifications).isEqualTo(-1)
+ assertThat(config?.maxNotifications).isEqualTo(-1)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
new file mode 100644
index 000000000000..0b0b1e45d604
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 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.statusbar.phone
+
+import android.platform.test.annotations.EnableFlags
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+class MultiDisplayAutoHideControllerStoreTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val testScope = kosmos.testScope
+ private val fakeDisplayRepository = kosmos.displayRepository
+
+ // Lazy so that @EnableFlags has time to run before underTest is instantiated.
+ private val underTest by lazy { kosmos.multiDisplayAutoHideControllerStore }
+
+ @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
+
+ @Test
+ fun beforeDisplayRemoved_doesNotStopInstances() =
+ testScope.runTest {
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+ verify(instance, never()).stop()
+ }
+
+ @Test
+ fun displayRemoved_stopsInstance() =
+ testScope.runTest {
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+ fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+
+ verify(instance).stop()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
index 778e8228ab9b..7a51b2ddb020 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -1088,7 +1088,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
@Test
@DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
- fun onMaxBoundsChanged_beforeStart_flagDisabled_listenerNotNotified() {
+ fun onMaxBoundsChanged_beforeStart_flagDisabled_listenerNotified() {
// Start out with an existing configuration with bounds
configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100)
configurationController.onConfigurationChanged(configuration)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index f6d439ab2639..5a77f3d40e82 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.os.ParcelUuid
-import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
@@ -25,91 +24,78 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
-import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.flags.fake
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryLogbufferName
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
-import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.fake
import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
import com.android.systemui.testKosmos
import com.android.systemui.util.CarrierConfigTracker
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.util.UUID
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class MobileIconsInteractorTest : SysuiTestCase() {
- private val kosmos = testKosmos()
-
- private lateinit var underTest: MobileIconsInteractor
- private lateinit var connectivityRepository: FakeConnectivityRepository
- private lateinit var connectionsRepository: FakeMobileConnectionsRepository
- private val userSetupRepository = FakeUserSetupRepository()
- private val mobileMappingsProxy = FakeMobileMappingsProxy()
- private val flags =
- FakeFeatureFlagsClassic().apply {
- set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+ private val kosmos by lazy {
+ testKosmos().apply {
+ mobileConnectionsRepositoryLogbufferName = "MobileIconsInteractorTest"
+ mobileConnectionsRepository.fake.run {
+ setMobileConnectionRepositoryMap(
+ mapOf(
+ SUB_1_ID to CONNECTION_1,
+ SUB_2_ID to CONNECTION_2,
+ SUB_3_ID to CONNECTION_3,
+ SUB_4_ID to CONNECTION_4,
+ )
+ )
+ setActiveMobileDataSubscriptionId(SUB_1_ID)
+ }
+ featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
}
+ }
- private val testDispatcher = StandardTestDispatcher()
- private val testScope = TestScope(testDispatcher)
-
- private val tableLogBuffer = logcatTableLogBuffer(kosmos, "MobileIconsInteractorTest")
-
- @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- connectivityRepository = FakeConnectivityRepository()
-
- connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy, tableLogBuffer)
- connectionsRepository.setMobileConnectionRepositoryMap(
- mapOf(
- SUB_1_ID to CONNECTION_1,
- SUB_2_ID to CONNECTION_2,
- SUB_3_ID to CONNECTION_3,
- SUB_4_ID to CONNECTION_4,
- )
+ // shortcut rename
+ private val Kosmos.connectionsRepository by Fixture { mobileConnectionsRepository.fake }
+
+ private val Kosmos.carrierConfigTracker by Fixture { mock<CarrierConfigTracker>() }
+
+ private val Kosmos.underTest by Fixture {
+ MobileIconsInteractorImpl(
+ mobileConnectionsRepository,
+ carrierConfigTracker,
+ tableLogger = mock(),
+ connectivityRepository,
+ FakeUserSetupRepository(),
+ testScope.backgroundScope,
+ context,
+ featureFlagsClassic,
)
- connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
-
- underTest =
- MobileIconsInteractorImpl(
- connectionsRepository,
- carrierConfigTracker,
- tableLogger = mock(),
- connectivityRepository,
- userSetupRepository,
- testScope.backgroundScope,
- context,
- flags,
- )
}
@Test
fun filteredSubscriptions_default() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.filteredSubscriptions)
assertThat(latest).isEqualTo(listOf<SubscriptionModel>())
@@ -118,7 +104,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
// Based on the logic from the old pipeline, we'll never filter subs when there are more than 2
@Test
fun filteredSubscriptions_moreThanTwo_doesNotFilter() =
- testScope.runTest {
+ kosmos.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
@@ -129,7 +115,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
- testScope.runTest {
+ kosmos.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
val latest by collectLastValue(underTest.filteredSubscriptions)
@@ -139,7 +125,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() =
- testScope.runTest {
+ kosmos.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
@@ -150,7 +136,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() =
- testScope.runTest {
+ kosmos.runTest {
val (sub1, sub2) =
createSubscriptionPair(
subscriptionIds = Pair(SUB_1_ID, SUB_2_ID),
@@ -167,7 +153,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() =
- testScope.runTest {
+ kosmos.runTest {
val (sub3, sub4) =
createSubscriptionPair(
subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
@@ -187,7 +173,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() =
- testScope.runTest {
+ kosmos.runTest {
val (sub3, sub4) =
createSubscriptionPair(
subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
@@ -207,7 +193,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() =
- testScope.runTest {
+ kosmos.runTest {
val (sub1, sub3) =
createSubscriptionPair(
subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -228,7 +214,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() =
- testScope.runTest {
+ kosmos.runTest {
val (sub1, sub3) =
createSubscriptionPair(
subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -249,7 +235,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_vcnSubId_agreesWithActiveSubId_usesActiveAkaVcnSub() =
- testScope.runTest {
+ kosmos.runTest {
val (sub1, sub3) =
createSubscriptionPair(
subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -258,7 +244,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
)
connectionsRepository.setSubscriptions(listOf(sub1, sub3))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
- connectivityRepository.vcnSubId.value = SUB_3_ID
+ kosmos.connectivityRepository.fake.vcnSubId.value = SUB_3_ID
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
.thenReturn(false)
@@ -269,7 +255,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_vcnSubId_disagreesWithActiveSubId_usesVcnSub() =
- testScope.runTest {
+ kosmos.runTest {
val (sub1, sub3) =
createSubscriptionPair(
subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -278,7 +264,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
)
connectionsRepository.setSubscriptions(listOf(sub1, sub3))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
- connectivityRepository.vcnSubId.value = SUB_1_ID
+ kosmos.connectivityRepository.fake.vcnSubId.value = SUB_1_ID
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
.thenReturn(false)
@@ -289,9 +275,9 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() =
- testScope.runTest {
+ kosmos.runTest {
// GIVEN the flag is false
- flags.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
+ featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
// GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING
val sub1 =
@@ -313,7 +299,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_filtersOutProvisioningSubs() =
- testScope.runTest {
+ kosmos.runTest {
val sub1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
@@ -326,7 +312,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = SUB_2_ID,
isOpportunistic = false,
carrierName = "Carrier 2",
- profileClass = SubscriptionManager.PROFILE_CLASS_PROVISIONING,
+ profileClass = PROFILE_CLASS_PROVISIONING,
)
connectionsRepository.setSubscriptions(listOf(sub1, sub2))
@@ -339,7 +325,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
/** Note: I'm not sure if this will ever be the case, but we can test it at least */
@Test
fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() =
- testScope.runTest {
+ kosmos.runTest {
// This is a contrived test case, where the active subId is the one that would
// also be filtered by opportunistic filtering.
@@ -376,7 +362,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_groupedPairAndNonProvisioned_groupedFilteringStillHappens() =
- testScope.runTest {
+ kosmos.runTest {
// Grouped filtering only happens when the list of subs is length 2. In this case
// we'll show that filtering of provisioning subs happens before, and thus grouped
// filtering happens even though the unfiltered list is length 3
@@ -406,7 +392,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_subNotExclusivelyNonTerrestrial_hasSub() =
- testScope.runTest {
+ kosmos.runTest {
val notExclusivelyNonTerrestrialSub =
SubscriptionModel(
isExclusivelyNonTerrestrial = false,
@@ -424,7 +410,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_subExclusivelyNonTerrestrial_doesNotHaveSub() =
- testScope.runTest {
+ kosmos.runTest {
val exclusivelyNonTerrestrialSub =
SubscriptionModel(
isExclusivelyNonTerrestrial = true,
@@ -442,7 +428,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscription_mixOfExclusivelyNonTerrestrialAndOther_hasOtherSubsOnly() =
- testScope.runTest {
+ kosmos.runTest {
val exclusivelyNonTerrestrialSub =
SubscriptionModel(
isExclusivelyNonTerrestrial = true,
@@ -476,7 +462,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_exclusivelyNonTerrestrialSub_andOpportunistic_bothFiltersHappen() =
- testScope.runTest {
+ kosmos.runTest {
// Exclusively non-terrestrial sub
val exclusivelyNonTerrestrialSub =
SubscriptionModel(
@@ -507,7 +493,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun activeDataConnection_turnedOn() =
- testScope.runTest {
+ kosmos.runTest {
CONNECTION_1.setDataEnabled(true)
val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
@@ -517,7 +503,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun activeDataConnection_turnedOff() =
- testScope.runTest {
+ kosmos.runTest {
CONNECTION_1.setDataEnabled(true)
val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
@@ -528,7 +514,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun activeDataConnection_invalidSubId() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
connectionsRepository.setActiveMobileDataSubscriptionId(INVALID_SUBSCRIPTION_ID)
@@ -539,7 +525,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_default_validated_notFailed() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = true
@@ -550,7 +536,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_notDefault_notValidated_notFailed() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = false
@@ -561,7 +547,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_default_notValidated_failed() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = true
@@ -572,7 +558,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_carrierMergedDefault_notValidated_failed() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.hasCarrierMergedConnection.value = true
@@ -584,7 +570,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
/** Regression test for b/275076959. */
@Test
fun failedConnection_dataSwitchInSameGroup_notFailed() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = true
@@ -602,7 +588,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_dataSwitchNotInSameGroup_isFailed() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = true
@@ -618,7 +604,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysShowDataRatIcon_configHasTrue() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
val config = MobileMappings.Config()
@@ -630,7 +616,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysShowDataRatIcon_configHasFalse() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
val config = MobileMappings.Config()
@@ -642,7 +628,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysUseCdmaLevel_configHasTrue() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
val config = MobileMappings.Config()
@@ -654,7 +640,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysUseCdmaLevel_configHasFalse() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
val config = MobileMappings.Config()
@@ -666,7 +652,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun isSingleCarrier_zeroSubscriptions_false() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isSingleCarrier)
connectionsRepository.setSubscriptions(emptyList())
@@ -676,7 +662,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun isSingleCarrier_oneSubscription_true() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isSingleCarrier)
connectionsRepository.setSubscriptions(listOf(SUB_1))
@@ -686,7 +672,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun isSingleCarrier_twoSubscriptions_false() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isSingleCarrier)
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
@@ -696,7 +682,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun isSingleCarrier_updates() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isSingleCarrier)
connectionsRepository.setSubscriptions(listOf(SUB_1))
@@ -708,7 +694,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.mobileIsDefault)
connectionsRepository.mobileIsDefault.value = false
@@ -719,7 +705,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun mobileIsDefault_mobileTrueAndCarrierMergedFalse_true() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.mobileIsDefault)
connectionsRepository.mobileIsDefault.value = true
@@ -731,7 +717,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
/** Regression test for b/272586234. */
@Test
fun mobileIsDefault_mobileFalseAndCarrierMergedTrue_true() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.mobileIsDefault)
connectionsRepository.mobileIsDefault.value = false
@@ -742,7 +728,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun mobileIsDefault_updatesWhenRepoUpdates() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.mobileIsDefault)
connectionsRepository.mobileIsDefault.value = true
@@ -760,7 +746,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun dataSwitch_inSameGroup_validatedMatchesPreviousValue_expiresAfter2s() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = true
@@ -774,17 +760,17 @@ class MobileIconsInteractorTest : SysuiTestCase() {
// After 1s, the force validation bit is still present, so the connection is not marked
// as failed
- advanceTimeBy(1000)
+ testScope.advanceTimeBy(1000)
assertThat(latest).isFalse()
// After 2s, the force validation expires so the connection updates to failed
- advanceTimeBy(1001)
+ testScope.advanceTimeBy(1001)
assertThat(latest).isTrue()
}
@Test
fun dataSwitch_inSameGroup_notValidated_immediatelyMarkedAsFailed() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = true
@@ -798,7 +784,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun dataSwitch_loseValidation_thenSwitchHappens_clearsForcedBit() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
// GIVEN the network starts validated
@@ -819,17 +805,17 @@ class MobileIconsInteractorTest : SysuiTestCase() {
// THEN the forced validation bit is still used...
assertThat(latest).isFalse()
- advanceTimeBy(1000)
+ testScope.advanceTimeBy(1000)
assertThat(latest).isFalse()
// ... but expires after 2s
- advanceTimeBy(1001)
+ testScope.advanceTimeBy(1001)
assertThat(latest).isTrue()
}
@Test
fun dataSwitch_whileAlreadyForcingValidation_resetsClock() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDefaultConnectionFailed)
connectionsRepository.mobileIsDefault.value = true
connectionsRepository.defaultConnectionIsValidated.value = true
@@ -837,7 +823,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
- advanceTimeBy(1000)
+ testScope.advanceTimeBy(1000)
// WHEN another change in same group event happens
connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
@@ -847,37 +833,37 @@ class MobileIconsInteractorTest : SysuiTestCase() {
// THEN the forced validation remains for exactly 2 more seconds from now
// 1.500s from second event
- advanceTimeBy(1500)
+ testScope.advanceTimeBy(1500)
assertThat(latest).isFalse()
// 2.001s from the second event
- advanceTimeBy(501)
+ testScope.advanceTimeBy(501)
assertThat(latest).isTrue()
}
@Test
fun isForceHidden_repoHasMobileHidden_true() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isForceHidden)
- connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
+ kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
assertThat(latest).isTrue()
}
@Test
fun isForceHidden_repoDoesNotHaveMobileHidden_false() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isForceHidden)
- connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+ kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
assertThat(latest).isFalse()
}
@Test
fun iconInteractor_cachedPerSubId() =
- testScope.runTest {
+ kosmos.runTest {
val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
@@ -887,7 +873,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() =
- testScope.runTest {
+ kosmos.runTest {
val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
connectionsRepository.isDeviceEmergencyCallCapable.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
index 46f822aae7b8..db24d4bc8070 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
@@ -21,18 +21,18 @@ import android.app.StatusBarManager.DISABLE_CLOCK
import android.app.StatusBarManager.DISABLE_NONE
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
-import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
-import org.junit.runner.RunWith;
+import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index c4d2569bba89..b9cdd06de5a2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -58,8 +58,8 @@ import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsVie
import com.android.systemui.statusbar.data.model.StatusBarMode
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.statusbar.events.data.repository.systemStatusEventAnimationRepository
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingIn
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingOut
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index d823bf57c824..4eef308a2772 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -27,10 +27,14 @@ import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
@@ -40,9 +44,7 @@ import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkMode
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
-import com.android.systemui.user.data.repository.userRepository
import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.time.fakeSystemClock
import com.android.wifitrackerlib.HotspotNetworkEntry
import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
@@ -53,31 +55,23 @@ import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
import com.android.wifitrackerlib.WifiPickerTracker
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.kotlin.any
-import org.mockito.kotlin.capture
+import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.mock
-import org.mockito.kotlin.times
+import org.mockito.kotlin.never
+import org.mockito.kotlin.reset
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
-/**
- * Note: Most of these tests are duplicates of [WifiRepositoryImplTest] tests.
- *
- * Any new tests added here may also need to be added to [WifiRepositoryImplTest].
- */
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class WifiRepositoryImplTest() : SysuiTestCase() {
- private val kosmos = testKosmos()
+class WifiRepositoryImplTest : SysuiTestCase() {
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
private val userRepository = kosmos.fakeUserRepository
// Using lazy means that the class will only be constructed once it's fetched. Because the
@@ -108,13 +102,13 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
private val callbackCaptor = argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>()
- private val dispatcher = StandardTestDispatcher()
- private val testScope = TestScope(dispatcher)
+ private val dispatcher = kosmos.testDispatcher
+ private val testScope = kosmos.testScope
@Before
fun setUp() {
userRepository.setUserInfos(listOf(PRIMARY_USER, ANOTHER_USER))
- whenever(wifiPickerTrackerFactory.create(any(), any(), capture(callbackCaptor), any()))
+ whenever(wifiPickerTrackerFactory.create(any(), any(), callbackCaptor.capture(), any()))
.thenReturn(wifiPickerTracker)
}
@@ -122,7 +116,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
fun wifiPickerTrackerCreation_scansDisabled() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
- testScope.runCurrent()
verify(wifiPickerTracker).disableScanning()
}
@@ -1001,7 +994,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(false) }
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
@@ -1017,7 +1009,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
@@ -1034,7 +1025,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
@@ -1051,7 +1041,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
@@ -1068,7 +1057,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
@@ -1085,7 +1073,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
}
@@ -1103,14 +1090,12 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
// WHEN the network is lost
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
getCallback().onWifiEntriesChanged()
- testScope.runCurrent()
// THEN the isWifiConnected updates
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
@@ -1216,9 +1201,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
assertThat(latest).isEmpty()
}
- // TODO(b/371586248): This test currently require currentUserContext to be public for testing,
- // this needs to
- // be updated to capture the argument instead so currentUserContext can be private.
@Test
@EnableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT)
fun oneUserVerifyCreatingWifiPickerTracker_multiuserFlagEnabled() =
@@ -1230,16 +1212,16 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
)
userRepository.setSelectedUserInfo(PRIMARY_USER)
- runCurrent()
- val currentUserContext by collectLastValue(underTest.selectedUserContext)
- assertThat(currentUserContext).isEqualTo(primaryUserMockContext)
- verify(wifiPickerTrackerFactory).create(any(), any(), any(), any())
+ collectLastValue(underTest.wifiNetwork)
+
+ val contextCaptor = argumentCaptor<Context>()
+ verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any())
+ // If the flag is on, verify that we use the context from #createContextAsUser and we
+ // do NOT use the top-level context
+ assertThat(contextCaptor.firstValue).isEqualTo(primaryUserMockContext)
}
- // TODO(b/371586248): This test currently require currentUserContext to be public for testing,
- // this needs to
- // be updated to capture the argument instead so currentUserContext can be private.
@Test
@EnableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT)
fun changeUserVerifyCreatingWifiPickerTracker_multiuserEnabled() =
@@ -1249,32 +1231,30 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
UserHandle.of(PRIMARY_USER_ID),
primaryUserMockContext,
)
-
- runCurrent()
userRepository.setSelectedUserInfo(PRIMARY_USER)
- runCurrent()
- val currentUserContext by collectLastValue(underTest.selectedUserContext)
- assertThat(currentUserContext).isEqualTo(primaryUserMockContext)
+ collectLastValue(underTest.wifiNetwork)
+
+ val contextCaptor = argumentCaptor<Context>()
+ verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any())
+ assertThat(contextCaptor.firstValue).isEqualTo(primaryUserMockContext)
+ reset(wifiPickerTrackerFactory)
+
+ // WHEN we switch to a different user
val otherUserMockContext = mock<Context>()
mContext.prepareCreateContextAsUser(
UserHandle.of(ANOTHER_USER_ID),
otherUserMockContext,
)
-
- runCurrent()
userRepository.setSelectedUserInfo(ANOTHER_USER)
- runCurrent()
- val otherUserContext by collectLastValue(underTest.selectedUserContext)
- assertThat(otherUserContext).isEqualTo(otherUserMockContext)
- verify(wifiPickerTrackerFactory, times(2)).create(any(), any(), any(), any())
+ // THEN we use the different user's context to create WifiPickerTracker
+ val newCaptor = argumentCaptor<Context>()
+ verify(wifiPickerTrackerFactory).create(newCaptor.capture(), any(), any(), any())
+ assertThat(newCaptor.firstValue).isEqualTo(otherUserMockContext)
}
- // TODO(b/371586248): This test currently require currentUserContext to be public for testing,
- // this needs to
- // be updated to capture the argument instead so currentUserContext can be private.
@Test
@DisableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT)
fun changeUserVerifyCreatingWifiPickerTracker_multiuserDisabled() =
@@ -1285,36 +1265,39 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
primaryUserMockContext,
)
- runCurrent()
userRepository.setSelectedUserInfo(PRIMARY_USER)
- runCurrent()
- val currentUserContext by collectLastValue(underTest.selectedUserContext)
- assertThat(currentUserContext).isEqualTo(primaryUserMockContext)
+ collectLastValue(underTest.wifiNetwork)
+
+ val contextCaptor = argumentCaptor<Context>()
+ verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any())
+ // If the flag is off, verify that we do NOT use the context from #createContextAsUser
+ // and we instead use the top-level context
+ assertThat(contextCaptor.firstValue).isNotEqualTo(primaryUserMockContext)
+ assertThat(contextCaptor.firstValue).isEqualTo(mContext)
+
+ reset(wifiPickerTrackerFactory)
+ // WHEN we switch to a different user
val otherUserMockContext = mock<Context>()
mContext.prepareCreateContextAsUser(
UserHandle.of(ANOTHER_USER_ID),
otherUserMockContext,
)
-
- runCurrent()
userRepository.setSelectedUserInfo(ANOTHER_USER)
- runCurrent()
- verify(wifiPickerTrackerFactory, times(1)).create(any(), any(), any(), any())
+ // THEN we do NOT re-create WifiPickerTracker because the multiuser flag is off
+ verify(wifiPickerTrackerFactory, never()).create(any(), any(), any(), any())
}
private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback {
- testScope.runCurrent()
- return callbackCaptor.value
+ return callbackCaptor.firstValue
}
private fun getTrafficStateCallback(): WifiManager.TrafficStateCallback {
- testScope.runCurrent()
val callbackCaptor = argumentCaptor<WifiManager.TrafficStateCallback>()
verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
- return callbackCaptor.value!!
+ return callbackCaptor.firstValue
}
private fun createHotspotWithType(@DeviceType type: Int): HotspotNetworkEntry {
@@ -1325,10 +1308,9 @@ class WifiRepositoryImplTest() : SysuiTestCase() {
}
private fun getScanResultsCallback(): WifiManager.ScanResultsCallback {
- testScope.runCurrent()
val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>()
verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture())
- return callbackCaptor.value!!
+ return callbackCaptor.firstValue
}
private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
index 9a862fc6a18f..c5eed7365d92 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
@@ -24,11 +24,19 @@ import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.plugins.statusbar.statusBarStateController
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
+import com.android.systemui.statusbar.phone.keyguardBypassController
import com.android.systemui.statusbar.policy.HeadsUpManagerTestUtil.createFullScreenIntentEntry
+import com.android.systemui.testKosmos
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.kotlin.JavaAdapter
import com.android.systemui.util.settings.FakeGlobalSettings
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -48,6 +56,7 @@ import org.mockito.junit.MockitoRule
@RunWith(AndroidJUnit4::class)
@EnableFlags(NotificationThrottleHun.FLAG_NAME)
class AvalancheControllerTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
// For creating mocks
@get:Rule var rule: MockitoRule = MockitoJUnit.rule()
@@ -61,7 +70,6 @@ class AvalancheControllerTest : SysuiTestCase() {
@Mock private val mAccessibilityMgr: AccessibilityManagerWrapper? = null
private val mUiEventLoggerFake = UiEventLoggerFake()
@Mock private lateinit var mHeadsUpManagerLogger: HeadsUpManagerLogger
-
@Mock private lateinit var mBgHandler: Handler
private val mLogger = Mockito.spy(HeadsUpManagerLogger(logcatLogBuffer()))
@@ -76,26 +84,33 @@ class AvalancheControllerTest : SysuiTestCase() {
Mockito.`when`(
mAccessibilityMgr!!.getRecommendedTimeoutMillis(
ArgumentMatchers.anyInt(),
- ArgumentMatchers.anyInt()
+ ArgumentMatchers.anyInt(),
)
)
.then { i: InvocationOnMock -> i.getArgument(0) }
// Initialize AvalancheController and TestableHeadsUpManager during setUp instead of
// declaration, where mocks are null
- mAvalancheController = AvalancheController(dumpManager, mUiEventLoggerFake,
- mHeadsUpManagerLogger, mBgHandler)
+ mAvalancheController =
+ AvalancheController(dumpManager, mUiEventLoggerFake, mHeadsUpManagerLogger, mBgHandler)
testableHeadsUpManager =
TestableHeadsUpManager(
mContext,
mLogger,
+ kosmos.statusBarStateController,
+ kosmos.keyguardBypassController,
+ GroupMembershipManagerImpl(),
+ kosmos.visualStabilityProvider,
+ kosmos.configurationController,
mExecutor,
mGlobalSettings,
mSystemClock,
mAccessibilityMgr,
mUiEventLoggerFake,
- mAvalancheController
+ JavaAdapter(kosmos.testScope),
+ kosmos.shadeInteractor,
+ mAvalancheController,
)
}
@@ -270,7 +285,6 @@ class AvalancheControllerTest : SysuiTestCase() {
assertThat(mAvalancheController.headsUpEntryShowing).isEqualTo(nextEntry)
}
-
@Test
fun testDelete_deleteSecondToLastEntry_showingEntryKeyBecomesPreviousHunKey() {
mAvalancheController.previousHunKey = ""
@@ -305,7 +319,7 @@ class AvalancheControllerTest : SysuiTestCase() {
mAvalancheController.delete(showingEntry, runnableMock!!, "testLabel")
// Next entry is shown
- assertThat(mAvalancheController.previousHunKey).isEqualTo("");
+ assertThat(mAvalancheController.previousHunKey).isEqualTo("")
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 89aa670e5f0c..0fbee6d29441 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -35,6 +35,8 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
@@ -49,15 +51,21 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.res.R;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.FakeGlobalSettings;
import com.android.systemui.util.time.FakeSystemClock;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,7 +81,10 @@ import java.util.List;
@SmallTest
@TestableLooper.RunWithLooper
@RunWith(ParameterizedAndroidJunit4.class)
+// TODO(b/378142453): Merge this with BaseHeadsUpManagerTest.
public class BaseHeadsUpManagerTest extends SysuiTestCase {
+ protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@@ -85,6 +96,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase {
private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
@Mock private Handler mBgHandler;
@Mock private DumpManager dumpManager;
+ @Mock private ShadeInteractor mShadeInteractor;
private AvalancheController mAvalancheController;
@Mock private AccessibilityManagerWrapper mAccessibilityMgr;
@@ -108,8 +120,22 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase {
}
private BaseHeadsUpManager createHeadsUpManager() {
- return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings,
- mSystemClock, mAccessibilityMgr, mUiEventLoggerFake, mAvalancheController);
+ return new TestableHeadsUpManager(
+ mContext,
+ mLogger,
+ mKosmos.getStatusBarStateController(),
+ mKosmos.getKeyguardBypassController(),
+ new GroupMembershipManagerImpl(),
+ mKosmos.getVisualStabilityProvider(),
+ mKosmos.getConfigurationController(),
+ mExecutor,
+ mGlobalSettings,
+ mSystemClock,
+ mAccessibilityMgr,
+ mUiEventLoggerFake,
+ new JavaAdapter(mKosmos.getTestScope()),
+ mShadeInteractor,
+ mAvalancheController);
}
private NotificationEntry createStickyEntry(int id) {
@@ -152,6 +178,8 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase {
super.SysuiSetup();
mAvalancheController = new AvalancheController(dumpManager, mUiEventLoggerFake, mLogger,
mBgHandler);
+ when(mShadeInteractor.isAnyExpanded()).thenReturn(MutableStateFlow(true));
+ when(mKosmos.getKeyguardBypassController().getBypassEnabled()).thenReturn(false);
}
@Test
@@ -293,51 +321,11 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase {
BaseHeadsUpManager.HeadsUpEntry.class);
headsUpEntry.mEntry = notifEntry;
- hum.onEntryRemoved(headsUpEntry);
+ hum.onEntryRemoved(headsUpEntry, "test");
verify(mLogger, times(1)).logNotificationActuallyRemoved(eq(notifEntry));
}
- @Test
- public void testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() {
- final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry notifEntry =
- HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext);
-
- // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
- hum.showNotification(notifEntry);
-
- final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
- notifEntry.getKey());
- headsUpEntry.mWasUnpinned = false;
-
- assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry));
- }
-
- @Test
- public void testShouldHeadsUpBecomePinned_wasUnpinned_false() {
- final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry notifEntry =
- HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext);
-
- // Add notifEntry to ANM mAlertEntries map and make it unpinned
- hum.showNotification(notifEntry);
-
- final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
- notifEntry.getKey());
- headsUpEntry.mWasUnpinned = true;
-
- assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry));
- }
-
- @Test
- public void testShouldHeadsUpBecomePinned_noFSI_false() {
- final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
-
- assertFalse(hum.shouldHeadsUpBecomePinned(entry));
- }
-
@Test
public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
index c2460f93b862..c2460f93b862 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
index 1915e8ede7e7..6175e05923a7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
@@ -15,7 +15,6 @@
*/
package com.android.systemui.statusbar.policy
-import android.content.Context
import android.os.Handler
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
@@ -26,27 +25,19 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.FakeStatusBarStateController
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.testKosmos
-import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.mockExecutorHandler
import com.android.systemui.util.kotlin.JavaAdapter
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.settings.GlobalSettings
-import com.android.systemui.util.time.SystemClock
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -78,7 +69,7 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
@Mock private lateinit var mVSProvider: VisualStabilityProvider
- @Mock private lateinit var mStatusBarStateController: StatusBarStateController
+ val statusBarStateController = FakeStatusBarStateController()
@Mock private lateinit var mBypassController: KeyguardBypassController
@@ -91,67 +82,21 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
private val mJavaAdapter: JavaAdapter = JavaAdapter(testScope.backgroundScope)
@Mock private lateinit var mShadeInteractor: ShadeInteractor
-
@Mock private lateinit var dumpManager: DumpManager
private lateinit var mAvalancheController: AvalancheController
@Mock private lateinit var mBgHandler: Handler
- private class TestableHeadsUpManagerPhone(
- context: Context,
- headsUpManagerLogger: HeadsUpManagerLogger,
- groupManager: GroupMembershipManager,
- visualStabilityProvider: VisualStabilityProvider,
- statusBarStateController: StatusBarStateController,
- keyguardBypassController: KeyguardBypassController,
- configurationController: ConfigurationController,
- globalSettings: GlobalSettings,
- systemClock: SystemClock,
- executor: DelayableExecutor,
- accessibilityManagerWrapper: AccessibilityManagerWrapper,
- uiEventLogger: UiEventLogger,
- javaAdapter: JavaAdapter,
- shadeInteractor: ShadeInteractor,
- avalancheController: AvalancheController
- ) :
- HeadsUpManagerPhone(
- context,
- headsUpManagerLogger,
- statusBarStateController,
- keyguardBypassController,
- groupManager,
- visualStabilityProvider,
- configurationController,
- mockExecutorHandler(executor),
- globalSettings,
- systemClock,
- executor,
- accessibilityManagerWrapper,
- uiEventLogger,
- javaAdapter,
- shadeInteractor,
- avalancheController
- ) {
- init {
- mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME
- mAutoDismissTime = TEST_AUTO_DISMISS_TIME
- }
-
- /** Wrapper for [BaseHeadsUpManager.shouldHeadsUpBecomePinned] for testing */
- fun shouldHeadsUpBecomePinnedWrapper(entry: NotificationEntry): Boolean {
- return shouldHeadsUpBecomePinned(entry)
- }
- }
-
- private fun createHeadsUpManagerPhone(): HeadsUpManagerPhone {
- return TestableHeadsUpManagerPhone(
+ private fun createHeadsUpManagerPhone(): BaseHeadsUpManager {
+ return BaseHeadsUpManager(
mContext,
mHeadsUpManagerLogger,
+ statusBarStateController,
+ mBypassController,
mGroupManager,
mVSProvider,
- mStatusBarStateController,
- mBypassController,
mConfigurationController,
+ mockExecutorHandler(mExecutor),
mGlobalSettings,
mSystemClock,
mExecutor,
@@ -159,20 +104,22 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
mUiEventLogger,
mJavaAdapter,
mShadeInteractor,
- mAvalancheController
+ mAvalancheController,
)
}
@Before
fun setUp() {
whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(false))
+ whenever(mShadeInteractor.isQsExpanded).thenReturn(MutableStateFlow(false))
+ whenever(mBypassController.bypassEnabled).thenReturn(false)
whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
val accessibilityMgr =
mDependency.injectMockDependency(AccessibilityManagerWrapper::class.java)
whenever(
accessibilityMgr.getRecommendedTimeoutMillis(
ArgumentMatchers.anyInt(),
- ArgumentMatchers.anyInt()
+ ArgumentMatchers.anyInt(),
)
)
.thenReturn(TEST_AUTO_DISMISS_TIME)
@@ -205,7 +152,7 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
hmp.removeNotification(
entry.key,
/* releaseImmediately= */ false,
- /* reason= */ "swipe out"
+ /* reason= */ "swipe out",
)
Assert.assertTrue(removedImmediately)
Assert.assertFalse(hmp.isHeadsUpEntry(entry.key))
@@ -245,6 +192,7 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
mSystemClock.advanceTime((TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2).toLong())
Assert.assertTrue(hmp.isHeadsUpEntry(entry.key))
}
+
@Test
@EnableFlags(NotificationThrottleHun.FLAG_NAME)
fun testShowNotification_removeWhenReorderingAllowedTrue() {
@@ -253,7 +201,26 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
hmp.showNotification(notifEntry)
- assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue();
+ assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue()
+ }
+
+ class TestAnimationStateHandler : AnimationStateHandler {
+ override fun setHeadsUpGoingAwayAnimationsAllowed(allowed: Boolean) {}
+ }
+
+ @Test
+ @EnableFlags(NotificationThrottleHun.FLAG_NAME)
+ fun testReorderingAllowed_clearsListOfEntriesToRemove() {
+ whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
+ val hmp = createHeadsUpManagerPhone()
+
+ val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ hmp.showNotification(notifEntry)
+ assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue()
+
+ hmp.setAnimationStateHandler(TestAnimationStateHandler())
+ hmp.mOnReorderingAllowedListener.onReorderingAllowed()
+ assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.isEmpty()).isTrue()
}
@Test
@@ -264,7 +231,7 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
hmp.showNotification(notifEntry)
- assertThat(notifEntry.isSeenInShade).isTrue();
+ assertThat(notifEntry.isSeenInShade).isTrue()
}
@Test
@@ -275,197 +242,136 @@ class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManager
val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
hmp.showNotification(notifEntry)
- assertThat(notifEntry.isSeenInShade).isFalse();
+ assertThat(notifEntry.isSeenInShade).isFalse()
}
@Test
+ fun testShouldHeadsUpBecomePinned_noFSI_false() =
+ testScope.runTest {
+ val hum = createHeadsUpManagerPhone()
+ statusBarStateController.setState(StatusBarState.KEYGUARD)
+
+ val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+
+ Assert.assertFalse(hum.shouldHeadsUpBecomePinned(entry))
+ }
+
+ @Test
+ fun testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() =
+ testScope.runTest {
+ val hum = createHeadsUpManagerPhone()
+ statusBarStateController.setState(StatusBarState.KEYGUARD)
+
+ val notifEntry =
+ HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext)
+
+ // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
+ hum.showNotification(notifEntry)
+
+ val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key)
+ headsUpEntry!!.mWasUnpinned = false
+
+ Assert.assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry))
+ }
+
+ @Test
+ fun testShouldHeadsUpBecomePinned_wasUnpinned_false() =
+ testScope.runTest {
+ val hum = createHeadsUpManagerPhone()
+ statusBarStateController.setState(StatusBarState.KEYGUARD)
+
+ val notifEntry =
+ HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext)
+
+ // Add notifEntry to ANM mAlertEntries map and make it unpinned
+ hum.showNotification(notifEntry)
+
+ val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key)
+ headsUpEntry!!.mWasUnpinned = true
+
+ Assert.assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry))
+ }
+
+ @Test
fun shouldHeadsUpBecomePinned_shadeNotExpanded_true() =
testScope.runTest {
// GIVEN
- val statusBarStateController = FakeStatusBarStateController()
whenever(mShadeInteractor.isAnyFullyExpanded).thenReturn(MutableStateFlow(false))
- val hmp =
- TestableHeadsUpManagerPhone(
- mContext,
- mHeadsUpManagerLogger,
- mGroupManager,
- mVSProvider,
- statusBarStateController,
- mBypassController,
- mConfigurationController,
- mGlobalSettings,
- mSystemClock,
- mExecutor,
- mAccessibilityManagerWrapper,
- mUiEventLogger,
- mJavaAdapter,
- mShadeInteractor,
- mAvalancheController
- )
+ val hmp = createHeadsUpManagerPhone()
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
statusBarStateController.setState(StatusBarState.SHADE)
runCurrent()
// THEN
- Assert.assertTrue(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+ Assert.assertTrue(hmp.shouldHeadsUpBecomePinned(entry))
}
@Test
fun shouldHeadsUpBecomePinned_shadeLocked_false() =
testScope.runTest {
// GIVEN
- val statusBarStateController = FakeStatusBarStateController()
- val hmp =
- TestableHeadsUpManagerPhone(
- mContext,
- mHeadsUpManagerLogger,
- mGroupManager,
- mVSProvider,
- statusBarStateController,
- mBypassController,
- mConfigurationController,
- mGlobalSettings,
- mSystemClock,
- mExecutor,
- mAccessibilityManagerWrapper,
- mUiEventLogger,
- mJavaAdapter,
- mShadeInteractor,
- mAvalancheController
- )
+ val hmp = createHeadsUpManagerPhone()
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
statusBarStateController.setState(StatusBarState.SHADE_LOCKED)
runCurrent()
// THEN
- Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+ Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
}
@Test
fun shouldHeadsUpBecomePinned_shadeUnknown_false() =
testScope.runTest {
// GIVEN
- val statusBarStateController = FakeStatusBarStateController()
- val hmp =
- TestableHeadsUpManagerPhone(
- mContext,
- mHeadsUpManagerLogger,
- mGroupManager,
- mVSProvider,
- statusBarStateController,
- mBypassController,
- mConfigurationController,
- mGlobalSettings,
- mSystemClock,
- mExecutor,
- mAccessibilityManagerWrapper,
- mUiEventLogger,
- mJavaAdapter,
- mShadeInteractor,
- mAvalancheController
- )
+ val hmp = createHeadsUpManagerPhone()
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
statusBarStateController.setState(1207)
runCurrent()
// THEN
- Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+ Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
}
@Test
fun shouldHeadsUpBecomePinned_keyguardWithBypassOn_true() =
testScope.runTest {
// GIVEN
- val statusBarStateController = FakeStatusBarStateController()
whenever(mBypassController.bypassEnabled).thenReturn(true)
- val hmp =
- TestableHeadsUpManagerPhone(
- mContext,
- mHeadsUpManagerLogger,
- mGroupManager,
- mVSProvider,
- statusBarStateController,
- mBypassController,
- mConfigurationController,
- mGlobalSettings,
- mSystemClock,
- mExecutor,
- mAccessibilityManagerWrapper,
- mUiEventLogger,
- mJavaAdapter,
- mShadeInteractor,
- mAvalancheController
- )
+ val hmp = createHeadsUpManagerPhone()
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
statusBarStateController.setState(StatusBarState.KEYGUARD)
runCurrent()
// THEN
- Assert.assertTrue(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+ Assert.assertTrue(hmp.shouldHeadsUpBecomePinned(entry))
}
@Test
fun shouldHeadsUpBecomePinned_keyguardWithBypassOff_false() =
testScope.runTest {
// GIVEN
- val statusBarStateController = FakeStatusBarStateController()
whenever(mBypassController.bypassEnabled).thenReturn(false)
- val hmp =
- TestableHeadsUpManagerPhone(
- mContext,
- mHeadsUpManagerLogger,
- mGroupManager,
- mVSProvider,
- statusBarStateController,
- mBypassController,
- mConfigurationController,
- mGlobalSettings,
- mSystemClock,
- mExecutor,
- mAccessibilityManagerWrapper,
- mUiEventLogger,
- mJavaAdapter,
- mShadeInteractor,
- mAvalancheController
- )
+ val hmp = createHeadsUpManagerPhone()
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
statusBarStateController.setState(StatusBarState.KEYGUARD)
runCurrent()
// THEN
- Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+ Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
}
@Test
fun shouldHeadsUpBecomePinned_shadeExpanded_false() =
testScope.runTest {
// GIVEN
- val statusBarStateController = FakeStatusBarStateController()
whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(true))
- val hmp =
- TestableHeadsUpManagerPhone(
- mContext,
- mHeadsUpManagerLogger,
- mGroupManager,
- mVSProvider,
- statusBarStateController,
- mBypassController,
- mConfigurationController,
- mGlobalSettings,
- mSystemClock,
- mExecutor,
- mAccessibilityManagerWrapper,
- mUiEventLogger,
- mJavaAdapter,
- mShadeInteractor,
- mAvalancheController
- )
+ val hmp = createHeadsUpManagerPhone()
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
statusBarStateController.setState(StatusBarState.SHADE)
runCurrent()
// THEN
- Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+ Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
}
companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
index 3f33d2f89f5e..8593f6a08b5a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
@@ -21,9 +21,9 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.view.RotationPolicy;
@@ -37,7 +37,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class RotationLockControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
index 3efabd743141..59987f413ad6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
import static org.mockito.Mockito.spy;
@@ -28,8 +27,14 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
@@ -37,16 +42,39 @@ class TestableHeadsUpManager extends BaseHeadsUpManager {
private HeadsUpEntry mLastCreatedEntry;
- TestableHeadsUpManager(Context context,
+ TestableHeadsUpManager(
+ Context context,
HeadsUpManagerLogger logger,
+ StatusBarStateController statusBarStateController,
+ KeyguardBypassController bypassController,
+ GroupMembershipManager groupMembershipManager,
+ VisualStabilityProvider visualStabilityProvider,
+ ConfigurationController configurationController,
DelayableExecutor executor,
GlobalSettings globalSettings,
SystemClock systemClock,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger,
+ JavaAdapter javaAdapter,
+ ShadeInteractor shadeInteractor,
AvalancheController avalancheController) {
- super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
- executor, accessibilityManagerWrapper, uiEventLogger, avalancheController);
+ super(
+ context,
+ logger,
+ statusBarStateController,
+ bypassController,
+ groupMembershipManager,
+ visualStabilityProvider,
+ configurationController,
+ mockExecutorHandler(executor),
+ globalSettings,
+ systemClock,
+ executor,
+ accessibilityManagerWrapper,
+ uiEventLogger,
+ javaAdapter,
+ shadeInteractor,
+ avalancheController);
mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME;
mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME;
@@ -61,11 +89,6 @@ class TestableHeadsUpManager extends BaseHeadsUpManager {
return mLastCreatedEntry;
}
- @Override
- public int getContentFlag() {
- return FLAG_CONTENT_VIEW_CONTRACTED;
- }
-
// The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
@Override
public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
index 39836e2ce32f..e686edec8514 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
@@ -18,9 +18,13 @@
package com.android.systemui.statusbar.policy.ui.dialog.viewmodel
+import android.app.AutomaticZenRule
import android.content.Intent
import android.content.applicationContext
import android.provider.Settings
+import android.service.notification.SystemZenRules
+import android.service.notification.ZenModeConfig
+import android.service.notification.ZenModeConfig.ScheduleInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.notification.modes.TestModeBuilder
@@ -35,6 +39,7 @@ import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogDelegate
import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogEventLogger
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import java.util.Calendar
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.test.runCurrent
@@ -60,6 +65,9 @@ class ModesDialogViewModelTest : SysuiTestCase() {
private lateinit var underTest: ModesDialogViewModel
+ private lateinit var timeScheduleMode: ZenMode
+ private lateinit var timeScheduleInfo: ScheduleInfo
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -71,6 +79,21 @@ class ModesDialogViewModelTest : SysuiTestCase() {
kosmos.mockModesDialogDelegate,
kosmos.mockModesDialogEventLogger,
)
+
+ timeScheduleInfo = ZenModeConfig.ScheduleInfo()
+ timeScheduleInfo.days = intArrayOf(Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY)
+ timeScheduleInfo.startHour = 11
+ timeScheduleInfo.endHour = 15
+ timeScheduleMode =
+ TestModeBuilder()
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .setType(AutomaticZenRule.TYPE_SCHEDULE_TIME)
+ .setManualInvocationAllowed(true)
+ .setConditionId(ZenModeConfig.toScheduleConditionId(timeScheduleInfo))
+ .setTriggerDescription(
+ SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, timeScheduleInfo)
+ )
+ .build()
}
@Test
@@ -325,17 +348,19 @@ class ModesDialogViewModelTest : SysuiTestCase() {
.setTriggerDescription(null)
.setEnabled(false, /* byUser= */ false)
.build(),
+ timeScheduleMode,
)
)
runCurrent()
- assertThat(tiles!!).hasSize(6)
+ assertThat(tiles!!).hasSize(7)
assertThat(tiles!![0].subtext).isEqualTo("When the going gets tough")
assertThat(tiles!![1].subtext).isEqualTo("On • When in Rome")
assertThat(tiles!![2].subtext).isEqualTo("Not set")
assertThat(tiles!![3].subtext).isEqualTo("Off")
assertThat(tiles!![4].subtext).isEqualTo("On")
assertThat(tiles!![5].subtext).isEqualTo("Not set")
+ assertThat(tiles!![6].subtext).isEqualTo(timeScheduleMode.triggerDescription)
}
@Test
@@ -381,11 +406,12 @@ class ModesDialogViewModelTest : SysuiTestCase() {
.setTriggerDescription(null)
.setEnabled(false, /* byUser= */ false)
.build(),
+ timeScheduleMode,
)
)
runCurrent()
- assertThat(tiles!!).hasSize(6)
+ assertThat(tiles!!).hasSize(7)
with(tiles?.elementAt(0)!!) {
assertThat(this.stateDescription).isEqualTo("Off")
assertThat(this.subtextDescription).isEqualTo("When the going gets tough")
@@ -410,6 +436,12 @@ class ModesDialogViewModelTest : SysuiTestCase() {
assertThat(this.stateDescription).isEqualTo("Off")
assertThat(this.subtextDescription).isEqualTo("Not set")
}
+ with(tiles?.elementAt(6)!!) {
+ assertThat(this.stateDescription).isEqualTo("Off")
+ assertThat(this.subtextDescription)
+ .isEqualTo(SystemZenRules.getDaysOfWeekFull(context, timeScheduleInfo)
+ + ", " + SystemZenRules.getTimeSummary(context, timeScheduleInfo))
+ }
// All tiles have the same long click info
tiles!!.forEach { assertThat(it.onLongClickLabel).isEqualTo("Open settings") }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
new file mode 100644
index 000000000000..7a9d0179b239
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 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.statusbar.window
+
+import android.platform.test.annotations.EnableFlags
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val fakeDisplayRepository = kosmos.displayRepository
+ private val testScope = kosmos.testScope
+
+ private val underTest by lazy { kosmos.multiDisplayStatusBarWindowControllerStore }
+
+ @Before
+ fun start() {
+ underTest.start()
+ }
+
+ @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
+
+ @Test
+ fun beforeDisplayRemoved_doesNotStopInstances() =
+ testScope.runTest {
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+ verify(instance, never()).stop()
+ }
+
+ @Test
+ fun displayRemoved_stopsInstance() =
+ testScope.runTest {
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+ fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+
+ verify(instance).stop()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt
index 6e66287c1683..61c719319de8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt
@@ -17,12 +17,17 @@ package com.android.systemui.statusbar.window
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
+import android.view.fakeWindowManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.fragments.fragmentService
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.policy.statusBarConfigurationController
import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
@@ -37,6 +42,9 @@ class StatusBarWindowControllerImplTest : SysuiTestCase() {
testKosmos().also { it.statusBarWindowViewInflater = it.fakeStatusBarWindowViewInflater }
private val underTest = kosmos.statusBarWindowControllerImpl
+ private val fakeExecutor = kosmos.fakeExecutor
+ private val fakeWindowManager = kosmos.fakeWindowManager
+ private val mockFragmentService = kosmos.fragmentService
private val fakeStatusBarWindowViewInflater = kosmos.fakeStatusBarWindowViewInflater
private val statusBarConfigurationController = kosmos.statusBarConfigurationController
@@ -59,4 +67,64 @@ class StatusBarWindowControllerImplTest : SysuiTestCase() {
verify(mockWindowView, never()).setStatusBarConfigurationController(any())
}
+
+ @Test
+ @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarConnectedDisplays.FLAG_NAME)
+ fun stop_statusBarModernizationFlagEnabled_doesNotRemoveFragment() {
+ val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+ underTest.stop()
+ fakeExecutor.runAllReady()
+
+ verify(mockFragmentService, never()).removeAndDestroy(windowView)
+ }
+
+ @Test
+ @DisableFlags(StatusBarRootModernization.FLAG_NAME)
+ @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+ fun stop_statusBarModernizationFlagDisabled_removesFragment() {
+ val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+ underTest.stop()
+ fakeExecutor.runAllReady()
+
+ verify(mockFragmentService).removeAndDestroy(windowView)
+ }
+
+ @Test
+ @DisableFlags(StatusBarRootModernization.FLAG_NAME)
+ @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+ fun stop_statusBarModernizationFlagDisabled_removesFragmentOnExecutor() {
+ val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+ underTest.stop()
+
+ verify(mockFragmentService, never()).removeAndDestroy(windowView)
+ fakeExecutor.runAllReady()
+ verify(mockFragmentService).removeAndDestroy(windowView)
+ }
+
+ @Test
+ @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+ fun stop_removesWindowViewFromWindowManager() {
+ underTest.attach()
+ underTest.stop()
+
+ assertThat(fakeWindowManager.addedViews).isEmpty()
+ }
+
+ @Test(expected = IllegalStateException::class)
+ @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+ fun stop_connectedDisplaysFlagDisabled_crashes() {
+ underTest.stop()
+ }
+
+ @Test
+ fun attach_windowViewAddedToWindowManager() {
+ val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+ underTest.attach()
+
+ assertThat(fakeWindowManager.addedViews.keys).containsExactly(windowView)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
index 9592b280be34..798380a92002 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
@@ -18,8 +18,8 @@ package com.android.systemui.stylus
import android.hardware.BatteryState
import android.hardware.input.InputManager
-import android.testing.AndroidTestingRunner
import android.view.InputDevice
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
@@ -35,7 +35,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class StylusUsiPowerStartableTest : SysuiTestCase() {
@Mock lateinit var inputManager: InputManager
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index 20b273ae7f4e..d5651ec8ce6c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -22,21 +22,25 @@ import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
import android.os.UserManager
+import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.GuestResetOrExitSessionReceiver
import com.android.systemui.GuestResumeSessionReceiver
import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.model.ShowDialogRequestModel
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.TestCoroutineScope
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,6 +52,7 @@ import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
class GuestUserInteractorTest : SysuiTestCase() {
@Mock private lateinit var manager: UserManager
@@ -64,16 +69,15 @@ class GuestUserInteractorTest : SysuiTestCase() {
private lateinit var underTest: GuestUserInteractor
- private lateinit var scope: TestCoroutineScope
- private lateinit var repository: FakeUserRepository
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val scope = kosmos.testScope
+ private val repository = FakeUserRepository()
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(manager.createGuest(any())).thenReturn(GUEST_USER_INFO)
- scope = TestCoroutineScope()
- repository = FakeUserRepository()
repository.setUserInfos(ALL_USERS)
underTest = initGuestUserInteractor(context)
@@ -83,8 +87,8 @@ class GuestUserInteractorTest : SysuiTestCase() {
GuestUserInteractor(
applicationContext = context,
applicationScope = scope,
- mainDispatcher = IMMEDIATE,
- backgroundDispatcher = IMMEDIATE,
+ mainDispatcher = kosmos.testDispatcher,
+ backgroundDispatcher = kosmos.testDispatcher,
manager = manager,
repository = repository,
deviceProvisionedController = deviceProvisionedController,
@@ -92,7 +96,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
refreshUsersScheduler =
RefreshUsersScheduler(
applicationScope = scope,
- mainDispatcher = IMMEDIATE,
+ mainDispatcher = kosmos.testDispatcher,
repository = repository,
),
uiEventLogger = uiEventLogger,
@@ -118,7 +122,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun onDeviceBootCompleted_allowedToAdd_createGuest() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
setAllowedToAdd()
underTest.onDeviceBootCompleted()
@@ -129,7 +133,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun onDeviceBootCompleted_awaitProvisioning_andCreateGuest() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
setAllowedToAdd(isAllowed = false)
underTest.onDeviceBootCompleted()
val captor =
@@ -145,7 +149,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun createAndSwitchTo() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
underTest.createAndSwitchTo(
showDialog = showDialog,
dismissDialog = dismissDialog,
@@ -160,7 +164,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun createAndSwitchTo_failsToCreate_doesNotSwitchTo() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
whenever(manager.createGuest(any())).thenReturn(null)
underTest.createAndSwitchTo(
@@ -177,7 +181,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun exit_returnsToTargetUser() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
repository.setSelectedUserInfo(GUEST_USER_INFO)
val targetUserId = NON_GUEST_USER_INFO.id
@@ -197,7 +201,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun exit_returnsToLastNonGuest() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
val expectedUserId = NON_GUEST_USER_INFO.id
whenever(manager.getUserInfo(expectedUserId)).thenReturn(NON_GUEST_USER_INFO)
repository.lastSelectedNonGuestUserId = expectedUserId
@@ -219,7 +223,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun exit_lastNonGuestWasRemoved_returnsToMainUser() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
val removedUserId = 310
val mainUserId = 10
repository.lastSelectedNonGuestUserId = removedUserId
@@ -242,7 +246,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun exit_guestWasEphemeral_itIsRemoved() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setUserInfos(listOf(NON_GUEST_USER_INFO, EPHEMERAL_GUEST_USER_INFO))
repository.setSelectedUserInfo(EPHEMERAL_GUEST_USER_INFO)
@@ -265,7 +269,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun exit_forceRemoveGuest_itIsRemoved() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(GUEST_USER_INFO)
val targetUserId = NON_GUEST_USER_INFO.id
@@ -287,7 +291,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun exit_selectedDifferentFromGuestUser_doNothing() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
underTest.exit(
@@ -304,7 +308,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun exit_selectedIsActuallyNotAguestUser_doNothing() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
underTest.exit(
@@ -321,7 +325,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun remove_returnsToTargetUser() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(GUEST_USER_INFO)
@@ -342,7 +346,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun remove_selectedDifferentFromGuestUser_doNothing() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
@@ -359,7 +363,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Test
fun remove_selectedIsActuallyNotAguestUser_doNothing() =
- runBlocking(IMMEDIATE) {
+ kosmos.runTest {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
@@ -395,11 +399,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
private val NON_GUEST_USER_INFO =
- UserInfo(
- /* id= */ 818,
- /* name= */ "non_guest",
- /* flags= */ UserInfo.FLAG_FULL,
- )
+ UserInfo(/* id= */ 818, /* name= */ "non_guest", /* flags= */ UserInfo.FLAG_FULL)
private val GUEST_USER_INFO =
UserInfo(
/* id= */ 669,
@@ -416,10 +416,6 @@ class GuestUserInteractorTest : SysuiTestCase() {
/* flags= */ UserInfo.FLAG_EPHEMERAL or UserInfo.FLAG_FULL,
UserManager.USER_TYPE_FULL_GUEST,
)
- private val ALL_USERS =
- listOf(
- NON_GUEST_USER_INFO,
- GUEST_USER_INFO,
- )
+ private val ALL_USERS = listOf(NON_GUEST_USER_INFO, GUEST_USER_INFO)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/TestableAlertDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/TestableAlertDialogTest.kt
index 01dd60ae2200..4351d28ecf45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/TestableAlertDialogTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/TestableAlertDialogTest.kt
@@ -21,8 +21,8 @@ import android.content.DialogInterface
import android.content.DialogInterface.BUTTON_NEGATIVE
import android.content.DialogInterface.BUTTON_NEUTRAL
import android.content.DialogInterface.BUTTON_POSITIVE
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -36,7 +36,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class TestableAlertDialogTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
index 2e6d0fc847bb..e25bf13c41f2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
@@ -27,7 +27,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -57,7 +57,7 @@ class SettingsProxyTest : SysuiTestCase() {
@Before
fun setUp() {
testScope = TestScope(testDispatcher)
- mSettings = FakeSettingsProxy(testDispatcher)
+ mSettings = FakeSettingsProxy(testScope)
mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
}
@@ -92,7 +92,7 @@ class SettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserverSync(
TEST_SETTING,
notifyForDescendants = true,
- mContentObserver
+ mContentObserver,
)
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -104,7 +104,7 @@ class SettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserver(
TEST_SETTING,
notifyForDescendants = true,
- mContentObserver
+ mContentObserver,
)
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -116,7 +116,7 @@ class SettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserverAsync(
TEST_SETTING,
notifyForDescendants = true,
- mContentObserver
+ mContentObserver,
)
testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
@@ -154,7 +154,7 @@ class SettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserverSync(
TEST_SETTING_URI,
notifyForDescendants = true,
- mContentObserver
+ mContentObserver,
)
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -166,7 +166,7 @@ class SettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserver(
TEST_SETTING_URI,
notifyForDescendants = true,
- mContentObserver
+ mContentObserver,
)
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -178,7 +178,7 @@ class SettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserverAsync(
TEST_SETTING_URI,
notifyForDescendants = true,
- mContentObserver
+ mContentObserver,
)
testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
@@ -202,7 +202,7 @@ class SettingsProxyTest : SysuiTestCase() {
TEST_SETTING_URI,
false,
mContentObserver,
- it
+ it,
)
}
}
@@ -382,15 +382,15 @@ class SettingsProxyTest : SysuiTestCase() {
assertThat(mSettings.getFloat(TEST_SETTING, 2.5F)).isEqualTo(2.5F)
}
- private class FakeSettingsProxy(val testDispatcher: CoroutineDispatcher) : SettingsProxy {
+ private class FakeSettingsProxy(val testScope: CoroutineScope) : SettingsProxy {
private val mContentResolver = mock(ContentResolver::class.java)
private val settingToValueMap: MutableMap<String, String?> = mutableMapOf()
override fun getContentResolver() = mContentResolver
- override val backgroundDispatcher: CoroutineDispatcher
- get() = testDispatcher
+ override val settingsScope: CoroutineScope
+ get() = testScope
override fun getUriFor(name: String) =
Uri.parse(StringBuilder().append("content://settings/").append(name).toString())
@@ -408,7 +408,7 @@ class SettingsProxyTest : SysuiTestCase() {
name: String,
value: String?,
tag: String?,
- makeDefault: Boolean
+ makeDefault: Boolean,
): Boolean {
settingToValueMap[name] = value
return true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
index 00b8cd04bdaf..5787f7dfc61f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
@@ -28,7 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -36,7 +36,6 @@ import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@@ -51,14 +50,9 @@ class UserSettingsProxyTest : SysuiTestCase() {
private var userId = MAIN_USER_ID
private val testDispatcher = StandardTestDispatcher()
- private var mSettings: UserSettingsProxy = FakeUserSettingsProxy({ userId }, testDispatcher)
+ private val testScope = TestScope(testDispatcher)
+ private var mSettings: UserSettingsProxy = FakeUserSettingsProxy({ userId }, testScope)
private var mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
- private lateinit var testScope: TestScope
-
- @Before
- fun setUp() {
- testScope = TestScope(testDispatcher)
- }
@Test
fun registerContentObserverForUser_inputString_success() =
@@ -69,7 +63,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -82,7 +76,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -96,7 +90,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -107,14 +101,14 @@ class UserSettingsProxyTest : SysuiTestCase() {
TEST_SETTING,
notifyForDescendants = true,
mContentObserver,
- userId
+ userId,
)
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
eq(true),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -125,16 +119,14 @@ class UserSettingsProxyTest : SysuiTestCase() {
TEST_SETTING,
notifyForDescendants = true,
mContentObserver,
- userId
+ userId,
)
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
- eq(
- true,
- ),
+ eq(true),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -145,7 +137,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
TEST_SETTING,
notifyForDescendants = true,
mContentObserver,
- userId
+ userId,
)
testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
@@ -153,7 +145,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(true),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -166,7 +158,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -179,7 +171,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -189,7 +181,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserverForUserAsync(
TEST_SETTING_URI,
mContentObserver,
- userId
+ userId,
)
testScope.advanceUntilIdle()
@@ -198,7 +190,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -213,7 +205,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
TEST_SETTING_URI,
mContentObserver,
userId,
- runnable
+ runnable,
)
testScope.advanceUntilIdle()
assertThat(callbackCalled).isTrue()
@@ -226,14 +218,14 @@ class UserSettingsProxyTest : SysuiTestCase() {
TEST_SETTING_URI,
notifyForDescendants = true,
mContentObserver,
- userId
+ userId,
)
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
eq(true),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -244,14 +236,14 @@ class UserSettingsProxyTest : SysuiTestCase() {
TEST_SETTING_URI,
notifyForDescendants = true,
mContentObserver,
- userId
+ userId,
)
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
eq(true),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -262,7 +254,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
TEST_SETTING_URI,
notifyForDescendants = true,
mContentObserver,
- userId
+ userId,
)
testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
@@ -270,7 +262,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(true),
eq(mContentObserver),
- eq(MAIN_USER_ID)
+ eq(MAIN_USER_ID),
)
}
@@ -283,7 +275,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(0)
+ eq(0),
)
}
@@ -296,7 +288,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(0)
+ eq(0),
)
}
@@ -309,7 +301,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(0)
+ eq(0),
)
}
}
@@ -320,14 +312,14 @@ class UserSettingsProxyTest : SysuiTestCase() {
mSettings.registerContentObserverSync(
TEST_SETTING_URI,
notifyForDescendants = true,
- mContentObserver
+ mContentObserver,
)
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
eq(true),
eq(mContentObserver),
- eq(0)
+ eq(0),
)
}
@@ -340,7 +332,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(0)
+ eq(0),
)
}
@@ -354,7 +346,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(TEST_SETTING_URI),
eq(false),
eq(mContentObserver),
- eq(0)
+ eq(0),
)
}
}
@@ -557,7 +549,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
*/
private class FakeUserSettingsProxy(
override val currentUserProvider: SettingsProxy.CurrentUserIdProvider,
- val testDispatcher: CoroutineDispatcher
+ val testScope: CoroutineScope,
) : UserSettingsProxy {
private val mContentResolver = mock(ContentResolver::class.java)
@@ -569,8 +561,8 @@ class UserSettingsProxyTest : SysuiTestCase() {
override fun getUriFor(name: String) =
Uri.parse(StringBuilder().append(URI_PREFIX).append(name).toString())
- override val backgroundDispatcher: CoroutineDispatcher
- get() = testDispatcher
+ override val settingsScope: CoroutineScope
+ get() = testScope
override fun getStringForUser(name: String, userHandle: Int) =
userIdToSettingsValueMap[userHandle]?.get(name) ?: ""
@@ -578,7 +570,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
override fun putString(
name: String,
value: String?,
- overrideableByRestore: Boolean
+ overrideableByRestore: Boolean,
): Boolean {
userIdToSettingsValueMap[DEFAULT_USER_ID]?.put(name, value)
return true
@@ -588,7 +580,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
name: String,
value: String?,
tag: String?,
- makeDefault: Boolean
+ makeDefault: Boolean,
): Boolean {
putStringForUser(name, value, DEFAULT_USER_ID)
return true
@@ -605,7 +597,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
tag: String?,
makeDefault: Boolean,
userHandle: Int,
- overrideableByRestore: Boolean
+ overrideableByRestore: Boolean,
): Boolean {
userIdToSettingsValueMap[userHandle]?.set(name, value)
return true
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
index 1ff9548486ab..c6bfb351b57d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
@@ -21,9 +21,9 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.animation.Animator;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -36,7 +36,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class KeepAwakeAnimationListenerTest extends SysuiTestCase {
@Mock WakeLock mWakeLock;
KeepAwakeAnimationListener mKeepAwakeAnimationListener;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 191486786329..75f3386ed695 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -39,14 +40,13 @@ import android.media.IAudioService;
import android.media.session.MediaSession;
import android.os.Handler;
import android.os.Process;
-import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
import android.view.accessibility.AccessibilityManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.settingslib.flags.Flags;
+import com.android.keyguard.TestScopeProvider;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCaseExtKt;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -64,6 +64,10 @@ import com.android.systemui.util.concurrency.ThreadFactory;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.domain.interactor.AudioSharingInteractor;
+import com.android.systemui.volume.domain.interactor.FakeAudioSharingInteractor;
+import com.android.systemui.volume.shared.VolumeLogger;
+
+import kotlinx.coroutines.test.TestScope;
import org.junit.Before;
import org.junit.Test;
@@ -94,6 +98,9 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
private RingerModeLiveData mRingerModeInternalLiveData;
private final FakeThreadFactory mThreadFactory = new FakeThreadFactory(
new FakeExecutor(new FakeSystemClock()));
+ private final TestScope mTestScope = TestScopeProvider.getTestScope();
+ private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope);
+ private FakeAudioSharingInteractor mFakeAudioSharingInteractor;
@Mock
private AudioManager mAudioManager;
@Mock
@@ -117,9 +124,7 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
@Mock
private DumpManager mDumpManager;
@Mock
- private AudioSharingInteractor mAudioSharingInteractor;
- @Mock
- private JavaAdapter mJavaAdapter;
+ private VolumeLogger mVolumeLogger;
@Before
@@ -136,6 +141,8 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
mCallback = mock(VolumeDialogControllerImpl.C.class);
mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
+ mFakeAudioSharingInteractor = spy(new FakeAudioSharingInteractor());
+ mFakeAudioSharingInteractor.setAudioSharingVolumeBarAvailable(true);
mVolumeController =
new TestableVolumeDialogControllerImpl(
mContext,
@@ -155,8 +162,9 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
mUserTracker,
mDumpManager,
mCallback,
- mAudioSharingInteractor,
- mJavaAdapter);
+ mFakeAudioSharingInteractor,
+ mJavaAdapter,
+ mVolumeLogger);
mVolumeController.setEnableDialogs(true, true);
}
@@ -305,13 +313,13 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX)
public void testSetStreamVolume_setSecondaryDeviceVolume() {
mVolumeController.setStreamVolume(
VolumeDialogControllerImpl.DYNAMIC_STREAM_BROADCAST, /* level= */ 100);
Objects.requireNonNull(TestableLooper.get(this)).processAllMessages();
+ mTestScope.getTestScheduler().advanceUntilIdle();
- verify(mAudioSharingInteractor).setStreamVolume(100);
+ verify(mFakeAudioSharingInteractor).setStreamVolume(100);
}
static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
@@ -336,7 +344,8 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
DumpManager dumpManager,
C callback,
AudioSharingInteractor audioSharingInteractor,
- JavaAdapter javaAdapter) {
+ JavaAdapter javaAdapter,
+ VolumeLogger volumeLogger) {
super(
context,
broadcastDispatcher,
@@ -355,7 +364,8 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
userTracker,
dumpManager,
audioSharingInteractor,
- javaAdapter);
+ javaAdapter,
+ volumeLogger);
mCallbacks = callback;
ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
index 76b7b8f946b4..a9c352df9a26 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
@@ -49,9 +49,10 @@ import com.android.systemui.testKosmos
import com.android.systemui.util.RingerModeLiveData
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.FakeThreadFactory
+import com.android.systemui.util.kotlin.JavaAdapter
import com.android.systemui.util.time.fakeSystemClock
import com.android.systemui.volume.data.repository.audioRepository
-import com.android.systemui.volume.domain.interactor.audioSharingInteractor
+import com.android.systemui.volume.domain.interactor.FakeAudioSharingInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -76,6 +77,9 @@ class VolumeDialogControllerImplTestKt : SysuiTestCase() {
private val kosmos: Kosmos = testKosmos()
private val audioManager: AudioManager = mock {}
private val callbacks: VolumeDialogController.Callbacks = mock {}
+ private val javaAdapter: JavaAdapter = JavaAdapter(kosmos.testScope)
+ private val fakeAudioSharingInteractor: FakeAudioSharingInteractor =
+ FakeAudioSharingInteractor()
private lateinit var threadFactory: FakeThreadFactory
private lateinit var underTest: VolumeDialogControllerImpl
@@ -87,6 +91,8 @@ class VolumeDialogControllerImplTestKt : SysuiTestCase() {
threadFactory =
FakeThreadFactory(FakeExecutor(fakeSystemClock)).apply { setLooper(looper) }
broadcastDispatcherContext = testableContext
+ fakeAudioSharingInteractor.setAudioSharingVolumeBarAvailable(true)
+
underTest =
VolumeDialogControllerImpl(
applicationContext,
@@ -108,7 +114,8 @@ class VolumeDialogControllerImplTestKt : SysuiTestCase() {
activityManager,
mock { on { userContext }.thenReturn(applicationContext) },
dumpManager,
- audioSharingInteractor,
+ fakeAudioSharingInteractor,
+ javaAdapter,
mock {},
)
.apply {
@@ -129,6 +136,7 @@ class VolumeDialogControllerImplTestKt : SysuiTestCase() {
},
)
testableLooper.processAllMessages()
+ testScheduler.advanceUntilIdle()
verify(callbacks) { 1 * { onStateChanged(any()) } }
}
@@ -163,6 +171,7 @@ class VolumeDialogControllerImplTestKt : SysuiTestCase() {
emitVolumeChange(AudioManager.STREAM_SYSTEM, AudioManager.FLAG_SHOW_UI)
runCurrent()
TestableLooper.get(this@VolumeDialogControllerImplTestKt).processAllMessages()
+ testScheduler.advanceUntilIdle()
verify(callbacks) { 1 * { onShowRequested(any(), any(), any()) } }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorTest.kt
new file mode 100644
index 000000000000..799ca4a49038
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.domain.interactor
+
+import android.app.ActivityManager
+import android.testing.TestableLooper
+import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.fakeVolumeDialogController
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.Events
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+
+private val volumeDialogTimeout = 3.seconds
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class VolumeDialogSliderInputEventsInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private lateinit var underTest: VolumeDialogSliderInputEventsInteractor
+
+ @Before
+ fun setup() {
+ underTest = kosmos.volumeDialogSliderInputEventsInteractor
+ }
+
+ @Test
+ fun inputEvents_resetDialogVisibilityTimeout() =
+ with(kosmos) {
+ testScope.runTest {
+ runCurrent()
+ val dialogVisibility by
+ collectLastValue(volumeDialogVisibilityInteractor.dialogVisibility)
+ fakeVolumeDialogController.onShowRequested(
+ Events.SHOW_REASON_VOLUME_CHANGED,
+ false,
+ ActivityManager.LOCK_TASK_MODE_LOCKED,
+ )
+ runCurrent()
+ advanceTimeBy(volumeDialogTimeout / 2)
+ assertThat(dialogVisibility)
+ .isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)
+
+ underTest.onTouchEvent(
+ MotionEvent.obtain(
+ /* downTime = */ 0,
+ /* eventTime = */ 0,
+ /* action = */ 0,
+ /* x = */ 0f,
+ /* y = */ 0f,
+ /* metaState = */ 0,
+ )
+ )
+ advanceTimeBy(volumeDialogTimeout / 2)
+
+ assertThat(dialogVisibility)
+ .isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
index 7c5a48728a11..3f995c69c32f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
@@ -155,6 +155,30 @@ class VolumeDialogSlidersInteractorTest : SysuiTestCase() {
}
}
+ @Test
+ fun activeStreamChanges_showBoth() {
+ with(kosmos) {
+ testScope.runTest {
+ runCurrent()
+ fakeVolumeDialogController.updateState {
+ activeStream = AudioManager.STREAM_SYSTEM
+ states.put(AudioManager.STREAM_MUSIC, buildStreamState())
+ states.put(AudioManager.STREAM_SYSTEM, buildStreamState())
+ }
+ val slidersModel by collectLastValue(underTest.sliders)
+ runCurrent()
+
+ fakeVolumeDialogController.updateState { activeStream = AudioManager.STREAM_MUSIC }
+ runCurrent()
+
+ assertThat(slidersModel!!.slider)
+ .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_MUSIC))
+ assertThat(slidersModel!!.floatingSliders)
+ .containsExactly(VolumeDialogSliderType.Stream(AudioManager.STREAM_SYSTEM))
+ }
+ }
+ }
+
private fun buildStreamState(
build: VolumeDialogController.StreamState.() -> Unit = {}
): VolumeDialogController.StreamState {
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 074277c55c88..dcb15a7cd9aa 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -103,6 +103,15 @@ public interface BcSmartspaceDataPlugin extends Plugin {
void onSmartspaceTargetsUpdated(List<? extends Parcelable> targets);
}
+ /**
+ * Sets {@link BcSmartspaceConfigPlugin}.
+ *
+ * TODO: b/259566300 - Remove once isViewPager2Enabled is fully rolled out
+ */
+ default void registerConfigProvider(BcSmartspaceConfigPlugin configProvider) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
+
/** View to which this plugin can be registered, in order to get updates. */
interface SmartspaceView {
void registerDataProvider(BcSmartspaceDataPlugin plugin);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt
new file mode 100644
index 000000000000..544b705c55c5
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.plugins.clocks
+
+import android.content.Context
+
+data class ClockPreviewConfig(
+ val previewContext: Context,
+ val isShadeLayoutWide: Boolean,
+ val isSceneContainerFlagEnabled: Boolean = false,
+)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 89da46544f1e..8ea5725b3509 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -139,7 +139,9 @@ data class ClockMessageBuffers(
/** Message buffer for large clock rendering */
val largeClockMessageBuffer: MessageBuffer,
-)
+) {
+ constructor(buffer: MessageBuffer) : this(buffer, buffer, buffer) {}
+}
data class AodClockBurnInModel(val scale: Float, val translationX: Float, val translationY: Float)
@@ -158,7 +160,10 @@ interface ClockFaceLayout {
@ProtectedReturn("return constraints;")
/** Custom constraints to apply to preview ConstraintLayout. */
- fun applyPreviewConstraints(context: Context, constraints: ConstraintSet): ConstraintSet
+ fun applyPreviewConstraints(
+ clockPreviewConfig: ClockPreviewConfig,
+ constraints: ConstraintSet,
+ ): ConstraintSet
fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel)
}
@@ -179,10 +184,10 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout {
}
override fun applyPreviewConstraints(
- context: Context,
+ clockPreviewConfig: ClockPreviewConfig,
constraints: ConstraintSet,
): ConstraintSet {
- return applyDefaultPreviewConstraints(context, constraints)
+ return applyDefaultPreviewConstraints(clockPreviewConfig, constraints)
}
override fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) {
@@ -191,10 +196,11 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout {
companion object {
fun applyDefaultPreviewConstraints(
- context: Context,
+ clockPreviewConfig: ClockPreviewConfig,
constraints: ConstraintSet,
): ConstraintSet {
constraints.apply {
+ val context = clockPreviewConfig.previewContext
val lockscreenClockViewLargeId = getId(context, "lockscreen_clock_view_large")
constrainWidth(lockscreenClockViewLargeId, WRAP_CONTENT)
constrainHeight(lockscreenClockViewLargeId, WRAP_CONTENT)
@@ -235,8 +241,10 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout {
getDimen(context, "status_view_margin_horizontal"),
)
val smallClockTopMargin =
- getDimen(context, "keyguard_clock_top_margin") +
- SystemBarUtils.getStatusBarHeight(context)
+ getSmallClockTopPadding(
+ clockPreviewConfig = clockPreviewConfig,
+ SystemBarUtils.getStatusBarHeight(context),
+ )
connect(smallClockViewId, TOP, PARENT_ID, TOP, smallClockTopMargin)
}
return constraints
@@ -251,10 +259,23 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout {
fun getDimen(context: Context, name: String): Int {
val packageName = context.packageName
- val res = context.packageManager.getResourcesForApplication(packageName)
+ val res = context.resources
val id = res.getIdentifier(name, "dimen", packageName)
return if (id == 0) 0 else res.getDimensionPixelSize(id)
}
+
+ fun getSmallClockTopPadding(
+ clockPreviewConfig: ClockPreviewConfig,
+ statusBarHeight: Int,
+ ): Int {
+ return if (clockPreviewConfig.isShadeLayoutWide) {
+ getDimen(clockPreviewConfig.previewContext, "keyguard_split_shade_top_margin") -
+ if (clockPreviewConfig.isSceneContainerFlagEnabled) statusBarHeight else 0
+ } else {
+ getDimen(clockPreviewConfig.previewContext, "keyguard_clock_top_margin") +
+ if (!clockPreviewConfig.isSceneContainerFlagEnabled) statusBarHeight else 0
+ }
+ }
}
}
diff --git a/packages/SystemUI/pods/Android.bp b/packages/SystemUI/pods/Android.bp
new file mode 100644
index 000000000000..e45f3170d9ad
--- /dev/null
+++ b/packages/SystemUI/pods/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+ // The package default_visibility specified here is inherited to subpackages that do not
+ // specify default_visibility:
+ default_visibility: ["//visibility:private"],
+}
diff --git a/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp b/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp
new file mode 100644
index 000000000000..df90be8ecb97
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2024 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.
+//
+
+soong_namespace {
+}
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+ name: "api",
+ srcs: [
+ "**/*.java",
+ "**/*.kt",
+ ],
+ libs: [
+ "jsr330",
+ ],
+ visibility: ["//frameworks/base/packages/SystemUI:__subpackages__"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java b/packages/SystemUI/pods/com/android/systemui/dagger/SysUISingleton.java
index a4b33427cbda..a4b33427cbda 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java
+++ b/packages/SystemUI/pods/com/android/systemui/dagger/SysUISingleton.java
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Application.java
index 21e53a5b51d0..21e53a5b51d0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java
+++ b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Application.java
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Background.java
index 141c9019b3e4..141c9019b3e4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java
+++ b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Background.java
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/Android.bp
new file mode 100644
index 000000000000..f04784885c10
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2024 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.
+//
+
+soong_namespace {
+}
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+ name: "impl",
+ srcs: ["*.kt"],
+ libs: [
+ "jsr330",
+ "dagger2",
+ "SystemUICommon",
+ "kotlinx_coroutines",
+ ],
+ static_libs: [
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/data:impl",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain:impl",
+ ],
+ visibility: ["//frameworks/base/packages/SystemUI"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt b/packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt
index e8639498b7c0..c20e368f1690 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.retail.dagger
+package com.android.systemui.retail
import com.android.systemui.retail.data.repository.RetailModeRepository
-import com.android.systemui.retail.data.repository.RetailModeSettingsRepository
+import com.android.systemui.retail.data.repository.impl.RetailModeSettingsRepository
import com.android.systemui.retail.domain.interactor.RetailModeInteractor
-import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl
+import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl
import dagger.Binds
import dagger.Module
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp
new file mode 100644
index 000000000000..f148a7c69ecc
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2024 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.
+//
+
+soong_namespace {
+}
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+ name: "api",
+ srcs: ["repository/*.kt"],
+ libs: [
+ "kotlinx_coroutines",
+ ],
+ visibility: [
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/dagger",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain",
+ ],
+}
+
+java_library {
+ name: "impl",
+ srcs: ["repository/impl/*.kt"],
+ libs: [
+ "jsr330",
+ "kotlinx_coroutines",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api",
+ "SystemUICommon",
+ ],
+ static_libs: [
+ "api",
+ ],
+ visibility: [
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/dagger",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain",
+ ],
+}
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt
new file mode 100644
index 000000000000..c9eac2588811
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.retail.data.repository
+
+import kotlinx.coroutines.flow.StateFlow
+
+/** Repository to track if the device is in Retail mode */
+interface RetailModeRepository {
+ /** Flow of whether the device is currently in retail mode. */
+ val retailMode: StateFlow<Boolean>
+
+ /** Last value of whether the device is in retail mode. */
+ val inRetailMode: Boolean
+ get() = retailMode.value
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt
index 09fd7df15dc2..8955263595f3 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.retail.data.repository
+package com.android.systemui.retail.data.repository.impl
import android.database.ContentObserver
import android.provider.Settings
@@ -22,6 +22,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.retail.data.repository.RetailModeRepository
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -34,16 +35,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-/** Repository to track if the device is in Retail mode */
-interface RetailModeRepository {
- /** Flow of whether the device is currently in retail mode. */
- val retailMode: StateFlow<Boolean>
-
- /** Last value of whether the device is in retail mode. */
- val inRetailMode: Boolean
- get() = retailMode.value
-}
-
/**
* Tracks [Settings.Global.DEVICE_DEMO_MODE].
*
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp
new file mode 100644
index 000000000000..787861ce5eb8
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2024 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.
+//
+
+soong_namespace {
+}
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+ name: "api",
+ srcs: ["interactor/*.kt"],
+ visibility: [
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+ ],
+}
+
+java_library {
+ name: "impl",
+ srcs: ["interactor/impl/*.kt"],
+ libs: [
+ "jsr330",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/data:api",
+ ],
+ static_libs: [
+ "api",
+ ],
+ visibility: [
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+ ],
+}
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
new file mode 100644
index 000000000000..748e34d430d8
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.retail.domain.interactor
+
+/** Interactor to determine if the device is currently in retail mode */
+interface RetailModeInteractor {
+ /** Whether the device is currently in retail mode */
+ val isInRetailMode: Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt
index eea452c78ea5..8dbe562c2ed7 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt
@@ -14,18 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.retail.domain.interactor
+package com.android.systemui.retail.domain.interactor.impl
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.retail.data.repository.RetailModeRepository
+import com.android.systemui.retail.domain.interactor.RetailModeInteractor
import javax.inject.Inject
-/** Interactor to determine if the device is currently in retail mode */
-interface RetailModeInteractor {
- /** Whether the device is currently in retail mode */
- val isInRetailMode: Boolean
-}
-
@SysUISingleton
class RetailModeInteractorImpl
@Inject
diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp b/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp
new file mode 100644
index 000000000000..1aa772961408
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2024 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.
+//
+
+soong_namespace {
+}
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+ name: "api",
+ srcs: [
+ "*.java",
+ "*.kt",
+ ],
+ libs: [
+ "//frameworks/libs/systemui:tracinglib-platform",
+ "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+ "SystemUICommon",
+ "androidx.annotation_annotation",
+ "kotlinx_coroutines_android",
+ "jsr330",
+ ],
+ kotlincflags: ["-Xjvm-default=all"],
+ visibility: ["//frameworks/base/packages/SystemUI:__subpackages__"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettings.java
index 84ab66b66a7c..84ab66b66a7c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettings.java
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 7fcabe4a4363..6b909529e33a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -23,9 +23,9 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
-import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
+import com.android.systemui.util.settings.SettingsSingleThreadBackground;
-import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
import javax.inject.Inject;
@@ -33,13 +33,13 @@ import javax.inject.Inject;
@SuppressLint("StaticSettingsProvider")
class GlobalSettingsImpl implements GlobalSettings {
private final ContentResolver mContentResolver;
- private final CoroutineDispatcher mBgDispatcher;
+ private final CoroutineScope mSettingsScope;
@Inject
GlobalSettingsImpl(ContentResolver contentResolver,
- @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
+ @SettingsSingleThreadBackground CoroutineScope settingsScope) {
mContentResolver = contentResolver;
- mBgDispatcher = bgDispatcher;
+ mSettingsScope = settingsScope;
}
@NonNull
@@ -56,8 +56,8 @@ class GlobalSettingsImpl implements GlobalSettings {
@NonNull
@Override
- public CoroutineDispatcher getBackgroundDispatcher() {
- return mBgDispatcher;
+ public CoroutineScope getSettingsScope() {
+ return mSettingsScope;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettings.java
index 6031a4e05629..6031a4e05629 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettings.java
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
index c29648186d54..ae89a5f021c2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -21,25 +21,25 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
-import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
+import com.android.systemui.util.settings.SettingsSingleThreadBackground;
-import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
import javax.inject.Inject;
class SecureSettingsImpl implements SecureSettings {
private final ContentResolver mContentResolver;
private final CurrentUserIdProvider mCurrentUserProvider;
- private final CoroutineDispatcher mBgDispatcher;
+ private final CoroutineScope mSettingsScope;
@Inject
SecureSettingsImpl(
ContentResolver contentResolver,
CurrentUserIdProvider currentUserProvider,
- @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
+ @SettingsSingleThreadBackground CoroutineScope settingsScope) {
mContentResolver = contentResolver;
mCurrentUserProvider = currentUserProvider;
- mBgDispatcher = bgDispatcher;
+ mSettingsScope = settingsScope;
}
@NonNull
@@ -62,8 +62,8 @@ class SecureSettingsImpl implements SecureSettings {
@NonNull
@Override
- public CoroutineDispatcher getBackgroundDispatcher() {
- return mBgDispatcher;
+ public CoroutineScope getSettingsScope() {
+ return mSettingsScope;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt
index 5d0b0d55e1f6..154d3cc9eda1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt
@@ -23,10 +23,12 @@ import android.provider.Settings.SettingNotFoundException
import androidx.annotation.AnyThread
import androidx.annotation.WorkerThread
import com.android.app.tracing.TraceUtils.trace
-import com.android.systemui.coroutines.newTracingContext
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.app.tracing.coroutines.nameCoroutine
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
/**
@@ -47,11 +49,14 @@ interface SettingsProxy {
/** Returns the [ContentResolver] this instance was constructed with. */
fun getContentResolver(): ContentResolver
- /**
- * Returns the background [CoroutineDispatcher] that the async APIs will use for a specific
- * implementation.
- */
- val backgroundDispatcher: CoroutineDispatcher
+ /** Returns the [CoroutineScope] that the async APIs will use. */
+ val settingsScope: CoroutineScope
+
+ @OptIn(ExperimentalStdlibApi::class)
+ fun settingsDispatcherContext(name: String): CoroutineContext {
+ return (settingsScope.coroutineContext[CoroutineDispatcher] ?: EmptyCoroutineContext) +
+ nameCoroutine(name)
+ }
/**
* Construct the content URI for a particular name/value pair, useful for monitoring changes
@@ -82,7 +87,7 @@ interface SettingsProxy {
* wish to synchronize execution.
*/
suspend fun registerContentObserver(name: String, settingsObserver: ContentObserver) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserver-A")) {
registerContentObserverSync(getUriFor(name), settingsObserver)
}
}
@@ -94,7 +99,7 @@ interface SettingsProxy {
*/
@AnyThread
fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-A")).launch {
+ settingsScope.launch("registerContentObserverAsync-A") {
registerContentObserverSync(getUriFor(name), settingsObserver)
}
@@ -111,7 +116,7 @@ interface SettingsProxy {
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-B")).launch {
+ settingsScope.launch("registerContentObserverAsync-B") {
registerContentObserverSync(getUriFor(name), settingsObserver)
registered.run()
}
@@ -134,7 +139,9 @@ interface SettingsProxy {
* wish to synchronize execution.
*/
suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) {
- withContext(backgroundDispatcher) { registerContentObserverSync(uri, settingsObserver) }
+ withContext(settingsDispatcherContext("registerContentObserver-B")) {
+ registerContentObserverSync(uri, settingsObserver)
+ }
}
/**
@@ -144,7 +151,7 @@ interface SettingsProxy {
*/
@AnyThread
fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-C")).launch {
+ settingsScope.launch("registerContentObserverAsync-C") {
registerContentObserverSync(uri, settingsObserver)
}
@@ -161,7 +168,7 @@ interface SettingsProxy {
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-D")).launch {
+ settingsScope.launch("registerContentObserverAsync-D") {
registerContentObserverSync(uri, settingsObserver)
registered.run()
}
@@ -188,9 +195,9 @@ interface SettingsProxy {
suspend fun registerContentObserver(
name: String,
notifyForDescendants: Boolean,
- settingsObserver: ContentObserver
+ settingsObserver: ContentObserver,
) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserver-C")) {
registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
}
}
@@ -206,7 +213,7 @@ interface SettingsProxy {
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-E")).launch {
+ settingsScope.launch("registerContentObserverAsync-E") {
registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
}
@@ -224,7 +231,7 @@ interface SettingsProxy {
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-F")).launch {
+ settingsScope.launch("registerContentObserverAsync-F") {
registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
registered.run()
}
@@ -239,7 +246,7 @@ interface SettingsProxy {
fun registerContentObserverSync(
uri: Uri,
notifyForDescendants: Boolean,
- settingsObserver: ContentObserver
+ settingsObserver: ContentObserver,
) {
trace({ "SP#registerObserver#[$uri]" }) {
getContentResolver()
@@ -257,9 +264,9 @@ interface SettingsProxy {
suspend fun registerContentObserver(
uri: Uri,
notifyForDescendants: Boolean,
- settingsObserver: ContentObserver
+ settingsObserver: ContentObserver,
) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserver-D")) {
registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
}
}
@@ -275,7 +282,7 @@ interface SettingsProxy {
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-G")).launch {
+ settingsScope.launch("registerContentObserverAsync-G") {
registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
}
@@ -293,7 +300,7 @@ interface SettingsProxy {
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-H")).launch {
+ settingsScope.launch("registerContentObserverAsync-H") {
registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
registered.run()
}
@@ -319,7 +326,9 @@ interface SettingsProxy {
* async block if they wish to synchronize execution.
*/
suspend fun unregisterContentObserver(settingsObserver: ContentObserver) {
- withContext(backgroundDispatcher) { unregisterContentObserverSync(settingsObserver) }
+ withContext(settingsDispatcherContext("unregisterContentObserver")) {
+ unregisterContentObserverSync(settingsObserver)
+ }
}
/**
@@ -330,7 +339,7 @@ interface SettingsProxy {
*/
@AnyThread
fun unregisterContentObserverAsync(settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-I")).launch {
+ settingsScope.launch("unregisterContentObserverAsync") {
unregisterContentObserver(settingsObserver)
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxyExt.kt
index 364681444c1b..364681444c1b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxyExt.kt
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java
index e13981dfe5c7..5632a36a2942 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.util.kotlin;
+package com.android.systemui.util.settings;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettings.java
index c67c60375b2c..c67c60375b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettings.java
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
index e670b2c2edd0..65d1c276cbfa 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -21,24 +21,24 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
-import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
+import com.android.systemui.util.settings.SettingsSingleThreadBackground;
-import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
import javax.inject.Inject;
class SystemSettingsImpl implements SystemSettings {
private final ContentResolver mContentResolver;
private final CurrentUserIdProvider mCurrentUserProvider;
- private final CoroutineDispatcher mBgCoroutineDispatcher;
+ private final CoroutineScope mSettingsScope;
@Inject
SystemSettingsImpl(ContentResolver contentResolver,
CurrentUserIdProvider currentUserProvider,
- @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
+ @SettingsSingleThreadBackground CoroutineScope settingsScope) {
mContentResolver = contentResolver;
mCurrentUserProvider = currentUserProvider;
- mBgCoroutineDispatcher = bgDispatcher;
+ mSettingsScope = settingsScope;
}
@NonNull
@@ -61,8 +61,8 @@ class SystemSettingsImpl implements SystemSettings {
@NonNull
@Override
- public CoroutineDispatcher getBackgroundDispatcher() {
- return mBgCoroutineDispatcher;
+ public CoroutineScope getSettingsScope() {
+ return mSettingsScope;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt
index 4b03df6b0070..1a5517059ca4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -23,13 +23,11 @@ import android.net.Uri
import android.os.UserHandle
import android.provider.Settings.SettingNotFoundException
import com.android.app.tracing.TraceUtils.trace
-import com.android.systemui.coroutines.newTracingContext
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow
import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow
import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrUseDefault
-import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
/**
@@ -73,13 +71,13 @@ interface UserSettingsProxy : SettingsProxy {
}
override suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserver-A")) {
registerContentObserverForUserSync(uri, settingsObserver, userId)
}
}
override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-A")).launch {
+ settingsScope.launch("registerContentObserverAsync-A") {
registerContentObserverForUserSync(uri, settingsObserver, userId)
}
@@ -96,9 +94,9 @@ interface UserSettingsProxy : SettingsProxy {
override suspend fun registerContentObserver(
uri: Uri,
notifyForDescendants: Boolean,
- settingsObserver: ContentObserver
+ settingsObserver: ContentObserver,
) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserver-B")) {
registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
}
}
@@ -113,7 +111,7 @@ interface UserSettingsProxy : SettingsProxy {
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-B")).launch {
+ settingsScope.launch("registerContentObserverAsync-B") {
registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
}
@@ -126,7 +124,7 @@ interface UserSettingsProxy : SettingsProxy {
fun registerContentObserverForUserSync(
name: String,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
}
@@ -141,9 +139,9 @@ interface UserSettingsProxy : SettingsProxy {
suspend fun registerContentObserverForUser(
name: String,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserverForUser-A")) {
registerContentObserverForUserSync(name, settingsObserver, userHandle)
}
}
@@ -158,7 +156,7 @@ interface UserSettingsProxy : SettingsProxy {
settingsObserver: ContentObserver,
userHandle: Int,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-C")).launch {
+ settingsScope.launch("registerContentObserverForUserAsync-A") {
registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
}
@@ -167,7 +165,7 @@ interface UserSettingsProxy : SettingsProxy {
fun registerContentObserverForUserSync(
uri: Uri,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
registerContentObserverForUserSync(uri, false, settingsObserver, userHandle)
}
@@ -182,9 +180,9 @@ interface UserSettingsProxy : SettingsProxy {
suspend fun registerContentObserverForUser(
uri: Uri,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserverForUser-B")) {
registerContentObserverForUserSync(uri, settingsObserver, userHandle)
}
}
@@ -199,7 +197,7 @@ interface UserSettingsProxy : SettingsProxy {
settingsObserver: ContentObserver,
userHandle: Int,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-D")).launch {
+ settingsScope.launch("registerContentObserverForUserAsync-B") {
registerContentObserverForUserSync(uri, settingsObserver, userHandle)
}
@@ -216,7 +214,7 @@ interface UserSettingsProxy : SettingsProxy {
userHandle: Int,
@WorkerThread registered: Runnable,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-E")).launch {
+ settingsScope.launch("registerContentObserverForUserAsync-C") {
registerContentObserverForUserSync(uri, settingsObserver, userHandle)
registered.run()
}
@@ -231,13 +229,13 @@ interface UserSettingsProxy : SettingsProxy {
name: String,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
registerContentObserverForUserSync(
getUriFor(name),
notifyForDescendants,
settingsObserver,
- userHandle
+ userHandle,
)
}
@@ -252,14 +250,14 @@ interface UserSettingsProxy : SettingsProxy {
name: String,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserverForUser-C")) {
registerContentObserverForUserSync(
name,
notifyForDescendants,
settingsObserver,
- userHandle
+ userHandle,
)
}
}
@@ -275,7 +273,7 @@ interface UserSettingsProxy : SettingsProxy {
settingsObserver: ContentObserver,
userHandle: Int,
) {
- CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-F")).launch {
+ settingsScope.launch("registerContentObserverForUserAsync-D") {
registerContentObserverForUserSync(
getUriFor(name),
notifyForDescendants,
@@ -291,7 +289,7 @@ interface UserSettingsProxy : SettingsProxy {
uri: Uri,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
trace({ "USP#registerObserver#[$uri]" }) {
getContentResolver()
@@ -299,7 +297,7 @@ interface UserSettingsProxy : SettingsProxy {
uri,
notifyForDescendants,
settingsObserver,
- getRealUserHandle(userHandle)
+ getRealUserHandle(userHandle),
)
Unit
}
@@ -316,14 +314,14 @@ interface UserSettingsProxy : SettingsProxy {
uri: Uri,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
- withContext(backgroundDispatcher) {
+ withContext(settingsDispatcherContext("registerContentObserverForUser-D")) {
registerContentObserverForUserSync(
uri,
notifyForDescendants,
settingsObserver,
- getRealUserHandle(userHandle)
+ getRealUserHandle(userHandle),
)
}
}
@@ -339,7 +337,7 @@ interface UserSettingsProxy : SettingsProxy {
settingsObserver: ContentObserver,
userHandle: Int,
) =
- CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-G")).launch {
+ settingsScope.launch("registerContentObserverForUserAsync-E") {
registerContentObserverForUserSync(
uri,
notifyForDescendants,
@@ -385,7 +383,7 @@ interface UserSettingsProxy : SettingsProxy {
tag: String?,
makeDefault: Boolean,
@UserIdInt userHandle: Int,
- overrideableByRestore: Boolean
+ overrideableByRestore: Boolean,
): Boolean
override fun getInt(name: String, default: Int): Int {
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index d069c0181218..fe9036bb2252 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -65,7 +65,7 @@
<string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"‏يجب إدخال رقم PIN لأنّك أجريت محاولات كثيرة جدًا."</string>
<string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"يجب إدخال كلمة المرور لأنك أجريت محاولات كثيرة جدًا."</string>
<string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"يجب رسم النقش لأنّك أجريت محاولات كثيرة جدًا."</string>
- <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"‏افتح برقم PIN أو البصمة."</string>
+ <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"افتح الجهاز برقم التعريف الشخصي أو البصمة."</string>
<string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"افتح القفل بكلمة مرور أو ببصمة إصبع."</string>
<string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"افتح بالنقش أو بصمة الإصبع"</string>
<string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"لمزيد من الأمان، تم قفل الجهاز وفقًا لسياسة العمل."</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 5ae41fedac49..e7116d63d5fc 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -65,7 +65,7 @@
<string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Se requiere PIN luego de demasiados intentos"</string>
<string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Se requiere contraseña luego de demasiados intentos"</string>
<string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Se requiere patrón luego de demasiados intentos"</string>
- <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbloq. PIN/huella"</string>
+ <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbloquear con PIN o huella dactilar"</string>
<string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Desbloq. contraseña/huella"</string>
<string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desbloq. patrón/huella"</string>
<string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Dispositivo bloqueado con la política del trabajo"</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 83a607b14a19..41c3e06bd062 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -42,7 +42,7 @@
<string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIMa PUKaren bidez desblokeatu behar da."</string>
<string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIMa desblokeatzen…"</string>
<string name="keyguard_accessibility_pin_area" msgid="7403009340414014734">"PIN kodearen eremua"</string>
- <string name="keyguard_accessibility_password" msgid="3524161948484801450">"Gailuko pasahitza"</string>
+ <string name="keyguard_accessibility_password" msgid="3524161948484801450">"Gailuaren pasahitza"</string>
<string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"SIM txartelaren PIN kodearen eremua"</string>
<string name="keyguard_accessibility_sim_puk_area" msgid="5537294043180237374">"SIM txartelaren PUK kodearen eremua"</string>
<string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Ezabatu"</string>
diff --git a/packages/SystemUI/res-product/values-or/strings.xml b/packages/SystemUI/res-product/values-or/strings.xml
index 4a6696869bd6..fd4d47b6bfbf 100644
--- a/packages/SystemUI/res-product/values-or/strings.xml
+++ b/packages/SystemUI/res-product/values-or/strings.xml
@@ -32,7 +32,7 @@
<string name="kg_failed_attempts_now_wiping" product="default" msgid="6381835450014881813">"ଆପଣ ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଫୋନ୍‌ଟି ରିସେଟ୍ କରିଦିଆଯିବ, ଫଳରେ ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
<string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="7325071812832605911">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଭୁଲ ପ୍ରୟାସ ପରେ, ଏହି ୟୁଜର ପ୍ରୋଫାଇଲ୍କୁ କାଢ଼ି ଦିଆଯିବ, ଯାହା ଫଳରେ ସମସ୍ତ ୟୁଜର ଡାଟା ଡିଲିଟ ହୋଇଯିବ।"</string>
<string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="8110939900089863103">"ଆପଣ ଫୋନକୁ ଅନଲକ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଭୁଲ ପ୍ରୟାସ ପରେ, ଏହି ୟୁଜର ପ୍ରୋଫାଇଲକୁ କାଢ଼ି ଦିଆଯିବ, ଯାହା ଫଳରେ ସମସ୍ତ ୟୁଜର ଡାଟା ଡିଲିଟ ହୋଇଯିବ।"</string>
- <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="8509811676952707883">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ୟୁଜରଙ୍କୁ ବାହାର କରିଦିଆଯିବ, ଯାହାଦ୍ୱାରା ସମସ୍ତ ଉପଯୋଗକର୍ତ୍ତା ଡାଟା ଡିଲିଟ ହୋଇଯିବ।"</string>
+ <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="8509811676952707883">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ୟୁଜରଙ୍କୁ କାଢ଼ି ଦିଆଯିବ, ଯାହାଦ୍ୱାରା ସମସ୍ତ ୟୁଜର ଡାଟା ଡିଲିଟ ହୋଇଯିବ।"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3051962486994265014">"ଆପଣ ଫୋନକୁ ଅନଲକ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ୟୁଜରଙ୍କୁ ବାହାର କରିଦିଆଯିବ, ଯାହା ଦ୍ୱାରା ସମସ୍ତ ୟୁଜର ଡାଟା ଡିଲିଟ ହେବ।"</string>
<string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"ଆପଣ ଟାବ୍‌ଲେଟ୍‌କୁ ଅନ୍‌ଲକ୍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ୱାର୍କ ପ୍ରୋଫାଇଲ୍‌କୁ ବାହାର କରିଦିଆଯିବ, ଯାହା ଫଳରେ ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"ଆପଣ ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ୱାର୍କ ପ୍ରୋଫାଇଲ୍‌କୁ ବାହାର କରିଦିଆଯିବ, ଯାହା ଫଳରେ ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
diff --git a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml
index c83b6d38a0e1..dfefb9d166af 100644
--- a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml
+++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:paddingMode="stack">
<item>
@@ -30,8 +31,8 @@
android:end="20dp"
android:gravity="end|center_vertical">
<vector
- android:width="@dimen/hearing_devices_preset_spinner_arrow_size"
- android:height="@dimen/hearing_devices_preset_spinner_arrow_size"
+ android:width="@dimen/hearing_devices_preset_spinner_icon_size"
+ android:height="@dimen/hearing_devices_preset_spinner_icon_size"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?androidprv:attr/colorControlNormal">
diff --git a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_popup_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml
index f35975ee8548..f35975ee8548 100644
--- a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_popup_background.xml
+++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml
diff --git a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml
index 3c60784cf6b6..c708d2280161 100644
--- a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml
+++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml
@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
Copyright (C) 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,11 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <size
- android:width="@dimen/volume_dialog_spacing"
- android:height="@dimen/volume_dialog_spacing" />
- <solid android:color="@color/transparent" />
-</shape>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/settingslib_switch_bar_bg_on"
+ android:insetTop="8dp"
+ android:insetBottom="8dp"
+ android:insetLeft="11dp"
+ android:insetRight="11dp" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_check.xml b/packages/SystemUI/res/drawable/ic_check.xml
new file mode 100644
index 000000000000..80707d876146
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_check.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2024 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:viewportHeight="24"
+ android:viewportWidth="24">
+ <path
+ android:pathData="M0 0h24v24H0z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_widgets.xml b/packages/SystemUI/res/drawable/ic_widgets.xml
new file mode 100644
index 000000000000..9e05809bfb33
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_widgets.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2024 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:tint="?attr/colorControlNormal"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@android:color/black"
+ android:pathData="M666,520L440,294L666,68L892,294L666,520ZM120,440L120,120L440,120L440,440L120,440ZM520,840L520,520L840,520L840,840L520,840ZM120,840L120,520L440,520L440,840L120,840ZM200,360L360,360L360,200L200,200L200,360ZM667,408L780,295L667,182L554,295L667,408ZM600,760L760,760L760,600L600,600L600,760ZM200,760L360,760L360,600L200,600L200,760ZM360,360L360,360L360,360L360,360L360,360ZM554,295L554,295L554,295L554,295L554,295ZM360,600L360,600L360,600L360,600L360,600ZM600,600L600,600L600,600L600,600L600,600Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/volume_background_top.xml b/packages/SystemUI/res/drawable/volume_background_top.xml
index 75849beeb016..132572a41a36 100644
--- a/packages/SystemUI/res/drawable/volume_background_top.xml
+++ b/packages/SystemUI/res/drawable/volume_background_top.xml
@@ -17,7 +17,6 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item>
<shape>
- <size android:width="@dimen/volume_dialog_width" />
<solid android:color="?androidprv:attr/materialColorSurface" />
<corners android:topLeftRadius="@dimen/volume_dialog_background_corner_radius"
android:topRightRadius="@dimen/volume_dialog_background_corner_radius"/>
diff --git a/packages/SystemUI/res/drawable/volume_background_top_legacy.xml b/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
index 3cd87fc32061..58ae150f2539 100644
--- a/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
+++ b/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
@@ -16,7 +16,7 @@
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <item>
+ <item android:gravity="bottom|end">
<shape>
<size android:width="@dimen/volume_dialog_panel_width" />
<solid android:color="?androidprv:attr/colorSurface" />
diff --git a/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml b/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml
new file mode 100644
index 000000000000..a8d4d2ece07f
--- /dev/null
+++ b/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding"
+ android:paddingTop="@dimen/dialog_top_padding"
+ android:paddingBottom="@dimen/dialog_bottom_padding">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:cardElevation="0dp"
+ app:cardCornerRadius="28dp"
+ app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
+
+ <com.android.systemui.reardisplay.RearDisplayEducationLottieViewWrapper
+ android:id="@+id/rear_display_folded_animation"
+ android:importantForAccessibility="no"
+ android:layout_width="@dimen/rear_display_animation_width_opened"
+ android:layout_height="@dimen/rear_display_animation_height_opened"
+ android:layout_gravity="center"
+ android:contentDescription="@string/rear_display_accessibility_unfolded_animation"
+ android:scaleType="fitXY"
+ app:lottie_rawRes="@raw/rear_display_turnaround"
+ app:lottie_autoPlay="true"
+ app:lottie_repeatMode="reverse"/>
+ </androidx.cardview.widget.CardView>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rear_display_unfolded_front_screen_on"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:lineSpacingExtra="2sp"
+ android:translationY="-1.24sp"
+ android:gravity="center_horizontal" />
+
+ <!-- Buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="36dp">
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ <TextView
+ android:id="@+id/button_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:layout_gravity="start"
+ android:text="@string/cancel"
+ style="@style/Widget.Dialog.Button.BorderButton" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/bluetooth_device_item.xml b/packages/SystemUI/res/layout/bluetooth_device_item.xml
index b9314c7ae0e0..124aec6a92dd 100644
--- a/packages/SystemUI/res/layout/bluetooth_device_item.xml
+++ b/packages/SystemUI/res/layout/bluetooth_device_item.xml
@@ -27,8 +27,8 @@
<ImageView
android:id="@+id/bluetooth_device_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -36,8 +36,8 @@
<TextView
android:layout_width="0dp"
+ android:layout_height="wrap_content"
android:id="@+id/bluetooth_device_name"
- style="@style/BluetoothTileDialog.DeviceName"
android:textDirection="locale"
android:textAlignment="gravity"
android:paddingStart="20dp"
@@ -54,8 +54,8 @@
<TextView
android:layout_width="0dp"
+ android:layout_height="wrap_content"
android:id="@+id/bluetooth_device_summary"
- style="@style/BluetoothTileDialog.DeviceSummary"
android:paddingStart="20dp"
android:paddingEnd="10dp"
android:paddingBottom="15dp"
@@ -65,7 +65,8 @@
app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintBottom_toBottomOf="parent"
- android:gravity="center_vertical" />
+ android:gravity="center_vertical"
+ android:textSize="14sp" />
<androidx.constraintlayout.widget.Guideline
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index b4eaa407889a..1f937174dea3 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -32,7 +32,7 @@
android:ellipsize="end"
android:gravity="center_vertical|center_horizontal"
android:text="@string/quick_settings_bluetooth_label"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -49,7 +49,8 @@
android:gravity="center_vertical|center_horizontal"
android:maxLines="2"
android:text="@string/quick_settings_bluetooth_tile_subtitle"
- android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ android:textSize="14sp"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_title" />
@@ -105,7 +106,7 @@
android:paddingStart="36dp"
android:text="@string/turn_on_bluetooth"
android:clickable="false"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
app:layout_constraintStart_toStartOf="parent"
@@ -146,7 +147,7 @@
android:paddingEnd="15dp"
android:paddingStart="36dp"
android:clickable="false"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/bluetooth_auto_on_toggle"
app:layout_constraintStart_toStartOf="parent"
@@ -187,7 +188,8 @@
android:layout_marginTop="20dp"
android:paddingStart="36dp"
android:paddingEnd="40dp"
- android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ android:textSize="14sp"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bluetooth_auto_on_toggle_info_icon" />
@@ -204,7 +206,7 @@
android:id="@+id/see_all_button"
style="@style/BluetoothTileDialog.Device"
android:paddingEnd="0dp"
- android:paddingStart="20dp"
+ android:paddingStart="26dp"
android:background="@drawable/bluetooth_tile_dialog_bg_off"
android:layout_width="0dp"
android:layout_height="64dp"
@@ -214,11 +216,11 @@
app:layout_constraintTop_toBottomOf="@+id/device_list"
app:layout_constraintBottom_toTopOf="@+id/pair_new_device_button"
android:drawableStart="@drawable/ic_arrow_forward"
- android:drawablePadding="20dp"
+ android:drawablePadding="26dp"
android:drawableTint="?android:attr/textColorPrimary"
android:text="@string/see_all_bluetooth_devices"
android:textSize="14sp"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
android:textDirection="locale"
android:textAlignment="viewStart"
android:maxLines="1"
@@ -229,7 +231,7 @@
android:id="@+id/pair_new_device_button"
style="@style/BluetoothTileDialog.Device"
android:paddingEnd="0dp"
- android:paddingStart="20dp"
+ android:paddingStart="26dp"
android:background="@drawable/bluetooth_tile_dialog_bg_off"
android:layout_width="0dp"
android:layout_height="64dp"
@@ -238,11 +240,11 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/see_all_button"
android:drawableStart="@drawable/ic_add"
- android:drawablePadding="20dp"
+ android:drawablePadding="26dp"
android:drawableTint="?android:attr/textColorPrimary"
android:text="@string/pair_new_bluetooth_devices"
android:textSize="14sp"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
android:textDirection="locale"
android:textAlignment="viewStart"
android:maxLines="1"
@@ -259,6 +261,7 @@
<Button
android:id="@+id/audio_sharing_button"
style="@style/BluetoothTileDialog.AudioSharingButton"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
@@ -282,6 +285,7 @@
<Button
android:id="@+id/done_button"
style="@style/Widget.Dialog.Button"
+ android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
diff --git a/packages/SystemUI/res/layout/bundle_notification_info.xml b/packages/SystemUI/res/layout/bundle_notification_info.xml
new file mode 100644
index 000000000000..8700832c0eb0
--- /dev/null
+++ b/packages/SystemUI/res/layout/bundle_notification_info.xml
@@ -0,0 +1,366 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2024, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<com.android.systemui.statusbar.notification.row.BundleNotificationInfo
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/notification_guts"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clipChildren="false"
+ android:clipToPadding="true"
+ android:orientation="vertical"
+ android:paddingStart="@dimen/notification_shade_content_margin_horizontal">
+
+ <!-- Package Info -->
+ <LinearLayout
+ android:id="@+id/header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:clipChildren="false"
+ android:paddingTop="@dimen/notification_guts_header_top_padding"
+ android:clipToPadding="true">
+ <ImageView
+ android:id="@+id/pkg_icon"
+ android:layout_width="@dimen/notification_guts_conversation_icon_size"
+ android:layout_height="@dimen/notification_guts_conversation_icon_size"
+ android:layout_centerVertical="true"
+ android:layout_alignParentStart="true"
+ android:layout_marginEnd="15dp" />
+ <LinearLayout
+ android:id="@+id/names"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_guts_conversation_icon_size"
+ android:layout_centerVertical="true"
+ android:gravity="center_vertical"
+ android:layout_alignEnd="@id/pkg_icon"
+ android:layout_toEndOf="@id/pkg_icon">
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
+ <TextView
+ android:id="@+id/group_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:ellipsize="end"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
+ <TextView
+ android:id="@+id/pkg_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceApp"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:maxLines="1"/>
+ <TextView
+ android:id="@+id/delegate_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ style="@style/TextAppearance.NotificationImportanceHeader"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:text="@string/notification_delegate_header"
+ android:maxLines="1" />
+
+ </LinearLayout>
+
+ <!-- end aligned fields -->
+ <!-- Optional link to app. Only appears if the channel is not disabled and the app
+asked for it -->
+ <ImageButton
+ android:id="@+id/app_settings"
+ android:layout_width="@dimen/notification_importance_toggle_size"
+ android:layout_height="@dimen/notification_importance_toggle_size"
+ android:layout_centerVertical="true"
+ android:visibility="gone"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/notification_app_settings"
+ android:src="@drawable/ic_info"
+ android:layout_toStartOf="@id/info"
+ android:tint="?androidprv:attr/materialColorPrimary"/>
+ <ImageButton
+ android:id="@+id/info"
+ android:layout_width="@dimen/notification_importance_toggle_size"
+ android:layout_height="@dimen/notification_importance_toggle_size"
+ android:layout_centerVertical="true"
+ android:contentDescription="@string/notification_more_settings"
+ android:background="@drawable/ripple_drawable_20dp"
+ android:src="@drawable/ic_settings"
+ android:tint="?androidprv:attr/materialColorPrimary"
+ android:layout_alignParentEnd="true" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/inline_controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@dimen/notification_shade_content_margin_horizontal"
+ android:layout_marginTop="@dimen/notification_guts_option_vertical_padding"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_text"
+ android:text="@string/notification_unblockable_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
+ <!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_call_text"
+ android:text="@string/notification_unblockable_call_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
+ <!-- Non configurable multichannel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_multichannel_text"
+ android:text="@string/notification_multichannel_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
+ <LinearLayout
+ android:id="@+id/interruptiveness_settings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/automatic"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/notification_importance_button_separation"
+ android:padding="@dimen/notification_importance_button_padding"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_guts_priority_button_bg"
+ android:orientation="vertical"
+ android:visibility="gone">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center"
+ >
+ <ImageView
+ android:id="@+id/automatic_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_notifications_automatic"
+ android:background="@android:color/transparent"
+ android:tint="@color/notification_guts_priority_contents"
+ android:clickable="false"
+ android:focusable="false"/>
+ <TextView
+ android:id="@+id/automatic_label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_importance_drawable_padding"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+ android:text="@string/notification_automatic_title"/>
+ </LinearLayout>
+ <TextView
+ android:id="@+id/automatic_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"
+ android:visibility="gone"
+ android:text="@string/notification_channel_summary_automatic"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/alert"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/notification_importance_button_padding"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_guts_priority_button_bg"
+ android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center"
+ >
+ <ImageView
+ android:id="@+id/alert_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_notifications_alert"
+ android:background="@android:color/transparent"
+ android:tint="@color/notification_guts_priority_contents"
+ android:clickable="false"
+ android:focusable="false"/>
+ <TextView
+ android:id="@+id/alert_label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_importance_drawable_padding"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+ android:text="@string/notification_alert_title"/>
+ </LinearLayout>
+ <TextView
+ android:id="@+id/alert_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"
+ android:visibility="gone"
+ android:text="@string/notification_channel_summary_default"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/silence"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_importance_button_separation"
+ android:padding="@dimen/notification_importance_button_padding"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_guts_priority_button_bg"
+ android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center"
+ >
+ <ImageView
+ android:id="@+id/silence_icon"
+ android:src="@drawable/ic_notifications_silence"
+ android:background="@android:color/transparent"
+ android:tint="@color/notification_guts_priority_contents"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:focusable="false"/>
+ <TextView
+ android:id="@+id/silence_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:layout_toEndOf="@id/silence_icon"
+ android:layout_marginStart="@dimen/notification_importance_drawable_padding"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+ android:text="@string/notification_silence_title"/>
+ </LinearLayout>
+ <TextView
+ android:id="@+id/silence_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"
+ android:visibility="gone"
+ android:text="@string/notification_channel_summary_low"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/notification_guts_bundle_feedback"
+ android:text="@string/notification_guts_bundle_feedback"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start|center_vertical"
+ android:minWidth="@dimen/notification_guts_bundle_feedback_size"
+ android:minHeight="@dimen/notification_guts_bundle_feedback_size"
+ android:maxWidth="200dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+
+ <RelativeLayout
+ android:id="@+id/bottom_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="60dp"
+ android:gravity="center_vertical"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
+ >
+ <TextView
+ android:id="@+id/turn_off_notifications"
+ android:text="@string/inline_turn_off_notifications"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:gravity="start|center_vertical"
+ android:minWidth="@dimen/notification_importance_toggle_size"
+ android:minHeight="@dimen/notification_importance_toggle_size"
+ android:maxWidth="200dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
+ android:id="@+id/done"
+ android:text="@string/inline_ok_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:gravity="end|center_vertical"
+ android:minWidth="@dimen/notification_importance_toggle_size"
+ android:minHeight="@dimen/notification_importance_toggle_size"
+ android:maxWidth="125dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </RelativeLayout>
+ </LinearLayout>
+</com.android.systemui.statusbar.notification.row.BundleNotificationInfo>
diff --git a/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml b/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml
index 9e84052956dc..17c2f8946a62 100644
--- a/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml
+++ b/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml
@@ -26,6 +26,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/qqs_layout_margin_top"
+ android:minHeight="@dimen/min_clickable_item_size"
+ android:minWidth="@dimen/min_clickable_item_size"
android:textAppearance="@style/TextAppearance.Dialog.Body.Message" />
<TextView
@@ -34,6 +36,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/qqs_layout_margin_top"
+ android:minHeight="@dimen/min_clickable_item_size"
+ android:minWidth="@dimen/min_clickable_item_size"
android:textAppearance="@style/TextAppearance.Dialog.Body.Message" />
<!-- Attach to Bugreport Switch -->
@@ -58,9 +62,9 @@
<Switch
android:id="@+id/attach_to_bugreport_switch"
android:layout_width="wrap_content"
- android:minHeight="@dimen/screenrecord_option_icon_size"
android:layout_height="wrap_content"
android:gravity="end"
+ style="@style/ScreenRecord.Switch"
android:layout_gravity="fill_vertical"
android:layout_weight="0" />
</LinearLayout>
@@ -87,9 +91,9 @@
<Switch
android:id="@+id/winscope_switch"
android:layout_width="wrap_content"
- android:minHeight="@dimen/screenrecord_option_icon_size"
android:layout_height="wrap_content"
android:gravity="end"
+ style="@style/ScreenRecord.Switch"
android:layout_gravity="fill_vertical"
android:layout_weight="0" />
</LinearLayout>
@@ -116,9 +120,9 @@
<Switch
android:id="@+id/trace_debuggable_apps_switch"
android:layout_width="wrap_content"
- android:minHeight="@dimen/screenrecord_option_icon_size"
android:layout_height="wrap_content"
android:gravity="end"
+ style="@style/ScreenRecord.Switch"
android:layout_gravity="fill_vertical"
android:layout_weight="0" />
</LinearLayout>
@@ -145,9 +149,9 @@
<Switch
android:id="@+id/long_traces_switch"
android:layout_width="wrap_content"
- android:minHeight="@dimen/screenrecord_option_icon_size"
android:layout_height="wrap_content"
android:gravity="end"
+ style="@style/ScreenRecord.Switch"
android:layout_gravity="fill_vertical"
android:layout_weight="0" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml b/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml
deleted file mode 100644
index d512e7c3a433..000000000000
--- a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<!--
- Copyright (C) 2024 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/hearing_devices_preset_spinner_height"
- android:paddingStart="@dimen/hearing_devices_preset_spinner_text_padding_start"
- android:paddingTop="@dimen/hearing_devices_preset_spinner_text_padding_vertical"
- android:paddingBottom="@dimen/hearing_devices_preset_spinner_text_padding_vertical"
- android:orientation="vertical">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
- android:lineSpacingExtra="6dp"
- android:text="@string/hearing_devices_preset_label"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textSize="14sp"
- android:gravity="center_vertical"
- android:textDirection="locale"
- android:layout_weight="1" />
- <TextView
- android:id="@+id/hearing_devices_preset_option_text"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:textAppearance="@style/TextAppearance.Dialog.Body"
- android:lineSpacingExtra="6dp"
- android:gravity="center_vertical"
- android:ellipsize="end"
- android:maxLines="1"
- android:textDirection="locale"
- android:layout_weight="1" />
-</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml
new file mode 100644
index 000000000000..70f2cd5fcc28
--- /dev/null
+++ b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml
@@ -0,0 +1,45 @@
+<!--
+ Copyright (C) 2024 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"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/bluetooth_dialog_device_height"
+ android:paddingStart="@dimen/hearing_devices_preset_spinner_padding"
+ android:paddingEnd="@dimen/hearing_devices_preset_spinner_padding"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/hearing_devices_spinner_check_icon"
+ android:layout_width="@dimen/hearing_devices_preset_spinner_icon_size"
+ android:layout_height="@dimen/hearing_devices_preset_spinner_icon_size"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="@dimen/hearing_devices_layout_margin"
+ android:tint="?androidprv:attr/materialColorOnPrimaryContainer"
+ android:src="@drawable/ic_check"
+ android:contentDescription="@string/hearing_devices_spinner_item_selected"/>
+ <TextView
+ android:id="@+id/hearing_devices_spinner_text"
+ style="?android:attr/spinnerDropDownItemStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textDirection="locale"
+ android:paddingStart="0dp"
+ android:maxLines="1"
+ android:ellipsize="end" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml b/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml
new file mode 100644
index 000000000000..75742440e889
--- /dev/null
+++ b/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/bluetooth_dialog_device_height"
+ android:paddingStart="@dimen/hearing_devices_preset_spinner_padding"
+ android:paddingEnd="@dimen/hearing_devices_preset_spinner_padding">
+ <TextView
+ android:id="@+id/hearing_devices_spinner_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.Dialog.Body"
+ android:layout_gravity="center_vertical"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textDirection="locale" />
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml
index 80692f9481b7..bf04a6f64d6a 100644
--- a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml
@@ -28,50 +28,16 @@
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/preset_spinner" />
-
- <Spinner
- android:id="@+id/preset_spinner"
- style="@style/BluetoothTileDialog.Device"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/hearing_devices_layout_margin"
- android:minHeight="@dimen/hearing_devices_preset_spinner_height"
- android:gravity="center_vertical"
- android:background="@drawable/hearing_devices_preset_spinner_background"
- android:popupBackground="@drawable/hearing_devices_preset_spinner_popup_background"
- android:dropDownVerticalOffset="@dimen/hearing_devices_preset_spinner_height"
- android:dropDownWidth="match_parent"
- android:paddingStart="0dp"
- android:paddingEnd="0dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/device_list"
- app:layout_constraintBottom_toTopOf="@id/pair_new_device_button"
- android:longClickable="false"
- android:visibility="gone"/>
-
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/device_function_barrier"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierAllowsGoneWidgets="false"
- app:barrierDirection="bottom"
- app:constraint_referenced_ids="device_list,preset_spinner" />
+ app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="@+id/pair_new_device_button"
style="@style/BluetoothTileDialog.Device"
- android:paddingEnd="0dp"
- android:paddingStart="20dp"
- android:background="@drawable/bluetooth_tile_dialog_bg_off"
- android:layout_width="0dp"
- android:layout_height="64dp"
- android:contentDescription="@string/accessibility_hearing_device_pair_new_device"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/device_function_barrier"
+ app:layout_constraintTop_toBottomOf="@id/device_list"
+ android:layout_height="@dimen/bluetooth_dialog_device_height"
+ android:contentDescription="@string/accessibility_hearing_device_pair_new_device"
android:drawableStart="@drawable/ic_add"
android:drawablePadding="20dp"
android:drawableTint="?android:attr/textColorPrimary"
@@ -81,26 +47,75 @@
android:textDirection="locale"
android:textAlignment="viewStart"
android:maxLines="1"
- android:ellipsize="end" />
+ android:ellipsize="end"
+ android:background="@drawable/bluetooth_tile_dialog_bg_off" />
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/device_barrier"
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:id="@+id/preset_layout"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:barrierAllowsGoneWidgets="false"
- app:barrierDirection="bottom"
- app:constraint_referenced_ids="device_function_barrier, pair_new_device_button" />
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/pair_new_device_button"
+ android:layout_marginTop="@dimen/hearing_devices_layout_margin"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/preset_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
+ android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
+ android:paddingStart="@dimen/hearing_devices_small_title_padding_horizontal"
+ android:text="@string/hearing_devices_preset_label"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textSize="14sp"
+ android:gravity="center_vertical"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textDirection="locale"/>
+ <Spinner
+ android:id="@+id/preset_spinner"
+ style="@style/BluetoothTileDialog.Device"
+ android:layout_height="@dimen/bluetooth_dialog_device_height"
+ android:layout_marginTop="4dp"
+ android:paddingStart="0dp"
+ android:paddingEnd="0dp"
+ android:background="@drawable/hearing_devices_spinner_background"
+ android:popupBackground="@drawable/hearing_devices_spinner_popup_background"
+ android:dropDownWidth="match_parent"
+ android:longClickable="false"/>
+ </LinearLayout>
<LinearLayout
- android:id="@+id/related_tools_container"
+ android:id="@+id/tools_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
- android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
- android:layout_marginTop="@dimen/hearing_devices_layout_margin"
- android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/device_barrier" />
+ app:layout_constraintTop_toBottomOf="@id/preset_layout"
+ android:layout_marginTop="@dimen/hearing_devices_layout_margin"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/tools_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
+ android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
+ android:paddingStart="@dimen/hearing_devices_small_title_padding_horizontal"
+ android:text="@string/hearing_devices_tools_label"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textSize="14sp"
+ android:gravity="center_vertical"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textDirection="locale"/>
+ <LinearLayout
+ android:id="@+id/tools_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
+ android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
+ android:layout_marginTop="4dp"
+ android:orientation="horizontal"/>
+ </LinearLayout>
+
</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_tool_item.xml b/packages/SystemUI/res/layout/hearing_tool_item.xml
index f5baf2aaf6dc..da9178b56d73 100644
--- a/packages/SystemUI/res/layout/hearing_tool_item.xml
+++ b/packages/SystemUI/res/layout/hearing_tool_item.xml
@@ -46,7 +46,7 @@
android:textAlignment="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/hearing_devices_layout_margin"
+ android:layout_marginTop="4dp"
android:ellipsize="end"
android:textSize="12sp"
android:maxLines="3"
diff --git a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
index a313833e2a66..4b2f45f87290 100644
--- a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
@@ -27,12 +27,13 @@
android:layout_height="@dimen/conversation_single_line_face_pile_size"
android:paddingHorizontal="16dp"
>
- <ImageView
+ <com.android.internal.widget.CachingIconView
android:id="@*android:id/conversation_icon"
android:layout_width="@dimen/conversation_single_line_avatar_size"
android:layout_height="@dimen/conversation_single_line_avatar_size"
android:layout_gravity="center_vertical|end"
- />
+ android:scaleType="centerCrop"
+ />
<ViewStub
android:id="@*android:id/conversation_face_pile"
diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid.xml b/packages/SystemUI/res/layout/notification_2025_hybrid.xml
new file mode 100644
index 000000000000..8c34cd4165e0
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_2025_hybrid.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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
+ -->
+
+<!-- extends LinearLayout -->
+<com.android.systemui.statusbar.notification.row.HybridNotificationView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="bottom|start"
+ android:paddingStart="@*android:dimen/notification_2025_content_margin_start"
+ android:paddingEnd="12dp">
+ <TextView
+ android:id="@+id/notification_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
+ android:paddingEnd="4dp"
+ />
+ <TextView
+ android:id="@+id/notification_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:paddingEnd="4dp"
+ style="@*android:style/Widget.DeviceDefault.Notification.Text"
+ />
+</com.android.systemui.statusbar.notification.row.HybridNotificationView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
new file mode 100644
index 000000000000..ff5d9d3567f6
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<!-- extends LinearLayout -->
+<com.android.systemui.statusbar.notification.row.HybridConversationNotificationView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical|start"
+ android:paddingStart="@*android:dimen/notification_2025_content_margin_start"
+ android:paddingEnd="12dp">
+
+ <FrameLayout
+ android:layout_width="@dimen/notification_2025_single_line_face_pile_size"
+ android:layout_height="@dimen/notification_2025_single_line_face_pile_size"
+ android:layout_marginEnd="8dp"
+ >
+ <ImageView
+ android:id="@*android:id/conversation_icon"
+ android:layout_width="@dimen/notification_2025_single_line_avatar_size"
+ android:layout_height="@dimen/notification_2025_single_line_avatar_size"
+ android:layout_gravity="center_vertical|end"
+ />
+
+ <ViewStub
+ android:id="@*android:id/conversation_face_pile"
+ android:layout="@*android:layout/conversation_face_pile_layout"
+ android:layout_width="@dimen/notification_2025_single_line_face_pile_size"
+ android:layout_height="@dimen/notification_2025_single_line_face_pile_size"
+ android:layout_gravity="center_vertical|end"
+ />
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/notification_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:paddingEnd="4dp"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
+ />
+
+ <TextView
+ android:id="@+id/conversation_notification_sender"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:paddingEnd="4dp"
+ style="@*android:style/Widget.DeviceDefault.Notification.Text"
+ />
+
+ <TextView
+ android:id="@+id/notification_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:paddingEnd="4dp"
+ style="@*android:style/Widget.DeviceDefault.Notification.Text"
+ />
+</com.android.systemui.statusbar.notification.row.HybridConversationNotificationView>
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
index d0a1ce8ae629..215e4e457060 100644
--- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
@@ -55,9 +55,14 @@
/>
<!-- Shows generic text. -->
+ <!-- Since there's so little room in the status bar chip area, don't ellipsize the text and
+ instead just fade it out a bit at the end. -->
<TextView
android:id="@+id/ongoing_activity_chip_text"
style="@style/StatusBar.Chip.Text"
+ android:ellipsize="none"
+ android:requiresFadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/ongoing_activity_chip_text_fading_edge_length"
android:visibility="gone"
/>
diff --git a/packages/SystemUI/res/layout/record_issue_dialog.xml b/packages/SystemUI/res/layout/record_issue_dialog.xml
index e30ae6e695fe..b2a8c4ce96db 100644
--- a/packages/SystemUI/res/layout/record_issue_dialog.xml
+++ b/packages/SystemUI/res/layout/record_issue_dialog.xml
@@ -38,6 +38,8 @@
android:drawableEnd="@drawable/arrow_pointing_down"
android:layout_marginTop="@dimen/qqs_layout_margin_top"
android:focusable="false"
+ android:minHeight="@dimen/min_clickable_item_size"
+ android:minWidth="@dimen/min_clickable_item_size"
android:clickable="true" />
<!-- Screen Record Switch -->
@@ -72,10 +74,10 @@
<Switch
android:id="@+id/screenrecord_switch"
android:layout_width="wrap_content"
- android:minHeight="@dimen/screenrecord_option_icon_size"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="fill_vertical"
+ style="@style/ScreenRecord.Switch"
android:layout_weight="0"
android:contentDescription="@string/quick_settings_screen_record_label" />
</LinearLayout>
@@ -112,11 +114,11 @@
<Switch
android:id="@+id/bugreport_switch"
android:layout_width="wrap_content"
- android:minHeight="@dimen/screenrecord_option_icon_size"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="fill_vertical"
android:layout_weight="0"
+ style="@style/ScreenRecord.Switch"
android:contentDescription="@string/qs_record_issue_bug_report" />
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/split_clock_view.xml b/packages/SystemUI/res/layout/split_clock_view.xml
deleted file mode 100644
index 8198f0333a94..000000000000
--- a/packages/SystemUI/res/layout/split_clock_view.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<!-- Extends LinearLayout -->
-<com.android.systemui.statusbar.policy.SplitClockView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- >
- <TextClock
- android:id="@+id/time_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
- android:textSize="@dimen/qs_time_collapsed_size"
- android:textColor="?android:attr/textColorPrimary"
- />
- <TextClock
- android:id="@+id/am_pm_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
- android:textSize="@dimen/qs_time_collapsed_size"
- android:textColor="?android:attr/textColorPrimary"
- android:importantForAccessibility="no"
- />
-
- <!-- Empty text view so we have the same height when expanded/collapsed-->
- <TextView
- android:id="@+id/empty_time_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
- android:textColor="?android:attr/textColorPrimary"
- />
-</com.android.systemui.statusbar.policy.SplitClockView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml b/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml
index 7c59aad10c91..71c77a56b6a8 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml
@@ -44,13 +44,13 @@
android:layout_height="wrap_content">
<com.android.systemui.statusbar.notification.row.FooterViewButton
- android:id="@+id/settings_button"
+ android:id="@+id/history_button"
style="@style/TextAppearance.NotificationFooterButtonRedesign"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:background="@drawable/notif_footer_btn_background"
- android:contentDescription="@string/notification_settings_button_description"
- android:drawableStart="@drawable/notif_footer_btn_settings"
+ android:contentDescription="@string/notification_history_button_description"
+ android:drawableStart="@drawable/notif_footer_btn_history"
android:focusable="true"
app:layout_constraintStart_toStartOf="parent" />
@@ -64,17 +64,17 @@
android:contentDescription="@string/accessibility_clear_all"
android:focusable="true"
android:text="@string/clear_all_notifications_text"
- app:layout_constraintEnd_toStartOf="@id/history_button"
- app:layout_constraintStart_toEndOf="@id/settings_button" />
+ app:layout_constraintEnd_toStartOf="@id/settings_button"
+ app:layout_constraintStart_toEndOf="@id/history_button" />
<com.android.systemui.statusbar.notification.row.FooterViewButton
- android:id="@+id/history_button"
+ android:id="@+id/settings_button"
style="@style/TextAppearance.NotificationFooterButtonRedesign"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:background="@drawable/notif_footer_btn_background"
- android:contentDescription="@string/notification_history_button_description"
- android:drawableStart="@drawable/notif_footer_btn_history"
+ android:contentDescription="@string/notification_settings_button_description"
+ android:drawableStart="@drawable/notif_footer_btn_settings"
android:focusable="true"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index f187ce62ddb2..b8544a64d9da 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,58 +13,70 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/volume_dialog_root"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ app:layoutDescription="@xml/volume_dialog_scene">
- <LinearLayout
- android:id="@+id/volume_dialog_container"
+ <View
+ android:id="@+id/volume_dialog_background"
+ android:layout_width="@dimen/volume_dialog_width"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/volume_dialog_background_vertical_margin"
+ android:layout_marginBottom="@dimen/volume_dialog_background_vertical_margin"
+ android:background="@drawable/volume_dialog_background"
+ app:layout_constraintBottom_toBottomOf="@id/volume_dialog_settings"
+ app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintTop_toTopOf="@id/volume_ringer_drawer" />
+
+ <include
+ android:id="@id/volume_ringer_drawer"
+ layout="@layout/volume_ringer_drawer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
- android:divider="@drawable/volume_dialog_floating_sliders_spacer"
- android:orientation="horizontal"
- android:showDividers="middle|end|beginning">
-
- <LinearLayout
- android:id="@+id/volume_dialog_floating_sliders_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:divider="@drawable/volume_dialog_floating_sliders_spacer"
- android:gravity="bottom"
- android:orientation="horizontal"
- android:paddingBottom="@dimen/volume_dialog_floating_sliders_bottom_padding"
- android:showDividers="middle" />
+ android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
+ app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="1" />
- <LinearLayout
- android:id="@+id/volume_dialog"
- android:layout_width="@dimen/volume_dialog_width"
- android:layout_height="wrap_content"
- android:background="@drawable/volume_dialog_background"
- android:clipChildren="false"
- android:clipToOutline="false"
- android:clipToPadding="false"
- android:divider="@drawable/volume_dialog_spacer"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:paddingVertical="@dimen/volume_dialog_vertical_padding"
- android:showDividers="middle">
+ <include
+ android:id="@+id/volume_dialog_main_slider_container"
+ layout="@layout/volume_dialog_slider" />
- <include layout="@layout/volume_ringer_drawer" />
+ <ImageButton
+ android:id="@+id/volume_dialog_settings"
+ android:layout_width="@dimen/volume_dialog_button_size"
+ android:layout_height="@dimen/volume_dialog_button_size"
+ android:layout_marginTop="@dimen/volume_dialog_components_spacing"
+ android:background="@drawable/ripple_drawable_20dp"
+ android:contentDescription="@string/accessibility_volume_settings"
+ android:soundEffectsEnabled="false"
+ android:src="@drawable/horizontal_ellipsis"
+ android:tint="?androidprv:attr/materialColorPrimary"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintTop_toBottomOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintVertical_bias="0" />
- <include layout="@layout/volume_dialog_slider" />
+ <LinearLayout
+ android:id="@+id/volume_dialog_floating_sliders_container"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/volume_dialog_floating_sliders_vertical_padding_negative"
+ android:layout_marginBottom="@dimen/volume_dialog_floating_sliders_vertical_padding_negative"
+ android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+ android:gravity="bottom"
+ android:orientation="horizontal"
+ android:showDividers="middle|beginning|end"
+ app:layout_constraintBottom_toBottomOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintEnd_toStartOf="@id/volume_dialog_background"
+ app:layout_constraintTop_toTopOf="@id/volume_dialog_main_slider_container" />
- <ImageButton
- android:id="@+id/volume_dialog_settings"
- android:layout_width="@dimen/volume_dialog_button_size"
- android:layout_height="@dimen/volume_dialog_button_size"
- android:background="@drawable/ripple_drawable_20dp"
- android:contentDescription="@string/accessibility_volume_settings"
- android:soundEffectsEnabled="false"
- android:src="@drawable/horizontal_ellipsis"
- android:tint="?androidprv:attr/materialColorPrimary" />
- </LinearLayout>
- </LinearLayout>
-</FrameLayout> \ No newline at end of file
+</androidx.constraintlayout.motion.widget.MotionLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_legacy.xml b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
index 9010ab764da0..d44b6a8534f2 100644
--- a/packages/SystemUI/res/layout/volume_dialog_legacy.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
@@ -93,9 +93,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/volume_background_bottom"
- android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
- android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
- android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
+ android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding">
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/settings"
android:src="@drawable/horizontal_ellipsis"
diff --git a/packages/SystemUI/res/layout/volume_ringer_button.xml b/packages/SystemUI/res/layout/volume_ringer_button.xml
index dc6780aeae60..38bb783c2920 100644
--- a/packages/SystemUI/res/layout/volume_ringer_button.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_button.xml
@@ -14,6 +14,7 @@
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
@@ -25,6 +26,7 @@
android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
android:contentDescription="@string/volume_ringer_mode"
android:gravity="center"
+ android:tint="?androidprv:attr/materialColorOnSurface"
android:src="@drawable/volume_ringer_item_bg"
android:background="@drawable/volume_ringer_item_bg"/>
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
index 7c266e60b503..d850bbe63afd 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
@@ -14,59 +14,18 @@
~ limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:id="@+id/volume_ringer_and_drawer_container"
- android:layout_width="wrap_content"
+<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/volume_ringer_drawer"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:gravity="center"
- android:paddingLeft="@dimen/volume_dialog_ringer_horizontal_padding"
- android:paddingRight="@dimen/volume_dialog_ringer_horizontal_padding"
android:layoutDirection="ltr"
- android:clipToPadding="false"
- android:clipChildren="false"
- android:background="@drawable/volume_background_top">
-
- <!-- Drawer view, invisible by default. -->
- <FrameLayout
- android:id="@+id/volume_drawer_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <!-- View that is animated to a tapped ringer selection, so it appears selected. -->
- <FrameLayout
- android:id="@+id/volume_drawer_selection_background"
- android:alpha="0.0"
- android:layout_width="@dimen/volume_dialog_ringer_drawer_button_size"
- android:layout_height="@dimen/volume_dialog_ringer_drawer_button_size"
- android:layout_gravity="bottom|right"
- android:background="@drawable/volume_drawer_selection_bg" />
-
- <LinearLayout
- android:id="@+id/volume_drawer_options"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <!-- add ringer buttons here -->
-
- </LinearLayout>
-
- </FrameLayout>
+ android:orientation="vertical"
+ app:layoutDescription="@xml/volume_dialog_ringer_drawer_motion_scene">
- <!-- The current ringer selection. When the drawer is opened, this animates to the corresponding
- position in the drawer. When the drawer is closed, it animates back. -->
- <ImageButton
- android:id="@+id/volume_new_ringer_active_button"
- android:layout_width="@dimen/volume_dialog_ringer_drawer_button_size"
- android:layout_height="@dimen/volume_dialog_ringer_drawer_button_size"
- android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
- android:background="@drawable/volume_drawer_selection_bg"
- android:contentDescription="@string/volume_ringer_change"
- android:gravity="center"
- android:padding="@dimen/volume_dialog_ringer_horizontal_padding"
- android:src="@drawable/ic_volume_media"
- android:tint="?androidprv:attr/materialColorOnPrimary" />
+ <!-- add ringer buttons here -->
-</FrameLayout> \ No newline at end of file
+</androidx.constraintlayout.motion.widget.MotionLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 048ddaf735da..ebee1576342a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Gehoortoestelle"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Skakel tans aan …"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Kan nie helderheid verstel nie omdat dit\n deur die topapp beheer word"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Outodraai"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Outodraai skerm"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ligging"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nuwe toestel saam te bind"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Kon nie voorafstelling opdateer nie"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Voorafstelling"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Gekies"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Nutsgoed"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Intydse Onderskrifte"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokkeer toestelmikrofoon?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokkeer toestelkamera?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokkeer toestelkamera en mikrofoon?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Begin nou"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Geen kennisgewings nie"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Geen nuwe kennisgewings nie"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Kennisgewingdemping is nou aan"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Jou toestelvolume en -waarskuwings word outomaties vir tot 2 minute lank verminder wanneer jy te veel kennisgewings op een slag kry."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Skakel af"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Ontsluit om ouer kennisgewings te sien"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skakel oor na app regs of onder terwyl jy verdeelde skerm gebruik"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skakel oor na app links of bo terwyl jy verdeelde skerm gebruik"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Tydens verdeelde skerm: verplaas ’n app van een skerm na ’n ander"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Skuif aktiewe venster tussen skerms"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Invoer"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Skakel oor na volgende taal"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Skakel oor na vorige taal"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gebruik minder as <xliff:g id="LENGTH">%1$d</xliff:g> karakters"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Maak gesprek oop"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Gespreklegstukke"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tik op \'n gesprek om dit by jou tuisskerm te voeg"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Keer die foon om vir hoër resolusie"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Voubare toestel word ontvou"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Voubare toestel word omgekeer"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gevou"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"oopgevou"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toeganklikheid"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Kortpadsleutels"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pasmaak kortpadsleutels"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Druk sleutel om kortpad toe te wys"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Soekkortpaaie"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Geen soekresultate nie"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikoon vir Handeling- of Meta-sleutel"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plusikoon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Pasmaak"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Klaar"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vou ikoon uit"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Sleephandvatsel"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Sleutelbordinstellings"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Stel kortpad"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Kanselleer"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Druk sleutel"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Sleutelkombinasie is reeds in gebruik. Probeer ’n ander sleutel."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeer met jou sleutelbord"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer kortpadsleutels"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeer met jou raakpaneel"</string>
diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml
index 4afae3328cf7..fbeefc83c43d 100644
--- a/packages/SystemUI/res/values-af/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Af"</item>
<item msgid="3028994095749238254">"Aan"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Onbeskikbaar"</item>
+ <item msgid="6419996398343291862">"Af"</item>
+ <item msgid="5908720590832378783">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9d03a911b9d3..0351c7508703 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ግቤት"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"መስሚያ አጋዥ መሣሪያዎች"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"በማብራት ላይ..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ከላይ ባለው መተግበሪያ ቁጥጥር ላይ ስለሆነ\n ብሩህነትን ማስተካከል አልተቻለም"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"በራስ ሰር አሽከርክር"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ማያ ገጽን በራስ-አሽከርክር"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"አካባቢ"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"አዲስ መሣሪያ ለማጣመር ጠቅ ያድርጉ"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ቅድመ-ቅምጥን ማዘመን አልተቻለም"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ቅድመ-ቅምጥ"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ተመርጧል"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"መሣሪያዎች"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"የቀጥታ መግለጫ ጽሑፍ"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"ማስታወሻ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"የመሣሪያ ማይክሮፎን እገዳ ይነሳ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"የመሣሪያ ካሜራ እገዳ ይነሳ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"የመሣሪያ ካሜራ እና ማይክሮፎን እገዳ ይነሳ?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"አሁን ጀምር"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ምንም ማሳወቂያ የለም"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"ምንም አዲስ ማሳወቂያዎች የሉም"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"የማሳወቂያ ረጋ ማለት አሁን በርቷል"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"በአንድ ጊዜ ብዙ ማሳወቂያዎችን ሲያገኙ የመሣሪያዎ ድምፅ እና ማንቂያዎች እስከ 2 ደቂቃዎች ድረስ በራስ-ሰር ይቀንሳሉ።"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"አጥፋ"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"የቆዩ ማሳወቂያዎችን ለማየት ይክፈቱ"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከታች ወዳለ መተግበሪያ ይቀይሩ"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከላይ ወዳለ መተግበሪያ ይቀይሩ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"በተከፈለ ማያ ገጽ ወቅት፡- መተግበሪያን ከአንዱ ወደ ሌላው ተካ"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"በማሳያዎች መካከል ንቁ መስኮትን ያንቀሳቅሱ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ግቤት"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ወደ ቀጣዩ ቋንቋ ቀይር"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"ወደ ቀዳሚ ቋንቋ ቀይር"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ከ<xliff:g id="LENGTH">%1$d</xliff:g> የሚያንሱ ቁምፊዎችን ይጠቀሙ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"ውይይት ይክፈቱ"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"የውይይት ምግብሮች"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"በመነሻ ማያ ገጽዎ ላይ ለማከል አንድ ውይይት መታ ያድርጉ"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ለከፍተኛ ጥራት ስልኩን ይቀይሩ"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"መታጠፍ የሚችል መሣሪያ እየተዘረጋ ነው"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"መታጠፍ የሚችል መሣሪያ እየተገለበጠ ነው"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"የታጠፈ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"የተዘረጋ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ተደራሽነት"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"የቁልፍ ሰሌዳ አቋራጮች"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"የቁልፍ ሰሌዳ አቋራጮችን ያብጁ"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"አቋራጭ ለመመደብ ቁልፍ ይጫኑ"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"የፍለጋ አቋራጮች"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ምንም የፍለጋ ውጤቶች የሉም"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"የእርምጃ ወይም ሜታ ቁልፍ አዶ"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"የመደመር አዶ"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"አብጅ"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ተከናውኗል"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"መዘርጊያ አዶ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ወይም"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"መያዣ ይጎትቱ"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"የቁልፍ ሰሌዳ ቅንብሮች"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"አቋራጭ አቀናብር"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ይቅር"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ቁልፍ ይጫኑ"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"የቁልፍ ጥምረት አስቀድሞ በሥራ ላይ ነው። ሌላ ቁልፍ ይሞክሩ።"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"የቁልፍ ሰሌዳዎን በመጠቀም ያስሱ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"የቁልፍ ሰሌዳ አቋራጮችን ይወቁ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"የመዳሰሻ ሰሌዳዎን በመጠቀም ያስሱ"</string>
diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml
index 8601132cf141..b98fe57c232e 100644
--- a/packages/SystemUI/res/values-am/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"አጥፋ"</item>
<item msgid="3028994095749238254">"አብራ"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"አይገኝም"</item>
+ <item msgid="6419996398343291862">"ጠፍቷል"</item>
+ <item msgid="5908720590832378783">"በርቷል"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 062ab78d1b31..645d88008b21 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -109,14 +109,14 @@
<string name="screenrecord_title" msgid="4257171601439507792">"مسجّل الشاشة"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
- <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"هل تريد تسجيل محتوى الشاشة؟"</string>
- <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"تسجيل محتوى تطبيق واحد"</string>
- <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"تسجيل محتوى الشاشة بالكامل"</string>
+ <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"هل تريد تسجيل الشاشة؟"</string>
+ <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"تسجيل شاشة تطبيق واحد"</string>
+ <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"تسجيل الشاشة بكاملها"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"‏تسجيل محتوى الشاشة بالكامل: %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"أثناء تسجيل محتوى الشاشة بالكامل، يتم تسجيل كل المحتوى المعروض على شاشتك. لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"أثناء تسجيل محتوى تطبيق، يتم تسجيل أي محتوى يتم عرضه أو تشغيله في ذلك التطبيق. لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
- <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"تسجيل محتوى الشاشة"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"اختيار تطبيق لتسجيل محتواه"</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"سيتم تسجيل كل المحتوى المعروض أو المشغَّل على شاشة التطبيق، لذا يُرجى توخي الحذر بشأن المعلومات الظاهرة، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور والمقاطع الصوتية والفيديوهات."</string>
+ <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"تسجيل الشاشة"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"يُرجى اختيار تطبيق لتسجيل شاشته"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"تسجيل الصوت"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"صوت الجهاز"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"الصوت من جهازك، مثلاً الموسيقى والمكالمات ونغمات الرنين"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"الإدخال"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعات الأذن الطبية"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"جارٍ التفعيل…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"لا يمكن ضبط مستوى السطوع لأنّ\n التطبيق الأول يتحكّم فيه"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"التدوير التلقائي"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"انقر لإقران جهاز جديد"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"تعذَّر تعديل الإعداد المسبق"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"الإعدادات المسبقة"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"تمّ اختياره"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"الأدوات"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"النسخ النصي التلقائي"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"ملاحظات"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"هل تريد إزالة حظر ميكروفون الجهاز؟"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"هل تريد إزالة حظر كاميرا الجهاز؟"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"هل تريد إزالة حظر الكاميرا والميكروفون؟"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"غير مفعَّل"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"لم يتم ضبط الوضع"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"الإدارة في الإعدادات"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ما مِن أوضاع مفعَّلة}=1{الوضع \"{mode}\" مفعَّل}two{وضعان مفعَّلان}few{‫# أوضاع مفعَّلة}many{‫# وضعًا مفعَّلاً}other{‫# وضع مفعَّل}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ما مِن أوضاع مفعَّلة}=1{‫\"{mode}\" مفعَّل}two{وضعان مفعَّلان}few{‫# أوضاع مفعَّلة}many{‫# وضعًا مفعَّلاً}other{‫# وضع مفعَّل}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"لن يتم إزعاجك بالأصوات والاهتزاز، باستثناء المُنبِّهات والتذكيرات والأحداث والمتصلين الذين تحددهم. وسيظل بإمكانك سماع أي عناصر أخرى تختار تشغيلها، بما في ذلك الموسيقى والفيديوهات والألعاب."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"لن يتم إزعاجك بالأصوات والاهتزاز، باستثناء المُنبِّهات. وسيظل بإمكانك سماع أي عناصر أخرى تختار تشغيلها، بما في ذلك الموسيقى والفيديوهات والألعاب."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"تخصيص"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"التبديل إلى التطبيق على اليسار أو الأسفل أثناء استخدام \"تقسيم الشاشة\""</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"التبديل إلى التطبيق على اليمين أو الأعلى أثناء استخدام \"تقسيم الشاشة\""</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"استبدال تطبيق بآخر في وضع \"تقسيم الشاشة\""</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"نقل نافذة نشطة بين شاشات العرض"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"الإدخال"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"التبديل إلى اللغة التالية"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"التبديل إلى اللغة السابقة"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"يجب استخدام أقل من <xliff:g id="LENGTH">%1$d</xliff:g> حرف."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"محادثة مفتوحة"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"التطبيقات المصغّرة للمحادثات"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"انقر على محادثة لإضافتها إلى \"الشاشة الرئيسية\""</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"للحصول على درجة دقة أعلى، اقلِب الهاتف."</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"جهاز قابل للطي يجري فتحه"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"جهاز قابل للطي يجري قلبه"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"مطوي"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"غير مطوي"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"‫%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"تسهيل الاستخدام"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"اختصارات لوحة المفاتيح"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"تخصيص اختصارات لوحة المفاتيح"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"اضغط على مفتاح لتخصيص الاختصار"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"البحث في الاختصارات"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ما مِن نتائج بحث"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"‏رمز مفتاح الإجراء (مفتاح Meta)"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"رمز علامة الجمع (+)"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"تخصيص"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"تم"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"رمز التوسيع"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"أو"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"مقبض السحب"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"إعدادات لوحة المفاتيح"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ضبط الاختصار"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"إلغاء"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"اضغط على مفتاح"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"يتم حاليًا استخدام مجموعة المفاتيح هذه. يُرجى تجربة مفتاح آخر."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"التنقّل باستخدام لوحة المفاتيح"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"تعرَّف على اختصارات لوحة المفاتيح"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"التنقّل باستخدام لوحة اللمس"</string>
@@ -1459,11 +1455,11 @@
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"عرض التطبيقات المستخدَمة مؤخرًا"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"مرِّر سريعًا للأعلى مع الاستمرار باستخدام 3 أصابع على لوحة اللمس"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"أحسنت."</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"لقد أكملْت الدليل التوجيهي على إيماءة \"عرض التطبيقات المستخدَمة مؤخرًا\"."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"لقد أكملْت التدريب على إيماءة عرض التطبيقات المستخدَمة مؤخرًا."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"عرض جميع التطبيقات"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اضغط على مفتاح الإجراء في لوحة المفاتيح"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"أحسنت!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"لقد أكملْت الدليل التوجيهي عن إيماءة \"عرض جميع التطبيقات\""</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"لقد أكملْت التدريب على إيماءة عرض جميع التطبيقات"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"الإضاءة الخلفية للوحة المفاتيح"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"‏مستوى الإضاءة: %1$d من %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"إدارة المنزل آليًّا"</string>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index f985e2f001c6..0be4367ae144 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"غير مفعَّلة"</item>
<item msgid="3028994095749238254">"مفعَّلة"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"غير متوفِّرة"</item>
+ <item msgid="6419996398343291862">"متوقّفة"</item>
+ <item msgid="5908720590832378783">"مفعّلة"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 7b3f0bbbc93c..e14f4ccdece6 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"শ্ৰৱণ যন্ত্ৰ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"অন কৰি থকা হৈছে…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"উজ্জ্বলতা মিলাব নোৱাৰি কাৰণ সেয়া\n শীৰ্ষৰ এপটোৱে নিয়ন্ত্ৰণ কৰি আছে"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"স্বয়ং-ঘূৰ্ণন"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"অৱস্থান"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইচ পেয়াৰ কৰিবলৈ ক্লিক কৰক"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"প্ৰিছেট আপডে’ট কৰিব পৰা নগ’ল"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"প্ৰিছেট"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"বাছনি কৰা হৈছে"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"সঁজুলি"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"লাইভ কেপশ্বন"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"টোকা"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইচৰ মাইক্ৰ\'ফ\'ন অৱৰোধৰ পৰা আঁতৰাবনে?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ডিভাইচৰ কেমেৰা অৱৰোধৰ পৰা আঁতৰাবনে?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ডিভাইচৰ কেমেৰা আৰু মাইক্ৰ\'ফ\'ন অৱৰোধৰ পৰা আঁতৰাবনে?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"এতিয়াই আৰম্ভ কৰক"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"কোনো জাননী নাই"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"কোনো নতুন জাননী নাই"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"জাননী কুলডাউন কৰা সুবিধাটো এতিয়া অন কৰা হৈছে"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"আপুনি একেলগে বহুতো জাননী পালে আপোনাৰ ডিভাইচটোৰ ভলিউম আৰু সতৰ্কবাৰ্তা স্বয়ংক্ৰিয়ভাৱে ২ মিনিটলৈকে কমোৱা হয়।"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"অফ কৰক"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"পুৰণি জাননী চবলৈ আনলক কৰক"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত সোঁফালে অথবা তলত থকা এপলৈ সলনি কৰক"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত বাওঁফালে অথবা ওপৰত থকা এপলৈ সলনি কৰক"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"বিভাজিত স্ক্ৰীনৰ ব্যৱহাৰ কৰাৰ সময়ত: কোনো এপ্ এখন স্ক্ৰীনৰ পৰা আনখনলৈ নিয়ক"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ডিছপ্লে’সমূহৰ মাজত সক্রিয় হৈ থকা ৱিণ্ড’ সলনা সলনিকৈ ব্যৱহাৰ কৰক"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ইনপুট"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"পৰৱৰ্তী ভাষাটোলৈ সলনি কৰক"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"পূৰ্বৰ ভাষালৈ সলনি কৰক"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> টাতকৈ কম বৰ্ণ ব্যৱহাৰ কৰক"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"বাৰ্তালাপ খোলক"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"বাৰ্তালাপ ৱিজেট"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"আপোনাৰ গৃহ স্ক্ৰীনত কোনো বাৰ্তালাপ যোগ দিবলৈ সেইটোত টিপক"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"অধিক ৰিজ’লিউশ্বনৰ বাবে, ফ’নটো লুটিয়াই দিয়ক"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফ’ল্ড কৰা"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"আনফ’ল্ড কৰা"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"সাধ্য সুবিধা"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"কীব’ৰ্ডৰ শ্বৰ্টকাট"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"কীব’ৰ্ডৰ শ্বৰ্টকাট কাষ্টমাইজ কৰক"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"শ্বৰ্টকাটৰ ভূমিকা অৰ্পণ কৰিবলৈ কী টিপক"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সন্ধানৰ শ্বৰ্টকাট"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"সন্ধানৰ কোনো ফলাফল নাই"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"কাৰ্য বা মেটা কীৰ চিহ্ন"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"যোগ চিনৰ চিহ্ন"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"কাষ্টমাইজ কৰক"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"হ’ল"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"বিস্তাৰ কৰাৰ চিহ্ন"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ড্ৰেগ হেণ্ডেল"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"কীব’ৰ্ডৰ ছেটিং"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"শ্বৰ্টকাট ছেট কৰক"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"বাতিল কৰক"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"কী টিপক"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"কীৰ মিশ্ৰণ ইতিমধ্যে ব্যৱহাৰ হৈ আছে। অন্য এটা কী ব্যৱহাৰ কৰি চাওক।"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"কীব’ৰ্ড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীব’ৰ্ডৰ শ্বৰ্টকাটসমূহৰ বিষয়ে জানক"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপোনাৰ টাচ্চপেড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string>
diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml
index 3ec2f5c67557..da237e51101e 100644
--- a/packages/SystemUI/res/values-as/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"অফ আছে"</item>
<item msgid="3028994095749238254">"অন আছে"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"উপলব্ধ নহয়"</item>
+ <item msgid="6419996398343291862">"অফ আছে"</item>
+ <item msgid="5908720590832378783">"অন আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 1c84a590d6b9..90168703b896 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eşitmə aparatları"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiv edilir..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Yuxarıdakı tətbiq tərəfindən idarə olunduğu üçün\n parlaqlığı tənzimləmək mümkün deyil"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Məkan"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz birləşdirmək üçün klikləyin"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Hazır ayar güncəllənmədi"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Hazır Ayar"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seçilib"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alətlər"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Canlı Altyazı"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Qeyd"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonu blokdan çıxarılsın?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerası blokdan çıxarılsın?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası və mikrofonu blokdan çıxarılsın?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"İndi başlayın"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Heç bir bildiriş yoxdur"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Yeni bildiriş yoxdur"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Bildiriş gözləmə müddəti artıq aktivdir"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Eyni anda çox bildiriş aldıqda cihazın səs və xəbərdarlıqları avtomatik 2 dəqiqəyə qədər azalır."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Deaktiv edin"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Köhnə bildirişləri görmək üçün kilidi açın"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran istifadə edərkən sağda və ya aşağıda tətbiqə keçin"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran istifadə edərkən solda və ya yuxarıda tətbiqə keçin"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Bölünmüş ekran rejimində: tətbiqi birindən digərinə dəyişin"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Aktiv pəncərəni displeylər arasında hərəkət etdirin"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Daxiletmə"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Növbəti dilə keçin"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Əvvəlki dilə keçin"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Maksimum <xliff:g id="LENGTH">%1$d</xliff:g> simvol istifadə edin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Söhbət vidcetləri"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Əsas ekranınıza əlavə etmək üçün söhbətə toxunun"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Daha yüksək ayırdetmə dəqiqliyi üçün telefonu çevirin"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Qatlana bilən cihaz açılır"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Qatlana bilən cihaz fırladılır"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"qatlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"açıq"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Xüsusi imkanlar"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klaviatura qısayolları"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klaviatura qısayollarını fərdiləşdirin"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Qısayol təyin etmək üçün düyməni basın"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Axtarış qısayolları"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Axtarış nəticəsi yoxdur"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Əməliyyat və ya Meta düyməsi ikonası"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Üstəgəl ikonası"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Fərdiləşdirin"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Hazırdır"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"İkonanı genişləndirin"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"və ya"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Dəstəyi çəkin"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatura ayarları"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Qısayol ayarlayın"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Ləğv edin"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Düyməni basın"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Düymə kombinasiyası artıq istifadə olunur. Başqa düyməni sınayın."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviaturadan istifadə edərək hərəkət edin"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klaviatura qısayolları haqqında öyrənin"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Taçpeddən istifadə edərək hərəkət edin"</string>
diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml
index 4eea105107c1..0203fb08ba6a 100644
--- a/packages/SystemUI/res/values-az/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Deaktiv"</item>
<item msgid="3028994095749238254">"Aktiv"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Əlçatan deyil"</item>
+ <item msgid="6419996398343291862">"Deaktiv"</item>
+ <item msgid="5908720590832378783">"Aktiv"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f260f5369f7c..d2636c050db0 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključuje se..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Ne možete da prilagodite osvetljenost jer je\n kontroliše aplikacija u vrhu"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatska rotacija"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili nov uređaj"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje zadatih podešavanja nije uspelo"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Unapred određena podešavanja"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Izabrano"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alatke"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Titl uživo"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Beleška"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite da odblokirate mikrofon uređaja?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite da odblokirate kameru uređaja?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite da odblokirate kameru i mikrofon uređaja?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pređi u aplikaciju zdesna ili ispod dok je podeljen ekran"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju sleva ili iznad dok koristite podeljeni ekran"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"U režimu podeljenog ekrana: zamena jedne aplikacije drugom"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Premesti aktivan prozor na sledeći ekran"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Unos"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Pređi na sledeći jezik"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Pređi na prethodni jezik"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Koristite manji broj znakova od <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Vidžeti za konverzaciju"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Dodirnite konverzaciju da biste je dodali na početni ekran"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za veću rezoluciju obrnite telefon"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Uređaj na preklop se otvara"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Uređaj na preklop se obrće"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tasterske prečice"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite tasterske prečice"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite taster da biste dodelili prečicu"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pretražite prečice"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretrage"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona tastera za radnju ili meta tastera"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona znaka plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Prilagodi"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Gotovo"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Marker za prevlačenje"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Podešavanja tastature"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Podesi prečicu"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite taster"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacija tastera se već koristi. Probajte sa drugim tasterom."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tasterskim prečicama"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću tačpeda"</string>
@@ -1450,7 +1446,7 @@
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prevucite ulevo ili udesno sa tri prsta na tačpedu"</string>
- <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Svaka čast!"</string>
+ <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Super!"</string>
<string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Dovršili ste pokret za povratak."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Idi na početni ekran"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prevucite nagore sa tri prsta na tačpedu"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
index 3f8841afb4f2..2401e4a2fc37 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Isključeno"</item>
<item msgid="3028994095749238254">"Uključeno"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nedostupno"</item>
+ <item msgid="6419996398343291862">"Isključeno"</item>
+ <item msgid="5908720590832378783">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a303c11ef0fc..388950cb7bdd 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Увод"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слыхавыя апараты"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Уключэнне…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Не ўдаецца адрэгуляваць яркасць, бо яна\nкантралюецца асноўнай праграмай"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аўтапаварот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аўтаматычны паварот экрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Месцазнаходжанне"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Націсніце, каб спалучыць новую прыладу"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Не ўдалося абнавіць набор налад"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Набор налад"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Выбрана"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Інструменты"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Аўтаматычныя субцітры"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Нататка"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблакіраваць мікрафон прылады?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблакіраваць камеру прылады?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблакіраваць камеру і мікрафон прылады?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пераключыцца на праграму справа або ўнізе на падзеленым экране"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пераключыцца на праграму злева або ўверсе на падзеленым экране"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"У рэжыме падзеленага экрана замяніць адну праграму на іншую"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Перамясціць актыўнае акно паміж дысплэямі"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Увод"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Пераключыцца на наступную мову"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Пераключыцца на папярэднюю мову"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Колькасць сімвалаў павінна быць меншай за <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Адкрытая размова"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Віджэты размовы"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Націсніце на размову, каб дадаць яе на галоўны экран"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Каб зрабіць фота з больш высокай раздзяляльнасцю, павярніце тэлефон"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складная прылада ў раскладзеным выглядзе"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перавернутая складная прылада"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складзена"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"раскладзена"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Спецыяльныя магчымасці"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Спалучэнні клавіш"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Наладзіць спалучэнні клавіш"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Націсніце клавішу, каб прызначыць спалучэнне клавіш"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук спалучэнняў клавіш"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Няма вынікаў пошуку"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Значок клавішы дзеяння (мета-клавішы)"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Значок плюса"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Наладзіць"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Гатова"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Разгарнуць\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер перацягвання"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Налады клавіятуры"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Наладзіць спалучэнне клавіш"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Скасаваць"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Націсніце клавішу"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Гэта спалучэнне клавіш ужо выкарыстоўваецца. Паспрабуйце іншую клавішу."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігацыя з дапамогай клавіятуры"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Азнаёмцеся са спалучэннямі клавіш"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігацыя з дапамогай сэнсарнай панэлі"</string>
diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml
index 85602864dc76..2dc705772c6c 100644
--- a/packages/SystemUI/res/values-be/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Выключана"</item>
<item msgid="3028994095749238254">"Уключана"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Недаступна"</item>
+ <item msgid="6419996398343291862">"Выключана"</item>
+ <item msgid="5908720590832378783">"Уключана"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a127515e8f19..2d68f9190a30 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Вход"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухови апарати"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включва се..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Яркостта не може да се коригира, защото се контролира\n от приложението на екрана"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авт. ориентация"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично завъртане на екрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за сдвояване на ново устройство"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Предварително зададените настройки не бяха актуализирани"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Предварително зададено"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Избрано"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Инструменти"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Надписи на живо"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Бележка"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се отблокира ли микрофонът на устройството?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се отблокира ли камерата на устройството?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се отблокират ли камерата и микрофонът на устройството?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Превключване към приложението вдясно/отдолу в режима на разделен екран"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Превключване към приложението вляво/отгоре в режима на разделен екран"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"При разделен екран: замяна на дадено приложение с друго"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Преместване на активния прозорец между екраните"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Въвеждане"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Превключване към следващия език"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Превключване към предишния език"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Използвайте по-малко от <xliff:g id="LENGTH">%1$d</xliff:g> знака"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Отворен разговор"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Приспособления за разговор"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Докоснете разговор, за да го добавите към началния си екран"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"За по-висока разделителна способност обърнете телефона"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Разгъване на сгъваемо устройство"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Обръщане на сгъваемо устройство"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Достъпност"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Клавишни комбинации"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Персонализиране на клавишните комбинации"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Натиснете клавиш, за да зададете клавишна комбинация"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Търсете клавишни комбинации"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Няма резултати от търсенето"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за свиване"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Икона на клавиша за действия или клавиша Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Икона на плюс"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Персонализиране"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Готово"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за разгъване"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Манипулатор за преместване с плъзгане"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Настройки на клавиатурата"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Задаване на клавишна комбинация"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Отказ"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Натиснете клавиш"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Клавишната комбинация вече се използва. Опитайте с друг клавиш."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигирайте посредством клавиатурата си"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете за клавишните комбинации"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигирайте посредством сензорния панел"</string>
@@ -1449,7 +1445,7 @@
<string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Преглед на скорошните приложения"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
- <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Прекарайте три пръста наляво или надясно по сензорния панел"</string>
+ <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Плъзнете три пръста наляво или надясно по сензорния панел"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Чудесно!"</string>
<string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Изпълнихте жеста за връщане назад."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Към началния екран"</string>
@@ -1457,7 +1453,7 @@
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Отлично!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Изпълнихте жеста за преминаване към началния екран"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Преглед на скорошните приложения"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Прекарайте три пръста нагоре по сензорния панел и задръжте"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Плъзнете три пръста нагоре по сензорния панел и задръжте"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Отлично!"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Изпълнихте жеста за преглед на скорошните приложения."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Преглед на всички приложения"</string>
diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
index 9b808de65480..cc632db72abf 100644
--- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Изкл."</item>
<item msgid="3028994095749238254">"Вкл."</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Не е налице"</item>
+ <item msgid="6419996398343291862">"Изкл."</item>
+ <item msgid="5908720590832378783">"Вкл."</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index ae810a612d28..4281ea111b03 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"হিয়ারিং এড"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"চালু করা হচ্ছে…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"উজ্জ্বলতা টপ অ্যাপ নিয়ন্ত্রণ করায়\n এটিকে অ্যাডজাস্ট করা যাচ্ছে না"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"নিজে থেকে ঘুরবে"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"অটো-রোটেট স্ক্রিন"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"লোকেশন"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইস পেয়ার করতে ক্লিক করুন"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"প্রিসেট আপডেট করা যায়নি"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"প্রিসেট"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"বেছে নেওয়া হয়েছে"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"টুল"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"লাইভ ক্যাপশন"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"মনে রাখবেন"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইসের মাইক্রোফোন আনব্লক করতে চান?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ডিভাইসের ক্যামেরা আনব্লক করতে চান?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ডিভাইসের ক্যামেরা এবং মাইক্রোফোন আনব্লক করতে চান?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"এখন শুরু করুন"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"কোনও বিজ্ঞপ্তি নেই"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"নতুন কোনও বিজ্ঞপ্তি নেই"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"নোটিফিকেশন কুলডাউন এখন চালু আছে"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"আপনি একসঙ্গে খুব বেশি বিজ্ঞপ্তি পেলে আপনার ডিভাইসের ভলিউম এবং সতর্কবার্তা সর্বাধিক ২ মিনিটের জন্য অটোমেটিক কমে যায়।"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"বন্ধ করুন"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"পুরনো বিজ্ঞপ্তি দেখতে আনলক করুন"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"স্প্লিট স্ক্রিন ব্যবহার করার সময় ডানদিকের বা নিচের অ্যাপে পাল্টে নিন"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"স্প্লিট স্ক্রিন ব্যবহার করার সময় বাঁদিকের বা উপরের অ্যাপে পাল্টে নিন"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"\'স্প্লিট স্ক্রিন\' থাকাকালীন: একটি অ্যাপ থেকে অন্যটিতে পাল্টান"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ডিসপ্লের মধ্যে একটি থেকে অপরটিতে অ্যাক্টিভ উইন্ডোটি সরান"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ইনপুট"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"পরবর্তী ভাষায় পাল্টান"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"আগের ভাষায় পাল্টান"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>টির চেয়ে কম অক্ষর ব্যবহার করুন"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"খোলা কথোপকথন"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"কথোপকথন উইজেট"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"কোনও কথোপথন আপনার হোম স্ক্রিনে যোগ করার জন্য এতে ট্যাপ করুন"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"আরও বেশি রেজোলিউশনের জন্য, ফোন ফ্লিপ করুন"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ফোল্ড করা যায় এমন ডিভাইস খোলা হচ্ছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ফোল্ড করা যায় এমন ডিভাইস উল্টানো হচ্ছে"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফোল্ড করা রয়েছে"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ফোল্ড করা নেই"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"অ্যাক্সেসিবিলিটি"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"কীবোর্ড শর্টকাট"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"কীবোর্ড শর্টকাট কাস্টমাইজ করুন"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"শর্টকাট অ্যাসাইন করতে কী প্রেস করুন"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"শর্টকাট সার্চ করুন"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"কোনও সার্চ ফলাফল নেই"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"আইকন আড়াল করুন"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"অ্যাকশন বা মেটা কী আইকন"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"প্লাস আইকন"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"কাস্টমাইজ করুন"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"হয়ে গেছে"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"আইকন বড় করুন"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"টেনে আনার হ্যান্ডেল"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"কীবোর্ড সেটিংস"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"শর্টকাট সেট করুন"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"বাতিল করুন"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"কী প্রেস করুন"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"কী কম্বিনেশন আগে থেকে ব্যবহার হচ্ছে। অন্য কী ব্যবহার করে দেখুন।"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"আপনার কীবোর্ড ব্যবহার করে নেভিগেট করুন"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীবোর্ড শর্টকাট সম্পর্কে জানুন"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপনার টাচপ্যাড ব্যবহার করে নেভিগেট করুন"</string>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index dd5b40636fb6..e21392857e7a 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"বন্ধ আছে"</item>
<item msgid="3028994095749238254">"চালু আছে"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"উপলভ্য নেই"</item>
+ <item msgid="6419996398343291862">"বন্ধ আছে"</item>
+ <item msgid="5908720590832378783">"চালু আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index df562ef3508a..9d9bf7f004a2 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -113,8 +113,8 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Snimaj jednu aplikaciju"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Snimaj cijeli ekran"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Snimi cijeli ekran: %s"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kada snimate cijeli ekran, snimat će se sve što se prikazuje na ekranu. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kada snimate aplikaciju, snimat će se sve što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kada snimate cijeli ekran, snimat će se sve što se prikazuje na ekranu. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kada snimate aplikaciju, snimat će se sve što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Snimaj ekran"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Odaberite aplikaciju koju želite snimati"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimanje zvuka"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ulaz"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Nije moguće podesiti osvijetljenost\n jer njome upravlja aplikacija pri vrhu"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko rotiranje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da uparite novi uređaj"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje zadane postavke nije uspjelo"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Zadana postavka"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Odabrano"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alati"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Automatski titlovi"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Bilješka"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokirati mikrofon uređaja?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokirati kameru uređaja?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokirati kameru i mikrofon uređaja?"</string>
@@ -555,21 +555,21 @@
<string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Dijeli cijeli ekran"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
- <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kada dijelite cijeli ekran, sve što je na ekranu će biti vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kada dijelite aplikaciju, sve što se prikazuje ili reproducira u toj aplikaciji će biti vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kada dijelite cijeli ekran, sve što je na ekranu će biti vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kada dijelite aplikaciju, sve što se prikazuje ili reproducira u toj aplikaciji će biti vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Dijeli ekran"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućila tu opciju"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Odaberite aplikaciju koju želite dijeliti"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Emitirati ekran?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Emitiraj jednu aplikaciju"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Emitiraj cijeli ekran"</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Kada emitirate cijeli ekran, vidljivo je sve što je na ekranu. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Kada emitirate aplikaciju, vidljivo je sve što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Kada emitirate cijeli ekran, vidljivo je sve što je na ekranu. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Kada emitirate aplikaciju, vidljivo je sve što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Emitiraj ekran"</string>
<string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Odaberite aplikaciju koju želite emitirati"</string>
<string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Pokrenuti dijeljenje?"</string>
- <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kada dijelite, snimate ili emitirate, Android ima pristup svemu što je vidljivo na ekranu ili što se reproducira na uređaju. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
- <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kada dijelite, snimate ili emitirate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
+ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kada dijelite, snimate ili emitirate, Android ima pristup svemu što je vidljivo na ekranu ili što se reproducira na uređaju. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
+ <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kada dijelite, snimate ili emitirate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, audio i videozapisi."</string>
<string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Pokreni"</string>
<string name="media_projection_entry_generic_permission_dialog_continue_single_app" msgid="5920814988611877051">"Naprijed"</string>
<string name="media_projection_task_switcher_text" msgid="590885489897412359">"Dijeljenje se pauzira kada promijenite aplikaciju"</string>
@@ -593,7 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Započni odmah"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nema obavještenja"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nema novih obavještenja"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Stišavanje obavijesti sada je uključeno"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Stišavanje obavještenja je sada uključeno"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Jačina zvuka uređaja i obavještenja se automatski stišavaju do 2 minute kada odjednom dobijete previše obavještenja."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Isključi"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Otključajte da vidite starija obavještenja"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prelazak u aplikaciju desno ili ispod uz podijeljeni ekran"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju lijevo ili iznad dok koristite podijeljeni ekran"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Za vrijeme podijeljenog ekrana: zamjena jedne aplikacije drugom"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Premještanje aktivnog prozora između ekrana"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Unos"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Prebacivanje na sljedeći jezik"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Prebacivanje na prethodni jezik"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Koristite manje od <xliff:g id="LENGTH">%1$d</xliff:g> znak(ov)a"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Vidžeti razgovora"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Dodirnite razgovor da ga dodate na početni ekran"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za višu rezoluciju obrnite telefon"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Sklopivi uređaj se rasklapa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Sklopivi uređaj se obrće"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sklopljeno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otklopljeno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Prečice tastature"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite prečice na tastaturi"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite tipku da dodijelite prečicu"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona tipke radnji ili meta tipka"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona znaka plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Prilagođavanje"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Gotovo"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona proširivanja"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ručica za prevlačenje"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Postavke tastature"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Postavi prečicu"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ta se kombinacija tipki već koristi. Pokušajte s drugom tipkom."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o prečicama tastature"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string>
diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
index 3f8841afb4f2..2401e4a2fc37 100644
--- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Isključeno"</item>
<item msgid="3028994095749238254">"Uključeno"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nedostupno"</item>
+ <item msgid="6419996398343291862">"Isključeno"</item>
+ <item msgid="5908720590832378783">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0ecd8c0e0c23..0be3d80edcb7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiòfons"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"S\'està activant…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"No es pot ajustar la brillantor perquè\n està controlada per l\'aplicació superior"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Gira automàticament"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Gira la pantalla automàticament"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fes clic per vincular un dispositiu nou"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"No s\'ha pogut actualitzar el valor predefinit"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Valors predefinits"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seleccionat"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Eines"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtítols instantanis"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vols desbloquejar el micròfon del dispositiu?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vols desbloquejar la càmera del dispositiu?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vols desbloquejar la càmera i el micròfon del dispositiu?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Desactivat"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"No definit"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gestiona a la configuració"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hi ha cap mode actiu}=1{{mode} està actiu}many{Hi ha # de modes actius}other{Hi ha # modes actius}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Cap mode actiu}=1{{mode} està actiu}many{# de modes actius}other{# modes actius}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"No t\'interromprà cap so ni cap vibració, tret dels de les alarmes, recordatoris, esdeveniments i trucades de les persones que especifiquis. Continuaràs sentint tot allò que decideixis reproduir, com ara música, vídeos i jocs."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"No t\'interromprà cap so ni cap vibració, tret dels de les alarmes. Continuaràs sentint tot allò que decideixis reproduir, com ara música, vídeos i jocs."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalitza"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Comença ara"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No hi ha cap notificació"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"No hi ha cap notificació nova"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"La moderació de notificacions està activada"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"El volum i les alertes del dispositiu es redueixen automàticament durant 2 minuts com a màxim quan reps massa notificacions alhora."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desactiva"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueja per veure notif. anteriors"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Canvia a l\'aplicació de la dreta o de sota amb la pantalla dividida"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Canvia a l\'aplicació de l\'esquerra o de dalt amb la pantalla dividida"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Durant el mode de pantalla dividida: substitueix una app per una altra"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mou la finestra activa entre pantalles"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Canvia a l\'idioma següent"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Caniva a l\'idioma anterior"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utilitza menys de <xliff:g id="LENGTH">%1$d</xliff:g> caràcters"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Toca una conversa per afegir-la a la teva pantalla d\'inici"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Per a una resolució més alta, gira el telèfon"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositiu plegable desplegant-se"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositiu plegable girant"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilitat"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tecles de drecera"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalitza les tecles de drecera"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Prem la tecla per assignar la drecera"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hi ha cap resultat de la cerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icona de la tecla d\'acció o Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Icona del signe més"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalitza"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Fet"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Desplega la icona"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ansa per arrossegar"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configuració del teclat"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Configura la drecera"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel·la"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prem una tecla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"La combinació de tecles ja s\'està utilitzant. Prova-ho amb una altra tecla."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega amb el teclat"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprèn les tecles de drecera"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega amb el ratolí tàctil"</string>
@@ -1458,7 +1453,7 @@
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Ben fet!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Has completat el gest per anar a la pantalla d\'inici"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Mostra les aplicacions recents"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Llisca cap amunt amb tres dits i mantén premut al ratolí tàctil"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Llisca cap amunt amb tres dits i mantén-los premuts al ratolí tàctil"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ben fet!"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completat el gest per veure les aplicacions recents."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Mostra totes les aplicacions"</string>
@@ -1482,7 +1477,7 @@
<string name="home_edu_notification_title" msgid="6097902076909654045">"Utilitza el ratolí tàctil per anar a la pantalla d\'inici"</string>
<string name="home_edu_notification_content" msgid="6631697734535766588">"Llisca tres dits cap amunt. Toca per aprendre més gestos."</string>
<string name="overview_edu_notification_title" msgid="1265824157319562406">"Utilitza el ratolí tàctil per veure les aplicacions recents"</string>
- <string name="overview_edu_notification_content" msgid="3578204677648432500">"Llisca cap amunt amb tres dits i mantén premut. Toca per aprendre més gestos."</string>
+ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Llisca cap amunt amb tres dits i mantén-los premut. Toca per aprendre més gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utilitza el teclat per veure totes les aplicacions"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Prem la tecla d\'acció en qualsevol moment. Toca per aprendre més gestos."</string>
<string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"L\'atenuació extra ara forma part del control lliscant de brillantor"</string>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index ea1a576d2cc0..94d554562b1c 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desactivat"</item>
<item msgid="3028994095749238254">"Activat"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"No disponible"</item>
+ <item msgid="6419996398343291862">"Desactivat"</item>
+ <item msgid="5908720590832378783">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3f00ce42939a..1bbef7bce160 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Naslouchátka"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapínání…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Jas nelze upravit, protože ho\n řídí hlavní aplikace"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. otáčení"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčení obrazovky"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zařízení"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Předvolbu nelze aktualizovat"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Předvolba"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Vybráno"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Nástroje"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Okamžité titulky"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Poznámka"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokovat mikrofon zařízení?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokovat fotoaparát zařízení?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokovat fotoaparát a mikrofon zařízení?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Spustit"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Žádná oznámení"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Žádná nová oznámení"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Oznámení jsou teď zeslabená"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Když máte moc oznámení najednou, až na dvě minuty se sníží hlasitost zařízení a oznámení se omezí."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Vypnout"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Starší oznámení se zobrazí po odemknutí"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Přepnout na aplikaci vpravo nebo dole v režimu rozdělené obrazovky"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Přepnout na aplikaci vlevo nebo nahoře v režimu rozdělené obrazovky"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"V režimu rozdělené obrazovky: nahradit jednu aplikaci druhou"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Přesunout aktivní okno mezi obrazovkami"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vstup"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Přepnout na další jazyk"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Přepnout na předchozí jazyk"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Použijte méně než <xliff:g id="LENGTH">%1$d</xliff:g> znaků"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgety konverzací"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Klepnutím na konverzaci ji přidáte na plochu"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Otočte telefon, abyste dosáhli vyššího rozlišení"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozkládání rozkládacího zařízení"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Otáčení rozkládacího zařízení"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"složené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Přístupnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové zkratky"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Přizpůsobení klávesových zkratek"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Nastavte zkratku stisknutím klávesy"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhledat zkratky"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Žádné výsledky hledání"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona klávesy Akce nebo Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona Plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Přizpůsobit"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Hotovo"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalení"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"nebo"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Úchyt pro přetažení"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavení klávesnice"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastavit zkratku"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Zrušit"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Stiskněte klávesu"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinace kláves se už používá. Použijte jinou klávesu."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigujte pomocí klávesnice"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte se klávesové zkratky"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigujte pomocí touchpadu"</string>
diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
index abfe50df0d36..a02ed764ab0e 100644
--- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Vypnuto"</item>
<item msgid="3028994095749238254">"Zapnuto"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Není k dispozici"</item>
+ <item msgid="6419996398343291862">"Vypnuto"</item>
+ <item msgid="5908720590832378783">"Zapnuto"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 9229b18d3363..b2e17a929900 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverer…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Lysstyrken kan ikke justeres, fordi den\n styres af den øverste app"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Roter automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Roter skærmen automatisk"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokation"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik for at parre en ny enhed"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Forindstillingen kunne ikke opdateres"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forindstilling"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valgt"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Værktøjer"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Livetekstning"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du fjerne blokeringen af enhedens mikrofon?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du fjerne blokeringen af enhedens kamera?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du fjerne blokeringen af enhedens kamera og mikrofon?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Start nu"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ingen notifikationer"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Ingen nye notifikationer"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Dæmpning af notifikationer er nu aktiveret"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Enheden skruer automatisk ned for lydstyrken og minimerer underretninger på skærmen i op til 2 minutter, når du får for mange notifikationer på én gang."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Deaktiver"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Lås op for at se ældre notifikationer"</string>
@@ -700,7 +699,7 @@
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Rumlig lyd"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Fra"</string>
<string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Fast"</string>
- <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Register. af hoved­bevægelser"</string>
+ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Hovedregistrering"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Tryk for at ændre ringetilstand"</string>
<string name="volume_ringer_mode" msgid="6867838048430807128">"ringetilstand"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"slå lyden fra"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skift til en app til højre eller nedenfor, når du bruger opdelt skærm"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skift til en app til venstre eller ovenfor, når du bruger opdelt skærm"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ved opdelt skærm: Udskift én app med en anden"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Flyt det aktive vindue fra skærm til skærm"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Skift til næste sprog"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Skift til forrige sprog"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Angiv færre end <xliff:g id="LENGTH">%1$d</xliff:g> tegn"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Åben samtale"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Samtalewidgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tryk på en samtale for at føje den til din startskærm"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Vend telefonen for at få højere opløsning"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldbar enhed foldes ud"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldbar enhed vendes om"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"foldet"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"foldet ud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hjælpefunktioner"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tastaturgenveje"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tilpas tastaturgenveje"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tryk på en tast for at tildele genvejen"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Genveje til søgning"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Der er ingen søgeresultater"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikon for handlingstast eller metatast"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plusikon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Tilpas"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Udfør"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon for Udvid"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Håndtag"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastaturindstillinger"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Konfigurer genvej"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuller"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tryk på en tast"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tastekombinationen er allerede i brug. Prøv en anden tast."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger ved hjælp af dit tastatur"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Se tastaturgenveje"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger ved hjælp af din touchplade"</string>
diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml
index 9009eedc39cc..8b536a286af0 100644
--- a/packages/SystemUI/res/values-da/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Fra"</item>
<item msgid="3028994095749238254">"Til"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Ikke tilgængelig"</item>
+ <item msgid="6419996398343291862">"Fra"</item>
+ <item msgid="5908720590832378783">"Til"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e8dcae9828ce..5f7128e804d0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Eingabe"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörgerät"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Wird aktiviert…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Die Helligkeit kann nicht angepasst werden, weil sie\n von der obersten App gesteuert wird"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. drehen"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Bildschirm automatisch drehen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Standort"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicken, um neues Gerät zu koppeln"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Voreinstellung konnte nicht aktualisiert werden"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Voreinstellung"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Ausgewählt"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Automatische Untertitel"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notiz"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blockierung des Gerätemikrofons aufheben?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Blockierung der Gerätekamera aufheben?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blockierung von Gerätekamera und Gerätemikrofon aufheben?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Jetzt starten"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Keine Benachrichtigungen"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Keine neuen Benachrichtigungen"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"„Benachrichtigungen reduzieren” ist jetzt aktiviert"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Wenn du zu viele Benachrichtigungen auf einmal erhältst, wird die Lautstärke automatisch bis zu 2 min lang verringert und Benachrichtigungen werden minimiert."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Deaktivieren"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Für ältere Benachrichtigungen entsperren"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Im Splitscreen-Modus zu einer App rechts oder unten wechseln"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Im Splitscreen-Modus zu einer App links oder oben wechseln"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Im Splitscreen: eine App durch eine andere ersetzen"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Aktives Fenster auf anderes Display verschieben"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Eingabe"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Zur nächsten Sprache wechseln"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Zur vorherigen Sprache wechseln"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Maximal <xliff:g id="LENGTH">%1$d</xliff:g> Zeichen möglich"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Offene Unterhaltung"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Unterhaltungs-Widgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tippe auf eine Unterhaltung, um sie deinem Startbildschirm hinzuzufügen"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Für höhere Auflösung Smartphone umdrehen"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Faltbares Gerät wird geöffnet"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Faltbares Gerät wird umgeklappt"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zugeklappt"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aufgeklappt"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Bedienungshilfen"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tastenkürzel"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tastenkombinationen anpassen"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Drücke eine Taste, um eine Tastenkombination festzulegen"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tastenkürzel suchen"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Keine Suchergebnisse"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Symbol für Aktions- oder Meta-Taste"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plussymbol"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Anpassen"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Fertig"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Symbol „Maximieren“"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oder"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ziehpunkt"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastatureinstellungen"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tastenkombination festlegen"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Abbrechen"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Taste drücken"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Diese Tastenkombination wird bereits verwendet. Versuche es mit einer anderen Taste."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigation mit der Tastatur"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informationen zu Tastenkombinationen"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigation mit dem Touchpad"</string>
@@ -1452,7 +1447,7 @@
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zurück"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Wische mit drei Fingern auf dem Touchpad nach links oder rechts"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Sehr gut!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du hast den Schritt für die „Zurück“-Geste abgeschlossen."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du hast das Tutorial für die „Zurück“-Touch-Geste abgeschlossen."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Startbildschirm"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Wische an einer beliebigen Stelle auf dem Touchpad mit drei Fingern nach oben"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Gut gemacht!"</string>
diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml
index e7f5b574755a..bb39b4e3c2b3 100644
--- a/packages/SystemUI/res/values-de/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Aus"</item>
<item msgid="3028994095749238254">"An"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nicht verfügbar"</item>
+ <item msgid="6419996398343291862">"Aus"</item>
+ <item msgid="5908720590832378783">"An"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index cf9adddcc3ea..fd8e37a34030 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Είσοδος"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Βοηθήματα ακοής"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ενεργοποίηση…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Δεν είναι δυνατή η προσαρμογή της φωτεινότητας, επειδή\n ελέγχεται από την εφαρμογή στην κορυφή"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Αυτόματη περιστροφή"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Αυτόματη περιστροφή οθόνης"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Τοποθεσία"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Κάντε κλικ για σύζευξη νέας συσκευής"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Δεν ήταν δυνατή η ενημέρωση της προεπιλογής"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Προεπιλογή"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Έχει επιλεγεί"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Εργαλεία"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Ζωντανοί υπότιτλοι"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Σημείωση"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Κατάργηση αποκλεισμού μικροφώνου συσκευής;"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Κατάργηση αποκλεισμού κάμερας συσκευής;"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Κατάργηση αποκλεισμού κάμερας και μικροφώνου συσκευής;"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Εναλλαγή στην εφαρμογή δεξιά ή κάτω κατά τη χρήση διαχωρισμού οθόνης"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Εναλλαγή σε εφαρμογή αριστερά ή επάνω κατά τη χρήση διαχωρισμού οθόνης"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Κατά τον διαχωρισμό οθόνης: αντικατάσταση μιας εφαρμογής με άλλη"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Μετακίνηση ενεργού παραθύρου μεταξύ οθονών"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Είσοδος"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Εναλλαγή στην επόμενη γλώσσα"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Εναλλαγή στην προηγούμενη γλώσσα"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Χρησιμοποιήστε λιγότερους από <xliff:g id="LENGTH">%1$d</xliff:g> χαρακτήρες"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Άνοιγμα συνομιλίας"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Γραφικά στοιχεία συνομιλίας"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Πατήστε μια συνομιλία για να την προσθέσετε στην αρχική οθόνη"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Για υψηλότερη ανάλυση, αναστρέψτε το τηλέφωνο"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Αναδιπλούμενη συσκευή που ξεδιπλώνει"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Αναδιπλούμενη συσκευή που διπλώνει"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"διπλωμένη"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ξεδιπλωμένη"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Προσβασιμότητα"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Συντομεύσεις πληκτρολογίου"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Προσαρμογή συντομεύσεων πληκτρολογίου"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Πατήστε το πλήκτρο για εκχώρηση της συντόμευσης"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Συντομεύσεις αναζήτησης"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Κανένα αποτέλεσμα αναζήτησης"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Εικονίδιο σύμπτυξης"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Εικονίδιο πλήκτρου ενέργειας ή Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Εικονίδιο συν"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Προσαρμογή"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Τέλος"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Εικονίδιο ανάπτυξης"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ή"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Λαβή μεταφοράς"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ρυθμίσεις πληκτρολογίου"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ορισμός συντόμευσης"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Ακύρωση"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Πατήστε ένα πλήκτρο"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ο συνδυασμός πλήκτρων χρησιμοποιείται ήδη. Δοκιμάστε άλλο πλήκτρο."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Πλοήγηση με το πληκτρολόγιο"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Μάθετε συντομεύσεις πληκτρολογίου"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Πλοήγηση με την επιφάνεια αφής"</string>
diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml
index 1276fb4addbc..ec2a930dcb75 100644
--- a/packages/SystemUI/res/values-el/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Ανενεργή"</item>
<item msgid="3028994095749238254">"Ενεργή"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Μη διαθέσιμο"</item>
+ <item msgid="6419996398343291862">"Ανενεργό"</item>
+ <item msgid="5908720590832378783">"Ενεργό"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 66659599dc94..4280ff2ad994 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -113,8 +113,8 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Record one app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Record entire screen"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Record entire screen: %s"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Record screen"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Choose app to record"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Can\'t adjust brightness because it\'s being\n controlled by the top app"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selected"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Move active window between displays"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Switch to previous language"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"For higher resolution, flip the phone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Press key to assign shortcut"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Action or Meta key icon"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plus icon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Customise"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Done"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Keyboard settings"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Set shortcut"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Key combination already in use. Try another key."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
index c0bbabea4d78..1b60921d3237 100644
--- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Off"</item>
<item msgid="3028994095749238254">"On"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Unavailable"</item>
+ <item msgid="6419996398343291862">"Off"</item>
+ <item msgid="5908720590832378783">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 9a3bedaabe4c..3b009a1f1d14 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -414,6 +414,8 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selected"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string>
<string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
@@ -1218,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your Home screen"</string>
@@ -1353,6 +1357,7 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"For higher resolution, flip the phone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
+ <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 66659599dc94..4280ff2ad994 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -113,8 +113,8 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Record one app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Record entire screen"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Record entire screen: %s"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Record screen"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Choose app to record"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Can\'t adjust brightness because it\'s being\n controlled by the top app"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selected"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Move active window between displays"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Switch to previous language"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"For higher resolution, flip the phone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Press key to assign shortcut"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Action or Meta key icon"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plus icon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Customise"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Done"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Keyboard settings"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Set shortcut"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Key combination already in use. Try another key."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
index c0bbabea4d78..1b60921d3237 100644
--- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Off"</item>
<item msgid="3028994095749238254">"On"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Unavailable"</item>
+ <item msgid="6419996398343291862">"Off"</item>
+ <item msgid="5908720590832378783">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 66659599dc94..4280ff2ad994 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -113,8 +113,8 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Record one app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Record entire screen"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Record entire screen: %s"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Record screen"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Choose app to record"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Can\'t adjust brightness because it\'s being\n controlled by the top app"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selected"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Move active window between displays"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Switch to previous language"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"For higher resolution, flip the phone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Press key to assign shortcut"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Action or Meta key icon"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plus icon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Customise"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Done"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Keyboard settings"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Set shortcut"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Key combination already in use. Try another key."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
index c0bbabea4d78..1b60921d3237 100644
--- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Off"</item>
<item msgid="3028994095749238254">"On"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Unavailable"</item>
+ <item msgid="6419996398343291862">"Off"</item>
+ <item msgid="5908720590832378783">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 3dc305811498..ad403b1658ee 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -114,7 +114,7 @@
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Grabar toda la pantalla"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Grabar toda la pantalla: %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Cuando grabes toda la pantalla, se grabará todo lo que se muestre en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Cuando grabes una app, se registrará todo lo que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Cuando grabes una app, se grabará todo lo que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Grabar pantalla"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Elige una app para grabar"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabar audio"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"La app superior controla el brillo,\npor lo que no se puede ajustar"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar la pantalla automáticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para vincular un dispositivo nuevo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"No se pudo actualizar el ajuste predeterminado"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Ajuste predeterminado"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seleccionado"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Herramientas"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitulado instantáneo"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Quieres desbloquear el micrófono del dispositivo?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Quieres desbloquear la cámara del dispositivo?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Quieres desbloquear la cámara y el micrófono del dispositivo?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Desactivado"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Sin establecer"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Administrar en configuración"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hay modos activos}=1{{mode} está activo}many{# de modos están activos}other{# modos están activos}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hay modos activos}=1{{mode} activo}many{# de modos activos}other{# modos activos}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas, los recordatorios, los eventos y las llamadas de los emisores que especifiques. Podrás escuchar el contenido que reproduzcas, como música, videos y juegos."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas. Podrás escuchar el contenido que reproduzcas, como música, videos y juegos."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ubicar la app a la derecha o abajo cuando usas la pantalla dividida"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ubicar la app a la izquierda o arriba cuando usas la pantalla dividida"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Durante pantalla dividida: Reemplaza una app con otra"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mover la ventana activa de una pantalla a otra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Cambiar al próximo idioma"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Cambiar al idioma anterior"</string>
@@ -1007,7 +1006,7 @@
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi desactivado"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth desactivado"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"No interrumpir desactivado"</string>
- <string name="dnd_is_on" msgid="7009368176361546279">"No interrumpir está activado"</string>
+ <string name="dnd_is_on" msgid="7009368176361546279">"No interrumpir activado"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Se activó el modo No interrumpir con una regla automática (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Se activó el modo No interrumpir con una app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Se activó el modo No interrumpir con una app o regla automática."</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Usa menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversación"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Presiona una conversación para agregarla a tu pantalla principal"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para obtener una resolución más alta, gira el teléfono"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable siendo desplegado"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable siendo girado"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personaliza las combinaciones de teclas"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Presiona la tecla para asignar el acceso directo"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar combinaciones de teclas"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"La búsqueda no arrojó resultados"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ícono tecla meta o de acción"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ícono de signo más"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Listo"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícono de expandir"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configuración del teclado"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Establecer combinación de teclas"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Presiona una tecla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"La combinación de teclas ya está en uso. Prueba con otra."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega con el teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega con el panel táctil"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index dec68dae3dc1..1c587d663563 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desactivados"</item>
<item msgid="3028994095749238254">"Activados"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"No disponible"</item>
+ <item msgid="6419996398343291862">"Desactivado"</item>
+ <item msgid="5908720590832378783">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 4660d9879e76..50de6d2e452a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"No se puede ajustar el brillo porque la aplicación superior lo está\n controlando"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar pantalla automáticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para emparejar un nuevo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"No se ha podido actualizar el preajuste"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preajuste"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seleccionado"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Herramientas"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtítulos automáticos"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Desbloquear el micrófono del dispositivo?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Desbloquear la cámara del dispositivo?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Desbloquear la cámara y el micrófono del dispositivo?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Desactivado"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Sin definir"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gestionar en los ajustes"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hay modos activos}=1{{mode} está activo}many{Hay # modos activos}other{Hay # modos activos}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hay modos activos}=1{{mode} activo}many{Hay # modos activos}other{Hay # modos activos}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas, los recordatorios, los eventos y las llamadas que especifiques. Seguirás escuchando el contenido que quieras reproducir, como música, vídeos y juegos."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas. Seguirás escuchando el contenido que quieras reproducir, como música, vídeos y juegos."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Empezar ahora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"No hay notificaciones nuevas"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Bajar volumen de notificaciones ahora está activado"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"El volumen y las alertas de tu dispositivo se reducen durante hasta 2 minutos si recibes muchas notificaciones a la vez."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desactivar"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver notificaciones anteriores"</string>
@@ -716,7 +715,7 @@
<string name="volume_panel_hint_muted" msgid="1124844870181285320">"silenciado"</string>
<string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Reproduciendo <xliff:g id="LABEL">%s</xliff:g> en"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"Se reproducirá en"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"El audio se reproducirá en"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Llamando desde"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Configurador de UI del sistema"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de estado"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar a la aplicación de la derecha o de abajo en pantalla dividida"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar a la app de la izquierda o de arriba en pantalla dividida"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Con pantalla dividida: reemplazar una aplicación por otra"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mover ventana activa de una pantalla a otra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Cambiar a siguiente idioma"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Cambiar a idioma anterior"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Usa menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversación"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Toca una conversación para añadirla a la pantalla de inicio"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para una mayor resolución, gira el teléfono"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable desplegándose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable mostrado desde varios ángulos"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar las combinaciones de teclas"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pulsa una tecla para asignar una combinación de teclas"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atajos de búsqueda"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hay resultados de búsqueda"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icono de la tecla de acción o de la tecla Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Icono de más"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Hecho"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icono de desplegar"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ajustes del teclado"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Establecer combinación de teclas"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pulsa una tecla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"La combinación de teclas ya se está usando. Prueba con otra tecla."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Desplázate con el teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Desplázate con el panel táctil"</string>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index e872c263f1e6..5c4f36a064db 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desactivados"</item>
<item msgid="3028994095749238254">"Activado"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"No disponible"</item>
+ <item msgid="6419996398343291862">"Desactivado"</item>
+ <item msgid="5908720590832378783">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index f2a92f299081..9c0d56dad8c3 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -115,8 +115,8 @@
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Kogu ekraanikuva salvestamine: %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kui salvestate kogu ekraani, salvestatakse kõik ekraanil kuvatud andmed. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kui salvestate rakendust, salvestatakse kõik, mida selles rakenduses näidatakse või esitatakse. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
- <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ekraanikuva jäädvustamine"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Vali salvestamiseks rakendus"</string>
+ <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Salvesta ekraanikuva"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Valige salvestamiseks rakendus"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Salvesta heli"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Seadme heli"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Seadmest pärinev heli, nt muusika, kõned ja helinad"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sisend"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuuldeaparaadid"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Sisselülitamine …"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Heledust ei saa reguleerida, kuna seda\n juhib ülemine rakendus"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Asukoht"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Uue seadme sidumiseks klõpsake"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Eelseadistust ei saanud värskendada"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Eelseadistus"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valitud"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tööriistad"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Reaalajas subtiitrid"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Märkus"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kas tühistada seadme mikrofoni blokeerimine?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kas tühistada seadme kaamera blokeerimine?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kas tühistada seadme kaamera ja mikrofoni blokeerimine?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Alusta kohe"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Märguandeid pole"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Uusi märguandeid ei ole"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Märguannete summutamine on nüüd sisse lülitatud"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Kui saate korraga liiga palju märguandeid, vähendab seade automaatselt helitugevust ja minimeerib märguanded kuni kaheks minutiks."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Lülita välja"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Vanemate märguannete nägemiseks avage"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Paremale või alumisele rakendusele lülitamine jagatud ekraani ajal"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vasakule või ülemisele rakendusele lülitamine jagatud ekraani ajal"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ekraanikuva jagamise ajal: ühe rakenduse asendamine teisega"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Aktiivse akna teisaldamine ekraanide vahel"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Sisend"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Järgmisele keelele lülitamine"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Eelmisele keelele lülitamine"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Kasutage vähem kui <xliff:g id="LENGTH">%1$d</xliff:g> tähemärki"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Vestlusvidinad"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Puudutage vestlust, et lisada see oma avakuvale"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Suurema eraldusvõime saavutamiseks pöörake telefon ümber"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Volditava seadme lahtivoltimine"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Volditava seadme ümberpööramine"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kokku volditud"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"lahti volditud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,35 +1418,28 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Juurdepääsetavus"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klaviatuuri otseteed"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klaviatuuri otseteede kohandamine"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Otsetee lisamiseks vajutage klahvi"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Otsige otseteid"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Otsingutulemused puuduvad"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Toiming või metaklahv"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Pluss-ikoon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Kohandamine"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Valmis"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laiendamisikoon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"või"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Lohistamispide"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatuuri seaded"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Määrake otsetee"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Tühista"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Vajutage klahvi"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Klahvikombinatsioon juba kasutusel. Proovige mõnda muud klahvi."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeerige klaviatuuri abil"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Õppige klaviatuuri otseteid"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeerige puuteplaadi abil"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Õppige puuteplaadi liigutusi"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigeerige klaviatuuri ja puuteplaadi abil"</string>
- <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Õppige puuteplaadi liigutusi, klaviatuuri otseteid ja palju muud"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Õppige puuteplaadi liigutusi, klaviatuuri otseteid ja palju muud."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Mine tagasi"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Avakuvale"</string>
<string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Hiljutiste rakenduste vaatamine"</string>
@@ -1460,7 +1455,7 @@
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Hiljutiste rakenduste vaatamine"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pühkige üles ja hoidke kolme sõrme puuteplaadil"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Väga hea!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Lõpetasite hiljutiste rakenduste vaatamise liigutuse."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Tegite hiljutiste rakenduste vaatamise liigutuse."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Kõigi rakenduste kuvamine"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Vajutage klaviatuuril toiminguklahvi"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hästi tehtud!"</string>
diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml
index 3af8dea15541..f9951280e5d4 100644
--- a/packages/SystemUI/res/values-et/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Välja lülitatud"</item>
<item msgid="3028994095749238254">"Sisse lülitatud"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Pole saadaval"</item>
+ <item msgid="6419996398343291862">"Väljas"</item>
+ <item msgid="5908720590832378783">"Sees"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index daca2a37635e..a971d1c25a16 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -116,7 +116,7 @@
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Pantaila osoa grabatzen ari zarenean, pantailan agertzen den guztia grabatzen da. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Aplikazio bat grabatzen ari zarenean, aplikazio horretan agertzen den edo bertan erreproduzitzen ari den guztia grabatzen da. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Grabatu pantaila"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Aukeratu zer aplikazio grabatu nahi duzun"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Aukeratu zein aplikazio grabatu nahi duzun"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabatu audioa"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Gailuaren audioa"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Gailuko soinuak; adibidez, musika, deiak eta tonuak"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sarrera"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audifonoak"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktibatzen…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Ezin da doitu argitasuna,\ngaineko aplikazioak kontrolatzen duelako"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Biratze automatikoa"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Biratu pantaila automatikoki"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Kokapena"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Egin klik beste gailu bat parekatzeko"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ezin izan da eguneratu aurrezarpena"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Aurrezarpena"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Hautatuta"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tresnak"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Istanteko azpitituluak"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Oharra"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Gailuaren mikrofonoa desblokeatu nahi duzu?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Gailuaren kamera desblokeatu nahi duzu?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Gailuaren kamera eta mikrofonoa desblokeatu nahi dituzu?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Hasi"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ez dago jakinarazpenik"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Ez dago jakinarazpen berririk"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Orain, jakinarazpenak arintzeko ezarpena aktibatuta dago"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Aldi berean jakinarazpen gehiegi jasotzen badituzu, gailuaren bolumena eta alertak automatikoki murriztuko dira 2 minutuz (gehienez)."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desaktibatu"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Jakinarazpen zaharragoak ikusteko, desblokeatu"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Aldatu eskuineko edo beheko aplikaziora pantaila zatitua erabiltzean"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Aldatu ezkerreko edo goiko aplikaziora pantaila zatitua erabiltzean"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Pantaila zatituan zaudela, ordeztu aplikazio bat beste batekin"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Eraman leiho aktiboa pantaila batetik bestera"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Sarrera"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Aldatu hurrengo hizkuntzara"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Aldatu aurreko hizkuntzara"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Erabili <xliff:g id="LENGTH">%1$d</xliff:g> karaktere baino gutxiago"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Elkarrizketa-widgetak"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Sakatu elkarrizketa bat orri nagusian gehitzeko"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Irauli telefonoa bereizmen handiago a lortzeko"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Gailu tolesgarria zabaltzen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Gailu tolesgarria biratzen"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"tolestuta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tolestu gabe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erabilerraztasuna"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Lasterbideak"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pertsonalizatu lasterbideak"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Sakatu tekla lasterbidea esleitzeko"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bilatu lasterbideak"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ez dago bilaketa-emaitzarik"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ekintzaren edo Meta teklaren ikonoa"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plus-ikonoa"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Pertsonalizatu"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Eginda"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Zabaltzeko ikonoa"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"edo"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Arrastatzeko kontrol-puntua"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Teklatuaren ezarpenak"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ezarri lasterbidea"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Utzi"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Sakatu tekla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tekla-konbinazio hori erabili da dagoeneko. Probatu beste tekla bat."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nabigatu teklatua erabilita"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ikasi lasterbideak"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nabigatu ukipen-panela erabilita"</string>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index 8ada72a9f3ae..5d4672f55adc 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desaktibatuta"</item>
<item msgid="3028994095749238254">"Aktibatuta"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Ez dago erabilgarri"</item>
+ <item msgid="6419996398343291862">"Desaktibatuta"</item>
+ <item msgid="5908720590832378783">"Aktibatuta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4f2c89e57216..bf7ccf0d8079 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ورودی"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سمعک"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"روشن کردن…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"نمی‌توان روشنایی را تنظیم کرد زیرا\n برنامه بالایی آن را کنترل می‌کند"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"چرخش خودکار"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"چرخش خودکار صفحه‌نمایش"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مکان"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"برای جفت کردن دستگاه جدید، کلیک کنید"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"پیش‌تنظیم به‌روزرسانی نشد"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"پیش‌تنظیم"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"انتخاب‌شده"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ابزارها"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"زیرنویس زنده ناشنوایان"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"یادداشت"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"دوربین و میکروفون دستگاه لغو انسداد شود؟"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"رفتن به برنامه سمت راست یا پایین درحین استفاده از صفحهٔ دونیمه"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"رفتن به برنامه سمت چپ یا بالا درحین استفاده از صفحهٔ دونیمه"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"درحین صفحهٔ دونیمه: برنامه‌ای را با دیگری جابه‌جا می‌کند"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"جابه‌جا کردن پنجره فعال بین نمایشگرها"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ورودی"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"رفتن به زبان بعدی"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"رفتن به زبان قبلی"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"از کمتر از <xliff:g id="LENGTH">%1$d</xliff:g> نویسه استفاده کنید"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریده‌دان کپی شد."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"باز کردن مکالمه"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ابزارک‌های مکالمه"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"روی مکالمه‌ای تک‌ضرب بزنید تا به «صفحه اصلی» اضافه شود"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"برای وضوح بیشتر، تلفن را بچرخانید"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"دستگاه تاشو درحال باز شدن"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"دستگاه تاشو درحال چرخش به اطراف"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"تاشده"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"تانشده"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"دسترس‌پذیری"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"میان‌برهای صفحه‌کلید"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"سفارشی‌سازی کردن میان‌برهای صفحه‌کلید"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"برای اختصاص دادن میان‌بر، کلید را فشار دهید"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"جستجوی میان‌برها"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"نتیجه‌ای برای جستجو پیدا نشد"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"نماد جمع کردن"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"نماد کلید کنش یا متا"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"نماد جمع"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"سفارشی‌سازی کردن"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"تمام"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"نماد ازهم بازکردن"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"دستگیره کشاندن"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"تنظیمات صفحه‌کلید"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"تنظیم میان‌بر"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"لغو"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"کلید را فشار دهید"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ترکیب کلید ازقبل درحال استفاده است. کلید دیگری را امتحان کنید."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"پیمایش کردن بااستفاده از صفحه‌کلید"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"آشنایی با میان‌برهای صفحه‌کلید"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"پیمایش کردن بااستفاده از صفحه لمسی"</string>
@@ -1446,7 +1442,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"آشنایی با اشاره‌های صفحه لمسی، میان‌برهای صفحه‌کلید، و موارد دیگر"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"برگشتن"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"رفتن به صفحه اصلی"</string>
- <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"مشاهده کردن برنامه‌های اخیر"</string>
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"مشاهده برنامه‌های اخیر"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تمام"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"برگشتن"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"با سه انگشت روی صفحه لمسی تند به چپ یا راست بکشید."</string>
@@ -1456,14 +1452,14 @@
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"با سه انگشت روی صفحه لمسی تند به بالا بکشید"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"عالی است!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"اشاره رفتن به صفحه اصلی را تکمیل کردید"</string>
- <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"مشاهده کردن برنامه‌های اخیر"</string>
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"مشاهده برنامه‌های اخیر"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"با سه انگشت روی صفحه لمسی تند به بالا بکشید و نگه دارید"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"عالی است!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"اشاره مشاهده برنامه‌های اخیر را انجام دادید"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"اشاره «مشاهده برنامه‌های اخیر» را تمام کردید"</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"مشاهده همه برنامه‌ها"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"دکمه کنش را روی صفحه لمسی فشار دهید"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"عالی بود!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"اشاره مشاهده همه برنامه‌ها را انجام دادید"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"اشاره «مشاهده همه برنامه‌ها» را تمام کردید"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"نور پس‌زمینه صفحه‌کلید"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"‏سطح %1$d از %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"کنترل خانه هوشمند"</string>
diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
index b7f4830db666..1f9d6c6218f7 100644
--- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"خاموش"</item>
<item msgid="3028994095749238254">"روشن"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"دردسترس نیست"</item>
+ <item msgid="6419996398343291862">"خاموش"</item>
+ <item msgid="5908720590832378783">"روشن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 581f0eada3ac..89ed95f0115f 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Syöttölaite"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuulolaitteet"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Otetaan käyttöön…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Kirkkautta ei voi säätää, koska \n ensisijainen sovellus ohjaa sitä"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaattinen kääntö"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Käännä näyttöä automaattisesti."</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sijainti"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Muodosta uusi laitepari klikkaamalla"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Esiasetusta ei voitu muuttaa"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Esiasetus"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valittu"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Työkalut"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Livetekstitys"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Muistiinpano"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kumotaanko laitteen mikrofonin esto?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kumotaanko laitteen kameran esto?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kumotaanko laitteen kameran ja mikrofonin esto?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Aloita nyt"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ei ilmoituksia"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Ei uusia ilmoituksia"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Ilmoitusten vaimennus on nyt päällä"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Äänenvoimakkuus ja ilmoitukset vaimennetaan enintään 2 minuutiksi, kun saat paljon ilmoituksia."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Laita pois päältä"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Avaa lukitus niin näet ilmoituksia"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Vaihda sovellukseen oikealla tai alapuolella jaetussa näytössä"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vaihda sovellukseen vasemmalla tai yläpuolella jaetussa näytössä"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Jaetun näytön aikana: korvaa sovellus toisella"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Siirrä aktiivinen ikkuna näytöltä toiselle"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Syöttötapa"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Vaihda seuraavaan kieleen"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Vaihda aiempaan kieleen"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Käytä alle <xliff:g id="LENGTH">%1$d</xliff:g> merkkiä"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Avaa keskustelu"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Keskusteluwidgetit"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Lisää keskustelu aloitusnäytölle napauttamalla sitä"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Resoluutio on parempi, kun käännät puhelimen"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Taitettava laite taitetaan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Taitettava laite käännetään ympäri"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"taitettu"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"taittamaton"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Saavutettavuus"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Pikanäppäimet"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pikanäppäimien muokkaaminen"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Määritä pikanäppäin painamalla näppäintä"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ei hakutuloksia"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Toiminto- tai Meta-näppäinkuvake"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Pluskuvake"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Muokkaa"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Valmis"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laajennuskuvake"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"tai"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vetokahva"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Näppäimistön asetukset"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Valitse pikanäppäin"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Peru"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Paina näppäintä"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Näppäinyhdistelmä on jo käytössä. Kokeile toista näppäintä."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Siirry käyttämällä näppäimistöä"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Opettele pikanäppäimiä"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Siirry käyttämällä kosketuslevyä"</string>
diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
index e323b8a46bc4..96750ef02d01 100644
--- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Pois päältä"</item>
<item msgid="3028994095749238254">"Päällä"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Ei saatavilla"</item>
+ <item msgid="6419996398343291862">"Pois päältä"</item>
+ <item msgid="5908720590832378783">"Päällä"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index bae94715ae6b..708d8b910306 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Prothèses auditives"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation en cours…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Impossible de régler la luminosité, car elle est\n contrôlée par l\'appli principale"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation auto"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquez ici pour associer un nouvel appareil"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Impossible de mettre à jour le préréglage"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Préréglage"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Sélectionné"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Outils"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sous-titres instantanés"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le microphone de l\'appareil?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer l\'appareil photo de l\'appareil?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le microphone?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'appli à droite ou en dessous avec l\'Écran divisé"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passer à l\'appli à gauche ou au-dessus avec l\'Écran divisé"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"En mode d\'écran divisé : remplacer une appli par une autre"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Déplacer la fenêtre active d\'un écran à l\'autre"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrée"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Passer à la langue suivante"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Passer à la langue précédente"</string>
@@ -1202,7 +1201,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Haut-parleurs et écrans"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Appareils suggérés"</string>
- <string name="media_input_group_title" msgid="2057057473860783021">"Entrer"</string>
+ <string name="media_input_group_title" msgid="2057057473860783021">"Entrée"</string>
<string name="media_output_group_title" msgid="6789001895863332576">"Sortie"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Arrêtez votre session partagée pour déplacer des contenus multimédias vers un autre appareil"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Arrêter"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utilisez moins de <xliff:g id="LENGTH">%1$d</xliff:g> caractères"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Ouvrir la conversation"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversation"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Touchez une conversation pour l\'ajouter à votre écran d\'accueil"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Pour une meilleure résolution, retournez le téléphone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable en cours de dépliage"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable en train d\'être retourné"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis-clavier"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personnaliser les raccourcis-clavier"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Appuyez sur la touche pour attribuer un raccourci"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Rechercher des raccourcis"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Aucun résultat de recherche"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icône de la touche Action ou Méta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Icône Plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personnaliser"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Terminé"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Poignée de déplacement"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Paramètres du clavier"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Définir un raccourci"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuler"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Appuyez sur la touche"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinaison de touches déjà utilisée. Essayez une autre touche."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide de votre clavier"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Apprenez à utiliser les raccourcis-clavier"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index 0bbacd09259c..782c05528fc0 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Désactivé"</item>
<item msgid="3028994095749238254">"Activé"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Non accessible"</item>
+ <item msgid="6419996398343291862">"Désactivée"</item>
+ <item msgid="5908720590832378783">"Activée"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 2006ea6d0348..41bd9106fb45 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -113,7 +113,7 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Enregistrer une appli"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Enregistrer tout l\'écran"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Enregistrer tout l\'écran : %s"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Lorsque vous enregistrez l\'intégralité de votre écran, tout ce qui s\'y affiche est enregistré. Faites donc attention aux éléments tels que les mots de passe, les détails du mode de paiement, les messages, les photos, et les contenus audio et vidéo."</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Lorsque vous enregistrez l\'intégralité de votre écran, tout ce qui s\'y affiche est enregistré. Faites donc attention aux éléments tels que les mots de passe, les détails de mode de paiement, les messages, les photos, et les contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Lorsque vous enregistrez une appli, tout ce qui est affiché ou lu dans celle-ci est enregistré. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages, photos et contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Enregistrer l\'écran"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Choisir l\'appli à enregistrer"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Appareils auditifs"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Impossible d\'ajuster la luminosité, car celle-ci\n est contrôlée par l\'appli principale"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation auto"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquer pour associer un nouvel appareil"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Impossible de mettre à jour les préréglages"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Préréglage"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Sélectionné"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Outils"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sous-titres instantanés"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le micro de l\'appareil ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer la caméra de l\'appareil ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le micro de l\'appareil ?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Commencer"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Aucune notification"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Aucune nouvelle notification"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"La limitation des notifications est maintenant activée"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Les alertes et le volume de l\'appareil sont réduits automatiquement pendant 2 minutes maximum quand vous recevez trop de notifications à la fois."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Désactiver"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Déverrouiller pour voir anciennes notifications"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'appli à droite ou en dessous avec l\'écran partagé"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passez à l\'appli à gauche ou au-dessus avec l\'écran partagé"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"En mode écran partagé : Remplacer une appli par une autre"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Déplacer la fenêtre active d\'un écran à l\'autre"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Saisie"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Passer à la langue suivante"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Revenir à la langue précédente"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utilisez moins de <xliff:g id="LENGTH">%1$d</xliff:g> caractères"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Conversation ouverte"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversation"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Appuyez sur une conversation pour l\'ajouter à votre écran d\'accueil"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Pour une résolution plus élevée, retournez le téléphone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable qui est déplié"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable qui est retourné"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,33 +1418,26 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis clavier"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personnaliser les raccourcis clavier"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Appuyez sur une touche pour attribuer un raccourci"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Rechercher des raccourcis"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Aucun résultat de recherche"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icône de touche d\'action ou de méta-touche"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Icône Plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personnaliser"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"OK"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Poignée de déplacement"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Paramètres du clavier"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Définir un raccourci"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuler"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Appuyez sur la touche"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinaison de touches déjà utilisée. Essayez une autre touche."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide du clavier"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Apprenez à utiliser les raccourcis clavier"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string>
- <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Découvrir les gestes au pavé tactile"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Découvrez les gestes au pavé tactile"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviguer à l\'aide de votre clavier et de votre pavé tactile"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Découvrir les gestes au pavé tactile, les raccourcis clavier et plus encore"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Retour"</string>
@@ -1452,7 +1447,7 @@
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Balayez vers la gauche ou la droite avec trois doigts sur le pavé tactile"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bravo !"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Vous avez appris le geste pour revenir en arrière."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Vous avez appris le geste pour revenir en arrière"</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Retour à l\'accueil"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Balayez vers le haut avec trois doigts sur le pavé tactile"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bravo !"</string>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index d0853f4a3185..ffceb0dfe776 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Désactivé"</item>
<item msgid="3028994095749238254">"Activé"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Indisponible"</item>
+ <item msgid="6419996398343291862">"Désactivé"</item>
+ <item msgid="5908720590832378783">"Activé"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index ebc19bd883f7..398360689afe 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiófonos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Non se pode axustar o brillo\n porque o controla a aplicación principal"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Xirar automaticamente"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Xirar pantalla automaticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localización"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic para vincular un novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Non se puido actualizar a configuración predeterminada"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Configuración predeterminada"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Elemento seleccionado"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtítulos instantáneos"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Queres desbloquear o micrófono do dispositivo?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Queres desbloquear a cámara do dispositivo?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Queres desbloquear a cámara e o micrófono do dispositivo?"</string>
@@ -578,7 +578,7 @@
<string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"Cambio de aplicación"</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"O teu administrador de TI bloqueou esta aplicación"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"A política do dispositivo desactivou a opción de capturar a pantalla"</string>
- <string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todo"</string>
+ <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Xestionar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
<string name="notification_settings_button_description" msgid="2441994740884163889">"Configuración de notificacións"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Non hai notificacións"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Non hai notificacións novas"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Agora a opción Amainar notificacións está activada"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Ao recibir moitas notificacións, o volume e as alertas redúcense automaticamente ata dous minutos."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desactivar"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver máis notificacións"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar á aplicación da dereita ou de abaixo coa pantalla dividida"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar á aplicación da esquerda ou de arriba coa pantalla dividida"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"En modo de pantalla dividida: Substituír unha aplicación por outra"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mover ventá activa entre pantallas"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Cambiar ao seguinte idioma"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Cambiar ao idioma anterior"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utiliza menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Toca unha conversa para engadila á pantalla de inicio"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Dálle a volta ao teléfono para gozar dunha maior resolución"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pregable abríndose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pregable xirando"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dispositivo pregado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dispositivo despregado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atallos de teclado"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar os atallos de teclado"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Preme a tecla para asignar o atallo"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Busca atallos"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Non hai resultados de busca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icona da tecla Meta ou de acción"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Icona do signo máis"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Feito"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona de despregar"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configuración do teclado"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Definir atallo"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Preme unha tecla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Xa se está usando esta combinación de teclas. Proba con outra."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega co teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende a usar os atallos de teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega co panel táctil"</string>
diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
index 18ad3df0a8c1..7889983f193b 100644
--- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desactivados"</item>
<item msgid="3028994095749238254">"Activados"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Non dispoñible"</item>
+ <item msgid="6419996398343291862">"Opción desactivada"</item>
+ <item msgid="5908720590832378783">"Opción activada"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d5e7ca4177aa..89012697cfac 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ઇનપુટ"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"સાંભળવામાં મદદ આપતા યંત્રો"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ચાલુ કરી રહ્યાં છીએ…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"બ્રાઇટનેસ ગોઠવી શકતા નથી કારણ કે તે\n લોકપ્રિય ઍપ દ્વારા નિયંત્રિત કરવામાં આવી રહી છે"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ઑટો રોટેટ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ઑટો રોટેટ સ્ક્રીન"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"લોકેશન"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"નવા ડિવાઇસ સાથે જોડાણ કરવા માટે ક્લિક કરો"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"પ્રીસેટ અપડેટ કરી શક્યા નથી"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"પ્રીસેટ"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"પસંદ કરી છે"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ટૂલ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"લાઇવ કૅપ્શન"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"નોંધ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ડિવાઇસના માઇક્રોફોનને અનબ્લૉક કરીએ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ડિવાઇસના કૅમેરાને અનબ્લૉક કરીએ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ડિવાઇસના કૅમેરા અને માઇક્રોફોનને અનબ્લૉક કરીએ?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે જમણી બાજુ કે નીચેની ઍપ પર સ્વિચ કરો"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે ડાબી બાજુની કે ઉપરની ઍપ પર સ્વિચ કરો"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"વિભાજિત સ્ક્રીન દરમિયાન: એક ઍપને બીજી ઍપમાં બદલો"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"સક્રિય વિન્ડોને ડિસ્પ્લેની વચ્ચે ખસેડો"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ઇનપુટ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"આગલી ભાષા પર સ્વિચ કરો"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"પાછલી ભાષા પર સ્વિચ કરો"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> કરતાં ઓછા અક્ષરનો ઉપયોગ કરો"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"વાતચીત ખોલો"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"વાતચીતના વિજેટ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"તમારી હોમ સ્ક્રીનમાં વાતચીત ઉમેરવા માટે તેના પર ટૅપ કરો"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"વધુ રિઝોલ્યુશન માટે, ફોનને ફ્લિપ કરો"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ અનફોલ્ડ કરવામાં આવી રહ્યું છે"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ ફ્લિપ કરવામાં આવી રહ્યું છે"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ફોલ્ડ કરેલું"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"અનફોલ્ડ કરેલું"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ઍક્સેસિબિલિટી"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"કીબોર્ડ શૉર્ટકટ"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"કીબોર્ડ શૉર્ટકટને કસ્ટમાઇઝ કરો"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"શૉર્ટકટ સોંપવા માટે દી દબાવો"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"શૉર્ટકટ શોધો"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"કોઈ શોધ પરિણામો નથી"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ઍક્શન અથવા મેટા કીનું આઇકન"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"પ્લસનું આઇકન"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"કસ્ટમાઇઝ કરો"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"થઈ ગયું"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\'મોટું કરો\'નું આઇકન"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"અથવા"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ઑબ્જેક્ટ ખેંચવાનું હૅન્ડલ"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"કીબોર્ડના સેટિંગ"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"શૉર્ટકટ સેટ કરો"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"રદ કરો"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"કી દબાવો"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"કી સંયોજન પેહલેથી ઉપયોગમાં છે. અન્ય કી અજમાવી જુઓ."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"તમારા કીબોર્ડ વડે નૅવિગેટ કરો"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"કીબોર્ડ શૉર્ટકર્ટ જાણો"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"તમારા ટચપૅડ વડે નૅવિગેટ કરો"</string>
@@ -1459,11 +1455,11 @@
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"તાજેતરની ઍપ જુઓ"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"તમારા ટચપૅડ પર ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ખૂબ સરસ કામ!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"તમે \"તાજેતરની ઍપ જુઓ\" સંકેત પૂર્ણ કર્યો."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"તમે \'તાજેતરની ઍપ જુઓ\' સંકેત પૂર્ણ કર્યો."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"બધી ઍપ જુઓ"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"વાહ!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"તમે \"બધી ઍપ જુઓ\" સંકેત પૂર્ણ કર્યો"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"તમે \'બધી ઍપ જુઓ\' સંકેત પૂર્ણ કર્યો"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"કીબોર્ડની બૅકલાઇટ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dમાંથી %1$d લેવલ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ઘરેલું સાધનોના નિયંત્રણો"</string>
diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
index e6202321148f..8c8d5f649407 100644
--- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"બંધ છે"</item>
<item msgid="3028994095749238254">"ચાલુ છે"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"અનુપલબ્ધ"</item>
+ <item msgid="6419996398343291862">"બંધ"</item>
+ <item msgid="5908720590832378783">"ચાલુ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index cad756d0cebb..241e2e630013 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -109,12 +109,12 @@
<string name="screenrecord_title" msgid="4257171601439507792">"स्क्रीन रिकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
- <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"क्या आपको स्क्रीन रिकॉर्ड करनी है?"</string>
- <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"एक ऐप्लिकेशन की रिकॉर्डिंग करें"</string>
+ <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"क्या आपको स्क्रीन को रिकॉर्ड करना है?"</string>
+ <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"एक ऐप्लिकेशन रिकॉर्ड करें"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"पूरी स्क्रीन रिकॉर्ड करें"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"पूरी स्क्रीन रिकॉर्ड करें: %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"पूरी स्क्रीन रिकॉर्ड करते समय, स्क्रीन पर दिखने वाली हर चीज़ रिकॉर्ड की जाती है. इसलिए पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, डिवाइस पर चल रहे ऑडियो और वीडियो, और फ़ोटो जैसी चीज़ों को लेकर सावधानी बरतें."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"किसी ऐप्लिकेशन को रिकॉर्ड करने के दौरान, उस पर दिख रहा कॉन्टेंट या चल रहा मीडिया दूसरी स्क्रीन पर भी रिकॉर्ड होता है. इसलिए, रिकॉर्ड करते समय पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, ऑडियो, और वीडियो को लेकर सावधानी बरतें."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"किसी ऐप्लिकेशन को रिकॉर्ड करने के दौरान, उस पर दिख रहा कॉन्टेंट या चल रहा मीडिया भी रिकॉर्ड होता है. इसलिए, रिकॉर्ड करते समय पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, ऑडियो, और वीडियो को लेकर सावधानी बरतें."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"स्क्रीन रिकॉर्ड करें"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"रिकॉर्ड करने के लिए ऐप्लिकेशन चुनें"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"ऑडियो रिकॉर्ड करें"</string>
@@ -125,7 +125,7 @@
<string name="screenrecord_continue" msgid="4055347133700593164">"शुरू करें"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"स्क्रीन को रिकॉर्ड किया जा रहा है"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"स्क्रीन और ऑडियो, दोनों रिकॉर्ड हो रहे हैं"</string>
- <string name="screenrecord_taps_label" msgid="1595690528298857649">"स्क्रीन को कहां-कहां छुआ गया, यह दिखाएं"</string>
+ <string name="screenrecord_taps_label" msgid="1595690528298857649">"दिखाएं कि स्क्रीन पर कहां-कहां टच किया जा रहा है"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"रोकें"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेयर करें"</string>
<string name="screenrecord_save_title" msgid="1886652605520893850">"स्क्रीन रिकॉर्डिंग सेव की गई"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"कान की मशीनें"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ब्लूटूथ चालू हो रहा है…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"स्क्रीन की रोशनी को एडजस्ट नहीं किया जा सकता, क्योंकि\n इसे टॉप ऐप्लिकेशन कंट्रोल कर रहा है"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रीन का अपने-आप दिशा बदलना (ऑटो-रोटेट)"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"जगह की जानकारी"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नया डिवाइस जोड़ने के लिए क्लिक करें"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"प्रीसेट अपडेट नहीं किया जा सका"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"प्रीसेट"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"चुना गया"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"टूल"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"लाइव कैप्शन"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"नोट"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"क्या आपको माइक्रोफ़ोन का ऐक्सेस अनब्लॉक करना है?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"क्या आपको कैमरे का ऐक्सेस अनब्लॉक करना है?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"क्या आप डिवाइस का कैमरा और माइक्रोफ़ोन अनब्लॉक करना चाहते हैं?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"बंद है"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"सेट नहीं है"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"सेटिंग में जाकर मैनेज करें"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{कोई मोड चालू नहीं है}=1{{mode} चालू है}one{# मोड चालू है}other{# मोड चालू हैं}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{कोई मोड चालू नहीं है}=1{{mode} मोड चालू है}one{# मोड चालू है}other{# मोड चालू हैं}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"आपको अलार्म, रिमाइंडर, इवेंट और चुनिंदा कॉल करने वालों के अलावा किसी और तरह से (आवाज़ करके और थरथरा कर ) परेशान नहीं किया जाएगा. आप फिर भी संगीत, वीडियो और गेम सहित अपना चुना हुआ सब कुछ सुन सकते हैं."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"आपको अलार्म छोड़कर दूसरी आवाज़ों और कंपनों से परेशान नहीं किया जाएगा. आपको अब भी संगीत, वीडियो और गेम सहित वह सब कुछ सुनाई देगा जो आपने चलाने के लिए चुना है."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"अपनी पसंद के मुताबिक बनाएं"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"अभी शुरू करें"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"कोई सूचना नहीं है"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"कोई नई सूचना नहीं है"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"लगातार सूचनाएं आने पर आवाज़ कम करने की सेटिंग चालू है"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"एक साथ कई सूचनाएं मिलने पर, डिवाइस में सूचनाओं से होने वाली आवाज़ और सूचनाएं, दो मिनट के लिए अपने-आप कम हो जाएंगी."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"बंद करें"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"पुरानी सूचाएं देखने के लिए अनलॉक करें"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन पर, दाईं ओर या नीचे के ऐप पर स्विच करने के लिए"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन पर, बाईं ओर या ऊपर के ऐप पर स्विच करने के लिए"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रीन के दौरान: एक ऐप्लिकेशन को दूसरे ऐप्लिकेशन से बदलें"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ऐक्टिव विंडो को एक से दूसरे डिसप्ले पर स्विच करें"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"इनपुट"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"अगली भाषा पर स्विच करने के लिए"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"पिछली भाषा पर स्विच करने के लिए"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> वर्ण से कम इस्तेमाल करें"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"बातचीत वाला विजेट"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"किसी बातचीत को होम स्क्रीन पर जोड़ने के लिए, उस बातचीत पर टैप करें"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"बेहतर रिज़ॉल्यूशन वाली फ़ोटो खींचने के लिए, फ़ोन को फ़्लिप करें"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फ़ोल्ड किया जा सकने वाला डिवाइस अनफ़ोल्ड किया जा रहा है"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फ़ोल्ड किया जा सकने वाला डिवाइस पलटा जा रहा है"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"डिवाइस फ़ोल्ड किया गया"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"डिवाइस अनफ़ोल्ड किया गया"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,55 +1418,48 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सुलभता"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"कीबोर्ड शॉर्टकट को पसंद के मुताबिक बनाएं"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"शॉर्टकट असाइन करने के लिए बटन दबाएं"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शॉर्टकट खोजें"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"खोज का कोई नतीजा नहीं मिला"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"छोटा करने का आइकॉन"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ऐक्शन या मेटा बटन का आइकॉन"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"प्लस का आइकॉन"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"पसंद के मुताबिक बनाएं"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"हो गया"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"बड़ा करने का आइकॉन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"या"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"खींचकर छोड़ने वाला हैंडल"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"कीबोर्ड सेटिंग"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"शॉर्टकट सेट करें"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द करें"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"बटन दबाएं"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"बटन का यह कॉम्बिनेशन पहले से इस्तेमाल किया जा रहा है. कोई दूसरा कॉम्बिनेशन आज़माएं."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"कीबोर्ड का इस्तेमाल करके नेविगेट करें"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट के बारे में जानें"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचपैड का इस्तेमाल करके नेविगेट करें"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"टचपैड से जुड़े जेस्चर के बारे में जानें"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"कीबोर्ड और टचपैड का इस्तेमाल करके नेविगेट करें"</string>
- <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपैड पर हाथ के जेस्चर, कीबोर्ड शॉर्टकट वगैरह के बारे में जानें"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपैड से जुड़े जेस्चर, कीबोर्ड शॉर्टकट वगैरह के बारे में जानें"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"वापस जाएं"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होम स्क्रीन पर जाएं"</string>
<string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"हो गया"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"वापस जाएं"</string>
- <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"अपने टचपैड पर तीन उंगलियों का इस्तेमाल करके, बाईं या दाईं ओर स्वाइप करें"</string>
+ <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"अपने टचपैड पर तीन उंगलियों से बाईं या दाईं ओर स्वाइप करें"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"बढ़िया!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"अब आपने जान लिया है कि हाथ का जेस्चर इस्तेमाल करके, पिछली स्क्रीन पर वापस कैसे जाएं."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, पिछली स्क्रीन पर वापस जाने का तरीका पता चल गया है."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"होम स्क्रीन पर जाएं"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"बहुत बढ़िया!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"अब आपको हाथ के जेस्चर का इस्तेमाल करके होम स्क्रीन पर जाने का तरीका पता चल गया है"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और फिर होल्ड करें"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और दबाकर रखें"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"बहुत बढ़िया!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"आपने हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने के लिए, हाथ के जेस्चर के बारे में जान लिया है."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने का तरीका पता चल गया है."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"सभी ऐप्लिकेशन देखें"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"अपने कीबोर्ड पर ऐक्शन बटन दबाएं"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"बहुत खूब!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"अब आपको इस बारे में जानकारी है कि सभी ऐप्लिकेशन देखने के लिए, हाथ के जेस्चर का इस्तेमाल कैसे किया जाता है"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, सभी ऐप्लिकेशन देखने का तरीका पता चल गया है"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड की बैकलाइट"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d में से %1$d लेवल"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string>
diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
index 6aa90789c246..69a4e4daa355 100644
--- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"बंद हैं"</item>
<item msgid="3028994095749238254">"चालू हैं"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"उपलब्ध नहीं है"</item>
+ <item msgid="6419996398343291862">"बंद है"</item>
+ <item msgid="5908720590832378783">"चालू है"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 3a01d94ef510..a179649922d2 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušna pomagala"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Svjetlina se ne može prilagoditi jer njome\n upravlja aplikacija pri vrhu"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko zakretanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko zakretanje zaslona"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili novi uređaj"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje unaprijed definiranih postavki nije uspjelo"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Unaprijed definirana postavka"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Odabrano"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alati"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Automatski titlovi"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Napomena"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite li deblokirati mikrofon uređaja?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite li deblokirati kameru uređaja?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite li deblokirati kameru i mikrofon uređaja?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prelazak na aplikaciju zdesna ili ispod uz podijeljeni zaslon"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prelazak na aplikaciju slijeva ili iznad uz podijeljeni zaslon"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Tijekom podijeljenog zaslona: zamijeni aplikaciju drugom"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Premještanje aktivnog prozora između zaslona"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Unos"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Prelazak na sljedeći jezik"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Prelazak na prethodni jezik"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Upotrijebite manje od ovoliko znakova: <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgeti razgovora"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Dodirnite razgovor da biste ga dodali na početni zaslon"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za višu razlučivost okrenite telefon"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rasklopljen sklopivi uređaj"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Okretanje sklopivog uređaja sa svih strana"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tipkovni prečaci"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodba tipkovnih prečaca"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite tipku da biste dodijelili prečac"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona tipke za radnju odnosno meta tipka"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona plusa"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Prilagodi"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Gotovo"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Marker za povlačenje"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Postavke tipkovnice"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Postavite prečac"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Odustani"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacija tipki već se upotrebljava. Pokušajte s drugom tipkom."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tipkovnice"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tipkovnim prečacima"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string>
@@ -1451,25 +1447,25 @@
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Natrag"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prijeđite ulijevo ili udesno trima prstima na dodirnoj podlozi"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Odlično!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Izvršili ste pokret za povratak."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Napravili ste pokret za povratak."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Na početnu stranicu"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prijeđite prema gore trima prstima na dodirnoj podlozi"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Sjajno!"</string>
- <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Izvršili ste pokret za otvaranje početnog zaslona"</string>
+ <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Napravili ste pokret za otvaranje početnog zaslona"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Pregled nedavnih aplikacija"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Prijeđite prema gore trima prstima na dodirnoj podlozi i zadržite pritisak"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavno korištenih aplikacija."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Napravili ste pokret za prikaz nedavno korištenih aplikacija."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Prikaži sve aplikacije"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku za radnju na tipkovnici"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Izvrsno!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvršili ste pokret za prikaz svih aplikacija"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Napravili ste pokret za prikaz svih aplikacija"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tipkovnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Razina %1$d od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Upravljanje uređajima"</string>
<string name="home_controls_dream_description" msgid="4644150952104035789">"Brzo upravljajte uređajima putem čuvara zaslona"</string>
<string name="volume_undo_action" msgid="5815519725211877114">"Poništi"</string>
- <string name="back_edu_toast_content" msgid="4530314597378982956">"Za povratak prijeđite ulijevo ili udesno trima prstima na dodirnoj podlozi"</string>
+ <string name="back_edu_toast_content" msgid="4530314597378982956">"Za povratak trima prstima prijeđite ulijevo ili udesno na dodirnoj podlozi"</string>
<string name="home_edu_toast_content" msgid="3381071147871955415">"Da biste se vratili na početni zaslon, prijeđite prema gore trima prstima na dodirnoj podlozi."</string>
<string name="overview_edu_toast_content" msgid="5797030644017804518">"Za prikaz nedavnih aplikacija prijeđite prema gore trima prstima i zadržite pritisak na dodirnoj podlozi"</string>
<string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Za prikaz svojih svih aplikacija pritisnite tipku za radnju na tipkovnici"</string>
diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
index 3f8841afb4f2..2401e4a2fc37 100644
--- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Isključeno"</item>
<item msgid="3028994095749238254">"Uključeno"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nedostupno"</item>
+ <item msgid="6419996398343291862">"Isključeno"</item>
+ <item msgid="5908720590832378783">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c9e20f8359be..4b5b9162b01b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Bevitel"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hallókészülék"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Bekapcsolás…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Nem lehet módosítani a fényerőt, mert a felső alkalmazás\n vezérli"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kattintson új eszköz párosításához"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nem sikerült frissíteni a beállításkészletet"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Beállításkészlet"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Kiválasztva"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Eszközök"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Élő feliratozás"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Megjegyzés"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Feloldja az eszköz mikrofonjának letiltását?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Feloldja az eszköz kamerájának letiltását?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Feloldja az eszköz kamerájának és mikrofonjának letiltását?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Ki"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Nincs beállítva"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"A Beállítások között kezelheti"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nincs aktív mód}=1{A(z) {mode} aktív}other{# mód aktív}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nincs aktív mód}=1{{mode} aktív}other{# mód aktív}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Az Ön által meghatározott ébresztéseken, emlékeztetőkön, eseményeken és hívókon kívül nem fogja Önt más hang vagy rezgés megzavarni. Továbbra is lesz hangjuk azoknak a tartalmaknak, amelyeket Ön elindít, például zenék, videók és játékok."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Az ébresztéseken kívül nem fogja Önt más hang és rezgés megzavarni. Továbbra is lesz hangjuk azoknak a tartalmaknak, amelyeket Ön elindít, például zenék, videók és játékok."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Személyre szabás"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Indítás most"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nincs értesítés"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nincsenek új értesítések"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Az értesítések befagyasztása mostantól be van kapcsolva"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Az eszköz hangerejét és értesítéseit a rendszer automatikusan legfeljebb két percig csökkenti, ha egyszerre túl sok értesítést kap."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Igen"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"A régebbiek feloldás után láthatók"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Váltás a jobb oldalt, illetve lent lévő appra osztott képernyő esetén"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Váltás a bal oldalt, illetve fent lévő appra osztott képernyő esetén"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Osztott képernyőn: az egyik alkalmazás lecserélése egy másikra"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Aktív ablak áthelyezése egyik kijelzőről a másikra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Bevitel"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Váltás a következő nyelvre"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Váltás az előző nyelvre"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Legfeljebb <xliff:g id="LENGTH">%1$d</xliff:g> karaktert használhat"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Beszélgetés megnyitása"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Beszélgetési modulok"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Koppintson a kívánt beszélgetésre a kezdőképernyőre való felvételhez"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"A nagyobb felbontás érdekében fordítsa meg a telefont"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Összehajtható eszköz kihajtása"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Összehajtható eszköz körbeforgatása"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"összehajtva"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kihajtva"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kisegítő lehetőségek"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Billentyűparancsok"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"A billentyűparancsok személyre szabása"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Nyomja meg a billentyűt a parancsikon hozzárendeléséhez"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Billentyűparancsok keresése"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nincsenek keresési találatok"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Művelet vagy Meta billentyű ikonja"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Pluszikon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Személyre szabás"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Kész"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kibontás ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vagy"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Fogópont"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Billentyűzetbeállítások"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Billentyűparancs beállítása"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Mégse"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nyomja le a billentyűt"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"A billentyűkombináció már használatban van. Próbálkozzon másik kulccsal."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigáció a billentyűzet segítségével"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Billentyűparancsok megismerése"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigálás az érintőpaddal"</string>
diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
index 76b3410ab6cb..8911fe9e2f8d 100644
--- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Ki"</item>
<item msgid="3028994095749238254">"Be"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nem áll rendelkezésre"</item>
+ <item msgid="6419996398343291862">"Ki"</item>
+ <item msgid="5908720590832378783">"Be"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 1d46bc2c86da..a06209867663 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -116,7 +116,7 @@
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Երբ դուք տեսագրում եք ամբողջ էկրանը, էկրանին ցուցադրվող ամեն ինչ տեսագրվում է։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Երբ դուք որևէ հավելված եք տեսագրում, հավելվածում ցուցադրվող կամ նվագարկվող ամեն ինչ տեսագրվում է։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Տեսագրել էկրանը"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Հավելվածի ընտրություն՝ տեսագրելու համար"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Հավելված ընտրեք՝ տեսագրելու համար"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Ձայնագրել"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Սարքի ձայները"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Ձեր սարքի ձայները, օրինակ՝ երաժշտությունը, զանգերն ու զանգերանգները"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Մուտքագրում"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Լսողական սարք"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Միացում…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Հնարավոր չէ կարգավորել պայծառությունը, քանի որ այն\n կառավարվում է գլխավոր հավելվածի կողմից"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ինքնապտտում"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ավտոմատ պտտել էկրանը"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Տեղորոշում"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Սեղմեք՝ նոր սարք զուգակցելու համար"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Չհաջողվեց թարմացնել կարգավորումների հավաքածուն"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Կարգավորումների հավաքածու"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Ընտրված է"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Գործիքներ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Կենդանի ենթագրեր"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Նշում"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Արգելահանե՞լ սարքի խոսափողը"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Արգելահանե՞լ սարքի տեսախցիկը"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Արգելահանե՞լ սարքի տեսախցիկը և խոսափողը"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Անջատված է"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Կարգավորված չէ"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Կառավարել կարգավորումներում"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ակտիվ ռեժիմներ չկան}=1{{mode} ռեժիմ ակտիվ է}one{# ռեժիմ ակտիվ է}other{# ռեժիմ ակտիվ է}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ակտիվ ռեժիմ չկա}=1{{mode} ռեժիմն ակտիվ է}one{# ռեժիմ ակտիվ է}other{# ռեժիմ ակտիվ է}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Ձայները և թրթռոցները չեն անհանգստացնի ձեզ, բացի ձեր կողմից նշված զարթուցիչները, հիշեցումները, միջոցառումների ծանուցումները և զանգերը։ Դուք կլսեք ձեր ընտրածի նվագարկումը, այդ թվում՝ երաժշտություն, տեսանյութեր և խաղեր:"</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Ձայները և թրթռոցները, բացի զարթուցիչներից, չեն անհանգստացնի ձեզ: Դուք կլսեք ձեր ընտրածի նվագարկումը, այդ թվում՝ երաժշտություն, տեսանյութեր և խաղեր:"</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Հարմարեցնել"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Անցեք աջ կողմի կամ ներքևի հավելվածին տրոհված էկրանի միջոցով"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Անցեք աջ կողմի կամ վերևի հավելվածին տրոհված էկրանի միջոցով"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Տրոհված էկրանի ռեժիմում մեկ հավելվածը փոխարինել մյուսով"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Տեղափոխել ակտիվ պատուհանը էկրանների միջև"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Ներածում"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Անցնել հաջորդ լեզվին"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Անցնել նախորդ լեզվին"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Օգտագործեք մինչև <xliff:g id="LENGTH">%1$d</xliff:g> նիշ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Զրույցի վիջեթներ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Հպեք զրույցին՝ այն հիմնական էկրանին ավելացնելու համար"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Ավելի մեծ լուծաչափի համար շրջեք հեռախոսը"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ծալովի սարք՝ բացված վիճակում"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Ծալովի սարք՝ շրջված վիճակում"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ծալված"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"բացված"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Հատուկ գործառույթներ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Ստեղնային դյուրանցումներ"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Կարգավորեք ստեղնային դյուրանցումներ"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Սեղմեք որևէ ստեղն՝ դյուրանցում նշանակելու համար"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Դյուրանցումների որոնում"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Որոնման արդյունքներ չկան"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ծալել պատկերակը"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Գործողության կամ Meta ստեղնի պատկերակ"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Պլյուս պատկերակ"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Կարգավորել"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Պատրաստ է"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ծավալել պատկերակը"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"կամ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Տեղափոխման նշիչ"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ստեղնաշարի կարգավորումներ"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ստեղծել դյուրանցում"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Չեղարկել"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Սեղմեք որևէ ստեղն"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ստեղների համակցությունն արդեն օգտագործվում է։ Ընտրեք այլ ստեղն։"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Կողմնորոշվեք ձեր ստեղնաշարի օգնությամբ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Սովորեք օգտագործել ստեղնային դյուրանցումները"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Կողմնորոշվեք ձեր հպահարթակի օգնությամբ"</string>
@@ -1458,7 +1454,7 @@
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Դուք սովորեցիք հիմնական էկրան անցնելու ժեստը"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Դիտել վերջին հավելվածները"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Երեք մատով սահեցրեք վերև և սեղմած պահեք հպահարթակին"</string>
- <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Կեցցե՛ք։"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Կեցցե՛ք"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Դուք կատարեցիք վերջին օգտագործված հավելվածների դիտման ժեստը։"</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Ինչպես դիտել բոլոր հավելվածները"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Սեղմեք գործողության ստեղնը ստեղնաշարի վրա"</string>
diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
index ce930c39aa83..f2b09e059429 100644
--- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Անջատված է"</item>
<item msgid="3028994095749238254">"Միացված է"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Հասանելի չէ"</item>
+ <item msgid="6419996398343291862">"Անջատված է"</item>
+ <item msgid="5908720590832378783">"Միացված է"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 1535314317a8..cf9b093a1d43 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Alat bantu dengar"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Mengaktifkan…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Tidak dapat menyesuaikan kecerahan karena sedang\n dikontrol oleh aplikasi atas"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Putar Otomatis"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Putar layar otomatis"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menyambungkan perangkat baru"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Tidak dapat memperbarui preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Dipilih"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alat"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Teks Otomatis"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Catatan"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Berhenti memblokir mikrofon perangkat?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Berhenti memblokir kamera perangkat?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Berhenti memblokir kamera dan mikrofon perangkat?"</string>
@@ -565,7 +565,7 @@
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Transmisikan seluruh layar"</string>
<string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"JIka Anda mentransmisikan seluruh layar, semua hal yang ada di layar Anda akan terlihat. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
<string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Jika Anda mentransmisikan aplikasi, semua hal yang ditampilkan atau diputar di aplikasi tersebut akan terlihat. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
- <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Layar Cast"</string>
+ <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Transmisikan layar"</string>
<string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Pilih aplikasi yang akan ditransmisikan"</string>
<string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Mulai berbagi?"</string>
<string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Jika Anda membagikan, merekam, atau mentransmisikan, Android akan memiliki akses ke semua hal yang ditampilkan di layar atau yang diputar di perangkat Anda. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Mulai sekarang"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Tidak ada notifikasi"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Tidak ada notifikasi baru"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Pengurangan suara dan getaran notifikasi kini aktif"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Saat Anda menerima terlalu banyak notifikasi sekaligus, volume dan getaran perangkat akan otomatis dikurangi hingga selama 2 menit."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Nonaktifkan"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Buka kunci untuk melihat notifikasi lama"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Beralih ke aplikasi di bagian kanan atau bawah saat menggunakan layar terpisah"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Beralih ke aplikasi di bagian kiri atau atas saat menggunakan layar terpisah"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Dalam layar terpisah: ganti salah satu aplikasi dengan yang lain"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Memindahkan jendela aktif dari satu layar ke layar lainnya"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Beralih ke bahasa berikutnya"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Beralih ke bahasa sebelumnya"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gunakan kurang dari <xliff:g id="LENGTH">%1$d</xliff:g> karakter"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Membuka percakapan"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widget Percakapan"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Ketuk percakapan untuk menambahkannya ke Layar utama"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Untuk resolusi lebih tinggi, balik ponsel"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Perangkat foldable sedang dibentangkan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Perangkat foldable sedang dibalik"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ditutup"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dibuka"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,30 +1418,23 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aksesibilitas"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan keyboard"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Menyesuaikan pintasan keyboard"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tekan tombol untuk menetapkan pintasan"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Telusuri pintasan"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Tidak ada hasil penelusuran"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikon tombol Tindakan atau Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikon plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Sesuaikan"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Selesai"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon luaskan"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handel geser"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Setelan Keyboard"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
- <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Menavigasi menggunakan keyboard"</string>
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Setel pintasan"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Batal"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tekan tombol"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinasi tombol sudah digunakan. Coba tombol lain."</string>
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Menggunakan keyboard untuk navigasi"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Pelajari pintasan keyboard"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Menavigasi menggunakan touchpad"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Pelajari gestur touchpad"</string>
@@ -1451,8 +1446,8 @@
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Geser ke kiri atau kanan menggunakan tiga jari di touchpad"</string>
- <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bagus!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah menyelesaikan gestur kembali."</string>
+ <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Sip!"</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah menyelesaikan gestur untuk kembali."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Buka layar utama"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Geser ke atas dengan tiga jari di touchpad"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bagus!"</string>
@@ -1463,7 +1458,7 @@
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah menyelesaikan gestur untuk melihat aplikasi terbaru."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua aplikasi"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan tombol tindakan di keyboard"</string>
- <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bagus!"</string>
+ <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Oke!"</string>
<string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Anda telah menyelesaikan gestur untuk melihat semua aplikasi"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Lampu latar keyboard"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Tingkat %1$d dari %2$d"</string>
diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml
index 5570edb557d4..7462ff6a98bd 100644
--- a/packages/SystemUI/res/values-in/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Nonaktif"</item>
<item msgid="3028994095749238254">"Aktif"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Tidak tersedia"</item>
+ <item msgid="6419996398343291862">"Nonaktif"</item>
+ <item msgid="5908720590832378783">"Aktif"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index edead8fdc433..fe32aba3d75b 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -113,10 +113,10 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Taka upp eitt forrit"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Taka upp allan skjáinn"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Taka upp allan skjáinn: %s"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Þegar þú tekur upp allan skjáinn verður allt sem er sýnilegt á skjánum tekið upp. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Þegar þú tekur upp forrit verður allt sem er sýnilegt eða spilað í forritinu tekið upp. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Þegar þú tekur upp allan skjáinn verður allt sem er sýnilegt á skjánum tekið upp. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Þegar þú tekur upp forrit verður allt sem er sýnilegt eða spilað í forritinu tekið upp. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Taka upp skjá"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Velja forrit til að taka upp"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Veldu forrit til að taka upp"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Taka upp hljóð"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Hljóð tækis"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Hljóð úr tækinu á borð við tónlist, símtöl og hringitóna"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Inntak"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Heyrnartæki"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Kveikir…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Ekki er hægt að breyta birtustiginu vegna þess að \n efsta forritið stjórnar því"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Sjálfvirkur snúningur"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Snúa skjá sjálfkrafa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Staðsetning"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Smelltu til að para nýtt tæki"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Tókst ekki að uppfæra forstillingu"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forstilling"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valið"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Verkfæri"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Skjátextar í rauntíma"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Glósa"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Opna fyrir hljóðnema tækisins?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Opna fyrir myndavél tækisins?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Opna fyrir myndavél og hljóðnema tækisins?"</string>
@@ -555,8 +555,8 @@
<string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Deila öllum skjánum"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
- <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Þegar þú deilir öllum skjánum verður allt á skjánum sýnilegt <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Þegar þú deilir forriti er allt sem sést eða er spilað í því forriti sýnilegt <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Þegar þú deilir öllum skjánum verður allt á skjánum sýnilegt <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Þegar þú deilir forriti er allt sem sést eða er spilað í því forriti sýnilegt <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deila skjá"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> slökkti á þessum valkosti"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Velja forrit til að deila"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skiptu í forrit til hægri eða fyrir neðan þegar skjáskipting er notuð"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skiptu í forrit til vinstri eða fyrir ofan þegar skjáskipting er notuð"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Í skjáskiptingu: Skipta forriti út fyrir annað forrit"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Færa virkan glugga á milli skjáa"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Innsláttur"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Skipta yfir í næsta tungumál"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Skipta yfir í fyrra tungumál"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Notaðu færri en <xliff:g id="LENGTH">%1$d</xliff:g> stafi"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Opna samtal"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Samtalsgræjur"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Ýttu á samtal til að bæta því á heimaskjáinn"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Snúðu símanum til að fá betri upplausn"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Samanbrjótanlegt tæki opnað"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Samanbrjótanlegu tæki snúið við"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"samanbrotið"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opið"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aðgengi"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Flýtilyklar"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sérsníddu flýtilykla"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Ýttu á lykil til að stilla flýtileið"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leita að flýtileiðum"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Engar leitarniðurstöður"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Tákn lýsilykils (aðgerðarlykils)"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plústákn"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Sérsníða"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Lokið"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Stækka tákn"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eða"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Dragkló"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Stillingar lyklaborðs"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Stilltu flýtileið"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Hætta við"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Ýttu á lykil"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Lyklasamsetning er þegar í notkun. Prófaðu annan lykil."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Flettu með því að nota lyklaborðið"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Kynntu þér flýtilykla"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Flettu með því að nota snertiflötinn"</string>
diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml
index 893ab6ce3bb6..df3bcf9f1f9b 100644
--- a/packages/SystemUI/res/values-is/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Slökkt"</item>
<item msgid="3028994095749238254">"Kveikt"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Ekki í boði"</item>
+ <item msgid="6419996398343291862">"Slökkt"</item>
+ <item msgid="5908720590832378783">"Kveikt"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index d7a279be03ea..a66ea91eb396 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingresso"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Apparecchi acustici"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Attivazione…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Impossibile regolare la luminosità perché è\n controllata dall\'app in primo piano"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotazione automatica"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotazione automatica dello schermo"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Posizione"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic per accoppiare un nuovo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Impossibile aggiornare preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selezionato"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Strumenti"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sottotitoli in tempo reale"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vuoi sbloccare il microfono del dispositivo?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vuoi sbloccare la fotocamera del dispositivo?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vuoi sbloccare la fotocamera e il microfono del dispositivo?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Avvia adesso"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nessuna notifica"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nessuna nuova notifica"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"L\'attenuazione delle notifiche è ora attiva"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e avvisi vengono ridotti automaticamente per un massimo di 2 minuti quando ricevi troppe notifiche contemporaneamente."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Disattiva"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Sblocca per vedere le notifiche meno recenti"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passa all\'app a destra o sotto mentre usi lo schermo diviso"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passa all\'app a sinistra o sopra mentre usi lo schermo diviso"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Con lo schermo diviso: sostituisci un\'app con un\'altra"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Sposta la finestra attiva tra gli schermi"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Inserimento"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Passa alla lingua successiva"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Passa alla lingua precedente"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Usa meno di <xliff:g id="LENGTH">%1$d</xliff:g> caratteri"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Apri conversazione"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widget di conversazione"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tocca una conversazione per aggiungerla alla schermata Home"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Gira il telefono per una maggiore risoluzione"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pieghevole che viene aperto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pieghevole che viene capovolto"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"Piegato"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"Non piegato"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilità"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Scorciatoie da tastiera"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizza scorciatoie da tastiera"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Premi un tasto per assegnare una scorciatoia"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Scorciatoie per la ricerca"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nessun risultato di ricerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icona tasto Azione o Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Icona Più"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizza"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Fine"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona Espandi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oppure"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Punto di trascinamento"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Impostazioni tastiera"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Imposta scorciatoia"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annulla"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Premi un tasto"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinazione di tasti già in uso. Prova con un altro tasto."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviga usando la tastiera"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informazioni sulle scorciatoie da tastiera"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviga usando il touchpad"</string>
@@ -1455,11 +1450,11 @@
<string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Hai completato il gesto Indietro."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Vai alla schermata Home"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Scorri in alto con tre dita sul touchpad"</string>
- <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Ottimo lavoro."</string>
+ <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Ottimo lavoro!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Hai completato il gesto Vai alla schermata Home"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Visualizza app recenti"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Scorri verso l\'alto e tieni premuto con tre dita sul touchpad"</string>
- <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ottimo lavoro."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ottimo lavoro!"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Hai completato il gesto Visualizza app recenti."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Visualizza tutte le app"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Premi il tasto azione sulla tastiera"</string>
diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml
index 784a3091ef19..9d26859df5ed 100644
--- a/packages/SystemUI/res/values-it/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Disattivi"</item>
<item msgid="3028994095749238254">"Attivi"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Non disponibile"</item>
+ <item msgid="6419996398343291862">"Off"</item>
+ <item msgid="5908720590832378783">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 9064d3dac5cd..7b4245ee1c1e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"קלט"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"מכשירי שמיעה"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ההפעלה מתבצעת…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"לא ניתן להתאים את הבהירות כי היא\n נשלטת על ידי האפליקציה העליונה"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"סיבוב אוטומטי"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"סיבוב אוטומטי של המסך"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"מיקום"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"צריך ללחוץ כדי להתאים מכשיר חדש"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"לא ניתן לעדכן את ההגדרה הקבועה מראש"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"הגדרה קבועה מראש"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"נבחר"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"כלים"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"כתוביות מיידיות"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"פתק"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"לבטל את חסימת המיקרופון של המכשיר?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"לבטל את חסימת המצלמה של המכשיר?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"לבטל את חסימת המצלמה והמיקרופון של המכשיר?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"כן, אפשר להתחיל"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"אין התראות"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"אין התראות חדשות"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"הפוגת ההתראות מופעלת"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"עוצמת הקול וההתראות במכשיר מופחתות אוטומטית למשך עד 2 דקות כשמתקבלות יותר מדי התראות בבת אחת."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"השבתה"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"יש לבטל את הנעילה כדי לראות התראות ישנות"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"מעבר לאפליקציה משמאל או למטה בזמן שימוש במסך מפוצל"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"מעבר לאפליקציה מימין או למעלה בזמן שימוש במסך מפוצל"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"כשהמסך מפוצל: החלפה בין אפליקציה אחת לאחרת"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"העברת החלון הפעיל בין מסכים"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"קלט"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"מעבר לשפה הבאה"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"מעבר לשפה הקודמת"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"אפשר להזין עד <xliff:g id="LENGTH">%1$d</xliff:g> תווים"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"‏מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"‏מספר ה-Build הועתק ללוח."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ווידג\'טים של שיחות"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"יש להקיש על שיחה כדי להוסיף אותה למסך הבית"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"כדי לצלם תמונה ברזולוציה גבוהה יותר, כדאי להפוך את הטלפון"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"מכשיר מתקפל עובר למצב לא מקופל"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"מכשיר מתקפל עובר למצב מהופך"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"מצב מקופל"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"מצב לא מקופל"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"‏%1$s‏ / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"נגישות"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"מקשי קיצור"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"התאמה אישית של מקשי הקיצור"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"יש ללחוץ על מקש כדי להקצות מקש קיצור"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"קיצורי דרך לחיפוש"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"אין תוצאות חיפוש"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"סמל מקש הפעולה (\"מטא\")"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"סמל הפלוס"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"התאמה אישית"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"סיום"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"סמל ההרחבה"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"או"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"נקודת האחיזה לגרירה"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"הגדרות המקלדת"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"הגדרה של מקש קיצור"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ביטול"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"יש ללחוץ על מקש"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"שילוב המקשים הזה כבר בשימוש. אפשר לנסות מקש אחר."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ניווט באמצעות המקלדת"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"מידע על מקשי קיצור"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ניווט באמצעות לוח המגע"</string>
@@ -1452,19 +1447,19 @@
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"מחליקים שמאלה או ימינה עם שלוש אצבעות על לוח המגע"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"איזה יופי!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"השלמת את התנועה \'הקודם\'."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"סיימת לתרגל את התנועה \'הקודם\'."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"מעבר למסך הבית"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"מחליקים כלפי מעלה עם שלוש אצבעות על לוח המגע"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"מעולה!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"סיימת לתרגל את תנועת החזרה למסך הבית"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"הצגת האפליקציות האחרונות"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"מחליקים למעלה ולוחצים לחיצה ארוכה עם שלוש אצבעות על לוח המגע"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"מחליקים למעלה עם שלוש אצבעות על לוח המגע ומשאירים אותן במגע עם הלוח"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"מעולה!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"השלמת את התנועה להצגת האפליקציות האחרונות."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"סיימת לתרגל את התנועה להצגת האפליקציות האחרונות."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"צפייה בכל האפליקציות"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"צריך להקיש על מקש הפעולה במקלדת"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"כל הכבוד!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"השלמת את התנועה להצגת כל האפליקציות"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"סיימת לתרגל את התנועה להצגת כל האפליקציות"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"התאורה האחורית במקלדת"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"‏רמה %1$d מתוך %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"שליטה במכשירים"</string>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index e2ba375763c2..d6b9bc8950af 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"מצב מושבת"</item>
<item msgid="3028994095749238254">"מצב פעיל"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"לא זמין"</item>
+ <item msgid="6419996398343291862">"מושבת"</item>
+ <item msgid="5908720590832378783">"מופעל"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a23dac840796..c4fd62b355f6 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"入力"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"補聴器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ON にしています…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"明るさはトップ アプリによって\n制御されているため、調整できません"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動回転"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"画面を自動回転します"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置情報"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"クリックすると、新しいデバイスをペア設定できます"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"プリセットを更新できませんでした"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"プリセット"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"選択中"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ツール"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"自動字幕起こし"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"注"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"デバイスのマイクのブロックを解除しますか?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"デバイスのカメラのブロックを解除しますか?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"デバイスのカメラとマイクのブロックを解除しますか?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"分割画面の使用時に右側または下部のアプリに切り替える"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"分割画面の使用時に左側または上部のアプリに切り替える"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"分割画面中: アプリを順に置換する"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"アクティブなウィンドウをディスプレイ間で移動する"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"入力"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"次の言語に切り替える"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"前の言語に切り替える"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"使用できる文字数は <xliff:g id="LENGTH">%1$d</xliff:g> 文字未満です"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"空の会話"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"会話ウィジェット"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"会話をタップするとホーム画面に追加されます"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"高解像度で撮るにはスマートフォンを裏返してください"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"折りたたみ式デバイスが広げられている"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"折りたたみ式デバイスがひっくり返されている"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折りたたんだ状態"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"広げた状態"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ユーザー補助"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"キーボード ショートカット"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"キーボード ショートカットをカスタマイズする"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ショートカットを割り当てるキーを押してください"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"検索ショートカット"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"検索結果がありません"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"アクションキーまたはメタキーのアイコン"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"プラスアイコン"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"カスタマイズ"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"完了"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"または"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ドラッグ ハンドル"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"キーボードの設定"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ショートカットの設定"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"キャンセル"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"キーを押してください"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"このキーの組み合わせはすでに使用されています。別のキーを試してください。"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"キーボードを使用して移動する"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"キーボード ショートカットの詳細"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"タッチパッドを使用して移動する"</string>
@@ -1449,21 +1445,21 @@
<string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"最近使ったアプリを表示する"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完了"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"戻る"</string>
- <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"タッチパッドを 3 本の指で左右にスワイプします"</string>
+ <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"タッチパッドを 3 本の指で左または右にスワイプします"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"その調子です!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"「戻る」操作を学習しました。"</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"「戻る」ジェスチャーを学習しました。"</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ホームに移動"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"タッチパッドを 3 本の指で上にスワイプします"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"よくできました!"</string>
- <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"「ホームに移動」操作を学習しました"</string>
+ <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"「ホームに移動」ジェスチャーを学習しました"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"最近使ったアプリを表示する"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"タッチパッドを 3 本の指で上にスワイプして長押しします"</string>
- <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"よくできました"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"「最近使ったアプリを表示する」操作を学習しました。"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"よくできました!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"「最近使ったアプリを表示する」ジェスチャーを学習しました。"</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"すべてのアプリを表示"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"キーボードのアクションキーを押します"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"完了です!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"「すべてのアプリを表示する」操作を学習しました"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"「すべてのアプリを表示する」ジェスチャーを学習しました"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"キーボード バックライト"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"レベル %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ホーム コントロール"</string>
diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
index 683a4e889fbb..81c10e7d0ab8 100644
--- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"OFF"</item>
<item msgid="3028994095749238254">"ON"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"使用不可"</item>
+ <item msgid="6419996398343291862">"OFF"</item>
+ <item msgid="5908720590832378783">"ON"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index d0ff84296f3e..7cb3c8a99303 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"შეყვანა"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"სმენის მოწყობილობები"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ირთვება…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"სიკაშკაშის კორექტირება ვერ ხერხდება, რადგან ის\n იმართება გახსნილი აპის მიერ"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ავტოროტაცია"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ეკრანის ავტომატური შეტრიალება"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"მდებარეობა"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"დააწკაპუნეთ ახალი მოწყობილობის დასაწყვილებლად"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"წინასწარ დაყენებული პარამეტრების განახლება ვერ მოხერხდა"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"წინასწარ დაყენებული"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"არჩეულია"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ხელსაწყოები"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ავტოსუბტიტრები"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"ჩანიშვნა"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"გსურთ მოწყობილობის კამერის განბლოკვა?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"გსურთ მოწყობილობის კამერის და მიკროფონის განბლოკვა?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ეკრანის გაყოფის გამოყენებისას აპზე მარჯვნივ ან ქვემოთ გადართვა"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ეკრანის გაყოფის გამოყენებისას აპზე მარცხნივ ან ზემოთ გადართვა"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"ეკრანის გაყოფის დროს: ერთი აპის მეორით ჩანაცვლება"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"აქტიური ფანჯრის გადატანა ეკრანებს შორის"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"შეყვანა"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"შემდეგ ენაზე გადართვა"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"წინა ენაზე გადართვა"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"გამოიყენეთ <xliff:g id="LENGTH">%1$d</xliff:g>-ზე ნაკლები სიმბოლო"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"მიმოწერის გახსნა"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"საუბრის ვიჯეტები"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"შეეხეთ საუბარს მის თქვენს მთავარ ეკრანზე დასამატებლად"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"მაღალი გარჩევადობისთვის ამოაბრუნეთ ტელეფონი"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"დასაკეცი მოწყობილობა იხსნება"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"დასაკეცი მოწყობილობა ტრიალებს"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"დაკეცილი"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"გაშლილი"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"მისაწვდომობა"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"კლავიატურის მალსახმობები"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"კლავიატურის მალსახმობების მორგება"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"მალსახმობის მინიჭებისთვის დააჭირეთ კლავიშს"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ძიების მალსახმობები"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ძიების შედეგები არ არის"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"მოქმედების ან მეტა კლავიშის ხატულა"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"პლუსის ხატულა"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"მორგება"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"მზადაა"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ხატულის გაფართოება"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ან"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"სახელური ჩავლებისთვის"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"კლავიატურის პარამეტრები"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"მალსახმობის დაყენება"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"გაუქმება"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"დააჭირეთ კლავიშს"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"კლავიშების კომბინაცია უკვე გამოიყენება. ცადეთ სხვა კლავიში."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ნავიგაცია კლავიატურის გამოყენებით"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"კლავიატურის მალსახმობების სწავლა"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ნავიგაცია სენსორული პანელის გამოყენებით"</string>
diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
index 7c13eb53d5d8..6e62ed4ee74a 100644
--- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"გამორთულია"</item>
<item msgid="3028994095749238254">"ჩართულია"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"მიუწვდომელია"</item>
+ <item msgid="6419996398343291862">"გამორთული"</item>
+ <item msgid="5908720590832378783">"ჩართული"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 94f8711cc7a0..4122eeef9d59 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Кіріс"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Есту аппараттары"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Қосылып жатыр…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Жарықтықты реттеу мүмкін емес, себебі ол\n жетекші қолданба арқылы басқарылады."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматты түрде бұру"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматты айналатын экран"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңа құрылғыны жұптау үшін басыңыз."</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Параметрлер жинағын жаңарту мүмкін болмады."</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Параметрлер жинағы"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Таңдалды"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Құралдар"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Ескертпе"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Құрылғы микрофонын блоктан шығару керек пе?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Құрылғы камерасын блоктан шығару керек пе?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Құрылғы камерасы мен микрофонын блоктан шығару керек пе?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Қазір бастау"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Хабарландырулар жоқ"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Жаңа хабарландырулар жоқ"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Хабарландыру дыбысын азайту параметрі енді қосулы"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Бір уақытта тым көп хабарландыру келсе, дыбыс деңгейі автоматты түрде азайтылып, хабарландырулар 2 минутқа кідіртіледі."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Өшіру"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Ескі хабарландырулар үшін құлыпты ашыңыз"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлінген экранда оң не төмен жақтағы қолданбаға ауысу"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлінген экранда сол не жоғары жақтағы қолданбаға ауысу"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Экранды бөлу кезінде: бір қолданбаны басқасымен алмастыру"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Дисплейлер арасында қосулы терезені ауыстыру"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Енгізу"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Келесі тілге ауысу"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Алдыңғы тілге ауысу"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Ең көбі <xliff:g id="LENGTH">%1$d</xliff:g> таңба пайдаланыңыз."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Ашық әңгіме"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Әңгіме виджеттері"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Негізгі экранға қосқыңыз келетін әңгімені түртіңіз."</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Жоғары ажыратымдылық үшін телефонды айналдырыңыз."</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Бүктемелі құрылғы ашылып жатыр."</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Бүктемелі құрылғы аударылып жатыр."</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"жабық"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ашық"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Арнайы мүмкіндіктер"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Перне тіркесімдері"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Пернелер тіркесімін бейімдеу"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Жылдам пәрменді тағайындау үшін пернені басыңыз."</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Іздеу жылдам пәрмендері"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Іздеу нәтижелері жоқ."</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Әрекет немесе Meta пернесінің белгішесі"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Қосу белгішесі"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Бейімдеу"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Дайын"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"немесе"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Сүйрейтін тетік"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Пернетақта параметрлері"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Жылдам пәрменді орнату"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Бас тарту"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Пернені басыңыз"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Бұл пернелер тіркесімі қазір қолданыста. Басқа пернені таңдаңыз."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Пернетақтамен жұмыс істеңіз"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Перне тіркесімдерін үйреніңіз."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Сенсорлық тақтамен жұмыс істеңіз"</string>
diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
index 2b4c1ac355a2..66deff6d7135 100644
--- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Өшірулі"</item>
<item msgid="3028994095749238254">"Қосулы"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Қолжетімді емес"</item>
+ <item msgid="6419996398343291862">"Өшірулі"</item>
+ <item msgid="5908720590832378783">"Қосулы"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 2b178181aa3f..f9ec58f2fba8 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"បញ្ចូល"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"កំពុង​បើក..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"មិនអាចកែតម្រូវកម្រិតពន្លឺបានទេ ដោយសារវាកំពុងស្ថិតក្រោម\nការគ្រប់គ្រងរបស់កម្មវិធីខាងលើគេ"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"បង្វិល​ស្វ័យ​ប្រវត្តិ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ទី​តាំង​"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ចុច ដើម្បីផ្គូផ្គងឧបករណ៍ថ្មី"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"មិនអាច​ប្ដូរ​ការកំណត់ជាមុន​បានទេ"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"កំណត់ជាមុន"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"បានជ្រើសរើស"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ឧបករណ៍"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"អក្សររត់ក្នុងពេលជាក់ស្ដែង"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"កំណត់ចំណាំ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ឈប់ទប់ស្កាត់​មីក្រូហ្វូន​របស់ឧបករណ៍ឬ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ឈប់ទប់ស្កាត់​កាមេរ៉ា​របស់ឧបករណ៍ឬ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ឈប់ទប់ស្កាត់​កាមេរ៉ា និងមីក្រូហ្វូន​របស់ឧបករណ៍ឬ?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ប្ដូរទៅកម្មវិធីនៅខាងស្ដាំ ឬខាងក្រោម ពេលកំពុងប្រើមុខងារ​បំបែកអេក្រង់"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ប្ដូរទៅកម្មវិធីនៅខាងឆ្វេង ឬខាងលើ ពេលកំពុងប្រើមុខងារ​បំបែកអេក្រង់"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"ក្នុងអំឡុងពេលប្រើមុខងារបំបែកអេក្រង់៖ ជំនួសកម្មវិធីពីមួយទៅមួយទៀត"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ផ្លាស់ទីវិនដូដែលសកម្មរវាងផ្ទាំងអេក្រង់"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"បញ្ចូល"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ប្ដូរទៅភាសាបន្ទាប់"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"ប្ដូរទៅភាសាមុន"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ប្រើតិចជាង <xliff:g id="LENGTH">%1$d</xliff:g> តួអក្សរ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខ​កំណែបង្កើត"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខ​កំណែបង្កើតទៅឃ្លីបបត។"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"បើកការសន្ទនា"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ធាតុ​ក្រាហ្វិកនៃការសន្ទនា"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ចុចការសន្ទនា ដើម្បីបញ្ចូលវាទៅក្នុងអេក្រង់ដើមរបស់អ្នក"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"សម្រាប់កម្រិតគុណភាពកាន់តែខ្ពស់ សូមត្រឡប់ទូរសព្ទ"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"បត់"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"លា"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ភាពងាយស្រួល"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ផ្លូវកាត់​ក្ដារ​ចុច"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ប្ដូរ​ផ្លូវកាត់​ក្ដារ​ចុចតាម​បំណង"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ចុចគ្រាប់ចុច ដើម្បីកំណត់ផ្លូវ​កាត់"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ស្វែងរកផ្លូវ​កាត់"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"គ្មាន​លទ្ធផល​ស្វែងរក​ទេ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"រូបគ្រាប់ចុចសកម្មភាព ឬមេតា"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"រូបសញ្ញាបូក"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"ប្ដូរ​តាម​បំណង"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"រួចរាល់"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"រូបតំណាង \"ពង្រីក\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ឬ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ដង​អូស"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ការកំណត់​ក្ដារចុច"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"កំណត់ផ្លូវ​កាត់"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"បោះបង់"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ចុចគ្រាប់ចុច"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"កំពុងប្រើបន្សំគ្រាប់ចុចស្រាប់ហើយ។ សាកល្បងប្រើគ្រាប់ចុចផ្សេង។"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"រុករកដោយប្រើក្ដារចុចរបស់អ្នក"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ស្វែងយល់អំពីផ្លូវកាត់​ក្ដារ​ចុច"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"រុករកដោយប្រើផ្ទាំងប៉ះរបស់អ្នក"</string>
diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml
index 3c15fd3a35e4..71b12ca8ff62 100644
--- a/packages/SystemUI/res/values-km/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"បិទ"</item>
<item msgid="3028994095749238254">"បើក"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"មិនអាចប្រើបាន"</item>
+ <item msgid="6419996398343291862">"បិទ"</item>
+ <item msgid="5908720590832378783">"បើក"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index b74a0535bdd4..f3155704c55f 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -270,7 +270,7 @@
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು."</string>
<string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಯ ಪರದೆ."</string>
<string name="accessibility_desc_lock_screen" msgid="409034672704273634">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
- <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ಕೆಲಸದ ಲಾಕ್ ಪರದೆ"</string>
+ <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ಕೆಲಸದ ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"ಮುಚ್ಚಿ"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ಸಂಪೂರ್ಣ ನಿಶ್ಯಬ್ಧ"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ಅಲಾರಮ್‌ಗಳು ಮಾತ್ರ"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ಇನ್‌ಪುಟ್"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ಬ್ರೈಟ್‌ನೆಸ್ ಅನ್ನು ಅಡ್ಜಸ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ,\n ಏಕೆಂದರೆ ಅದನ್ನು ಟಾಪ್ ಆ್ಯಪ್ ನಿಯಂತ್ರಿಸುತ್ತಿದೆ"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ಸ್ವಯಂ-ತಿರುಗುವಿಕೆ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ಸ್ಥಳ"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ಪ್ರಿಸೆಟ್ ಅನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ಪ್ರಿಸೆಟ್‌"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ಟೂಲ್‌ಗಳು"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ಲೈವ್ ಕ್ಯಾಪ್ಶನ್"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"ಟಿಪ್ಪಣಿ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ಸಾಧನದ ಕ್ಯಾಮರಾ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ಸಾಧನದ ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಅನ್‍ಬ್ಲಾಕ್ ಮಾಡಬೇಕೇ?"</string>
@@ -560,8 +560,8 @@
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ಸ್ಕ್ರೀನ್‌ ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಈ ಆಯ್ಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದೆ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"ಹಂಚಿಕೊಳ್ಳಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಕ್ಯಾಸ್ಟ್ ಮಾಡಬೇಕೆ?"</string>
- <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ಒಂದು ಆ್ಯಪ್ ಅನ್ನು ಕ್ಯಾಸ್ಟ್ ಮಾಡಿ"</string>
+ <string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಕಾಸ್ಟ್ ಮಾಡಬೇಕೆ?"</string>
+ <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ಒಂದು ಆ್ಯಪ್ ಅನ್ನು ಕಾಸ್ಟ್ ಮಾಡಿ"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"ಸಂಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಕ್ಯಾಸ್ಟ್ ಮಾಡಿ"</string>
<string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"ನಿಮ್ಮ ಸಂಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ನೀವು ಕ್ಯಾಸ್ಟ್ ಮಾಡುವಾಗ, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಏನಾದರೂ ಗೋಚರಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string>
<string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಕ್ಯಾಸ್ಟ್ ಮಾಡುತ್ತಿರುವಾಗ, ಆ ಆ್ಯಪ್‌ನಲ್ಲಿ ತೋರಿಸಿರುವ ಅಥವಾ ಪ್ಲೇ ಮಾಡಿರುವುದು ಗೋಚರಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string>
@@ -868,11 +868,10 @@
<string name="system_multitasking_rhs" msgid="8714224917276297810">"ಬಲಭಾಗದಲ್ಲಿ ಪ್ರಸ್ತುತ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string>
<string name="system_multitasking_lhs" msgid="8402954791206308783">"ಎಡಭಾಗದಲ್ಲಿ ಪ್ರಸ್ತುತ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್‌ನಿಂದ ಪೂರ್ಣ ಸ್ಕ್ರೀನ್‌ಗೆ ಬದಲಿಸಿ"</string>
- <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ಪರದೆ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಬಲಭಾಗ ಅಥವಾ ಕೆಳಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್‌ಗೆ ಬದಲಿಸಿ"</string>
- <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ಪರದೆ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಎಡಭಾಗ ಅಥವಾ ಮೇಲ್ಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್‌ಗೆ ಬದಲಿಸಿ"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಬಲಭಾಗ ಅಥವಾ ಕೆಳಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್‌ಗೆ ಬದಲಿಸಿ"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಎಡಭಾಗ ಅಥವಾ ಮೇಲ್ಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್‌ಗೆ ಬದಲಿಸಿ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸುವ ಸಮಯದಲ್ಲಿ: ಒಂದು ಆ್ಯಪ್‌ನಿಂದ ಮತ್ತೊಂದು ಆ್ಯಪ್‌ಗೆ ಬದಲಿಸಿ"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ಸಕ್ರಿಯ ವಿಂಡೋವನ್ನು ಡಿಸ್‌ಪ್ಲೇಗಳ ನಡುವೆ ಸರಿಸಿ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ಇನ್‌ಪುಟ್"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ಮುಂದಿನ ಭಾಷೆಗೆ ಬದಲಿಸಿ"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"ಹಿಂದಿನ ಭಾಷೆಗೆ ಬದಲಿಸಿ"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> ಕ್ಕಿಂತ ಕಡಿಮೆ ಅಕ್ಷರಗಳನ್ನು ಬಳಸಿ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"ಸಂಭಾಷಣೆಯನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ಸಂಭಾಷಣೆ ವಿಜೆಟ್‌ಗಳು"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ಸಂಭಾಷಣೆಯನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಸೇರಿಸಲು ಅದನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ಅಧಿಕ ರೆಸಲ್ಯೂಷನ್‌ಗಾಗಿ, ಫೋನ್ ಅನ್ನು ಫ್ಲಿಪ್ ಮಾಡಿ"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಸುತ್ತಲೂ ತಿರುಗಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,33 +1418,26 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ಶಾರ್ಟ್‌ಕಟ್ ಅನ್ನು ನಿಯೋಜಿಸಲು ಕೀಯನ್ನು ಒತ್ತಿರಿ"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ಹುಡುಕಾಟದ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ಯಾವುದೇ ಹುಡುಕಾಟ ಫಲಿತಾಂಶಗಳಿಲ್ಲ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ಆ್ಯಕ್ಷನ್ ಅಥವಾ ಮೆಟಾ ಕೀ ಐಕಾನ್"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ಪ್ಲಸ್ ಐಕಾನ್"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ಮುಗಿದಿದೆ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ಅಥವಾ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ಡ್ರ್ಯಾಗ್‌ ಹ್ಯಾಂಡಲ್‌"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ಕೀಬೋರ್ಡ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ಶಾರ್ಟ್‌ಕಟ್ ಸೆಟ್ ಮಾಡಿ"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ಕೀ ಅನ್ನು ಒತ್ತಿರಿ"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ಕೀ ಸಂಯೋಜನೆಯು ಈಗಾಗಲೇ ಬಳಕೆಯಲ್ಲಿದೆ. ಮತ್ತೊಂದು ಕೀ ಬಳಸಿ ನೋಡಿ."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಕಲಿಯಿರಿ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
- <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ಟಚ್‌ಪ್ಯಾಡ್ ಗೆಸ್ಚರ್‌ಗಳನ್ನು ಕಲಿಯಿರಿ"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ಟಚ್‌ಪ್ಯಾಡ್ ಜೆಸ್ಚರ್‌ಗಳನ್ನು ಕಲಿಯಿರಿ"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಮತ್ತು ಟಚ್‌ಪ್ಯಾಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ಟಚ್‌ಪ್ಯಾಡ್ ಗೆಸ್ಚರ್‌ಗಳು, ಕೀಬೋರ್ಡ್‌ಗಳ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ತಿಳಿಯಿರಿ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ಹಿಂದಿರುಗಿ"</string>
@@ -1459,11 +1455,11 @@
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್‌ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ಭೇಷ್‌!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ನೀವು ಇತ್ತೀಚಿನ ಆ್ಯಪ್‌ಗಳ ಗೆಸ್ಚರ್‌ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ನೀವು ಇತ್ತೀಚಿನ ಆ್ಯಪ್‌ಗಳ ಜೆಸ್ಚರ್‌ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್‌ನಲ್ಲಿ ಆ್ಯಕ್ಷನ್‌ ಕೀಯನ್ನು ಒತ್ತಿ"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ಭೇಷ್!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ನೀವು ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳ ಗೆಸ್ಚರ್‌ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ನೀವು ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳ ಜೆಸ್ಚರ್‌ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ಕೀಬೋರ್ಡ್ ಬ್ಯಾಕ್‌ಲೈಟ್"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ರಲ್ಲಿ %1$d ಮಟ್ಟ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ಮನೆ ನಿಯಂತ್ರಣಗಳು"</string>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index 5a188f19a5ac..49c688abff72 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ಆಫ್"</item>
<item msgid="3028994095749238254">"ಆನ್"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"ಲಭ್ಯವಿಲ್ಲ"</item>
+ <item msgid="6419996398343291862">"ಆಫ್ ಆಗಿದೆ"</item>
+ <item msgid="5908720590832378783">"ಆನ್ ಆಗಿದೆ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cc2cb909058a..931066b3d749 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"입력"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"보청기"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"켜는 중..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"상위 앱에서 밝기를 제어하고 있으므로\n 밝기를 조절할 수 없습니다."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"자동 회전"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"화면 자동 회전"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"위치"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"새 기기와 페어링하려면 클릭하세요"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"사전 설정을 업데이트할 수 없음"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"미리 설정"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"선택됨"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"도구"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"실시간 자막"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"메모"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 차단 해제하시겠습니까?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"기기 카메라를 차단 해제하시겠습니까?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"기기 카메라 및 마이크를 차단 해제하시겠습니까?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"시작하기"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"알림 없음"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"새로운 알림 없음"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"알림 쿨다운 사용 설정됨"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"한 번에 너무 많은 알림을 받으면 최대 2분간 자동으로 기기 볼륨이 줄어들고 알림이 최소화됩니다."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"사용 중지"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"잠금 해제하여 이전 알림 보기"</string>
@@ -699,7 +698,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"소음 제어"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"공간 음향"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"사용 안함"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"수정됨"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"고정됨"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"머리 추적"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"탭하여 벨소리 장치 모드 변경"</string>
<string name="volume_ringer_mode" msgid="6867838048430807128">"벨소리 장치 모드"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"화면 분할을 사용하는 중에 오른쪽 또는 아래쪽에 있는 앱으로 전환"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"화면 분할을 사용하는 중에 왼쪽 또는 위쪽에 있는 앱으로 전환하기"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"화면 분할 중: 다른 앱으로 바꾸기"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"디스플레이 간 활성 창 이동"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"입력"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"다음 언어로 전환"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"이전 언어로 전환"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>자 미만이어야 합니다."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"대화 열기"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"대화 위젯"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"대화를 탭하여 홈 화면에 추가하세요."</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"해상도를 높이려면 후면 카메라를 사용하세요."</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"폴더블 기기를 펼치는 모습"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"폴더블 기기를 뒤집는 모습"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"접은 상태"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"펼친 상태"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,33 +1418,26 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"접근성"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"단축키"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"단축키 맞춤설정"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"키를 눌러 단축키 지정"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"검색 바로가기"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"검색 결과 없음"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"작업 또는 메타 키 아이콘"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"더하기 아이콘"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"맞춤설정"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"완료"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"확장 아이콘"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"또는"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"드래그 핸들"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"키보드 설정"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"단축키 설정"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"취소"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"키를 누르세요."</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"이미 사용 중인 키 조합입니다. 다른 키를 사용해 보세요."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"키보드를 사용하여 이동"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"단축키에 관해 알아보세요."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"터치패드를 사용하여 이동"</string>
- <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"터치패드 동작 알아보기"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"터치패드 동작을 알아보세요."</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"키보드와 터치패드를 사용하여 이동"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"터치패드 동작, 단축키 등 알아보기"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"뒤로 이동"</string>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index bfa11271bbab..002d38e71e96 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"사용 안함"</item>
<item msgid="3028994095749238254">"사용"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"사용할 수 없음"</item>
+ <item msgid="6419996398343291862">"사용 안함"</item>
+ <item msgid="5908720590832378783">"사용"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index bcf594db3ded..fc16164b6874 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -114,7 +114,7 @@
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Бүтүндөй экранды жаздыруу"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Толук экранды жаздыруу: %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Бүтүндөй экранды жаздырганда, андагы нерселердин баары видеого түшүп калат. Андыктан этият болуп, сырсөздөр, төлөм ыкмалары, билдирүүлөр, сүрөттөр, аудио жана видео материалдар сыяктуу купуя нерселерди көрсөтүп албаңыз."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Колдонмону жаздырганда ал колдонмодо көрсөтүлүп же ойнотулуп жаткан нерселер жаздырылат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Колдонмону жаздырганда, андагы нерселердин баары видеого түшүп калат. Андыктан сырсөздөр, төлөмдүн чоо-жайы, билдирүүлөр, сүрөттөр, аудио жана видео сыяктуу нерселер менен этият болуңуз."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Экранды жаздыруу"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Жаздыруу үчүн колдонмо тандоо"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Аудио жаздыруу"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Киргизүү"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Угуу аппараттары"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Күйгүзүлүүдө…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Жарыктыкты тууралоого болбойт, анткени аны\n жогорку колдонмо көзөмөлдөйт"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авто буруу"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Экранды авто буруу"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Жайгашкан жер"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңы түзмөк кошуу үчүн басыңыз"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Алдын ала коюлган параметрлер жаңыртылган жок"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Алдын ала коюлган параметрлер"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Тандалды"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Куралдар"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Ыкчам коштомо жазуулар"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Учкай маалымат"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Түзмөктүн микрофонун бөгөттөн чыгарасызбы?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Түзмөктүн камерасын бөгөттөн чыгарасызбы?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Түзмөктүн камерасы менен микрофону бөгөттөн чыгарылсынбы?"</string>
@@ -556,7 +556,7 @@
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Бүтүндөй экранды бөлүшкөндө андагы бардык нерселер <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна көрүнөт. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Колдонмону бөлүшкөндө ал колдонмодо көрсөтүлүп же ойнотулуп жаткан нерселер <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна көрүнөт. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Колдонмону бөлүшкөндө, андагы нерселер <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна көрүнөт. Андыктан сырсөздөр, төлөмдүн чоо-жайы, билдирүүлөр, сүрөттөр, аудио жана видеолор менен этият болуңуз."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Экранды бөлүшүү"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> бул параметрди өчүрүп койду"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Бөлүшүү үчүн колдонмо тандоо"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Азыр баштоо"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Билдирме жок"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Жаңы билдирмелер жок"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Азыр билдирмелердин үнүн басаңдатуу күйүк"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Өтө көп билдирме келсе, түзмөктүн үнү 2 мүнөткө басаңдап, эскертүүлөрдүн саны азаят."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Өчүрүү"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Билдирмелерди көрүү үчүн кулпуну ачыңыз"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлүнгөн экранда сол же төмөн жактагы колдонмого которулуу"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлүнгөн экранды колдонуп жатканда сол же жогору жактагы колдонмого которулуңуз"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Экранды бөлүү режиминде бир колдонмону экинчисине алмаштыруу"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Активдүү терезени экрандардын ортосунда жылдыруу"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Киргизүү"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Кийинки тилге которулуу"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Мурунку тилге которулуу"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> символдон ашпашы керек"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Ачык сүйлөшүү"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Сүйлөшүүлөр виджеттери"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Сүйлөшүүнү башкы экранга кошуу үчүн таптап коюңуз"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Жогорку дааналык үчүн телефондун арткы камерасын колдонуңуз"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ачылып турган бүктөлмө түзмөк"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Оодарылып жаткан бүктөлмө түзмөк"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"бүктөлгөн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ачылган"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,34 +1418,27 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Атайын мүмкүнчүлүктөр"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Ыкчам баскычтар"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Ыкчам баскычтарды ыңгайлаштыруу"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Ыкчам баскычты дайындоо үчүн баскычты басыңыз"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ыкчам баскычтарды издөө"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Эч нерсе табылган жок"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Аракет же Мета ачкыч сүрөтчөсү"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Кошуу сүрөтчөсү"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Ыңгайлаштыруу"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Бүттү"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жайып көрсөтүү сүрөтчөсү"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"же"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Cүйрөө маркери"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Баскычтоп параметрлери"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
- <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Нерселерге баскычтоп аркылуу өтүңүз"</string>
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ыкчам баскычты тууралоо"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Баскычты басыңыз"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ачкыч айкалышы колдонулууда. Башка ачкычты байкап көрүңүз."</string>
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Керектүү нерселерге баскычтоп аркылуу өтүү"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ыкчам баскычтар тууралуу билип алыңыз"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Керектүү жерге сенсордук такта аркылуу өтөсүз"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Сенсордук тактадагы жаңсоолорду үйрөнүп алыңыз"</string>
- <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Нерселерге баскычтоп жана сенсордук такта аркылуу өтүңүз"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Керектүү нерселерге баскычтоп жана сенсордук такта аркылуу өтүү"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Сенсордук тактадагы жаңсоолор, ыкчам баскычтар жана башкалар жөнүндө билип алыңыз"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Артка кайтуу"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Башкы бетке өтүү"</string>
@@ -1452,7 +1447,7 @@
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артка кайтуу"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Сенсордук тактаны үч манжаңыз менен солго же оңго сүрүңүз"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Сонун!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"\"Артка\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"\"Артка\" жаңсоосун үйрөндүңүз."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Башкы бетке өтүү"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Сенсордук тактаны үч манжаңыз менен жогору сүрүңүз"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Азаматсыз!"</string>
@@ -1496,6 +1491,6 @@
<string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Колдонмолор сунуштады"</string>
<string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Экран"</string>
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгисиз"</string>
- <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бардык карталарды баштапкы абалга келтиресизби?"</string>
- <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Бардык Ыкчам параметрлер карталары түзмөктүн баштапкы параметрлерине кайтарылат"</string>
+ <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бардык параметрлерди кайра коесузбу?"</string>
+ <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Бардык ыкчам параметрлер түзмөктүн баштапкы маанилерине кайтарылат"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
index e9d9612a4e47..4834dbc69246 100644
--- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Өчүк"</item>
<item msgid="3028994095749238254">"Күйүк"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Жеткиликсиз"</item>
+ <item msgid="6419996398343291862">"Өчүк"</item>
+ <item msgid="5908720590832378783">"Күйүк"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 235015b5286f..70ae5c1832af 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -91,7 +91,6 @@
<dimen name="notification_blocker_channel_list_height">128dp</dimen>
<dimen name="keyguard_indication_margin_bottom">8dp</dimen>
- <dimen name="lock_icon_margin_bottom">24dp</dimen>
<!-- Keyboard shortcuts helper -->
<dimen name="ksh_container_horizontal_margin">48dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 4898fa8d823a..3a8c682bce0e 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ການປ້ອນຂໍ້ມູນ"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ເຄື່ອງຊ່ວຍຟັງ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ກຳລັງເປີດ..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ບໍ່ສາມາດປັບຄວາມແຈ້ງເນື່ອງຈາກມັນ\n ຖືກຄວບຄຸມໂດຍແອັບຍອດນິຍົມ"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ໝຸນ​ອັດ​ຕະ​ໂນ​ມັດ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ສະຖານທີ່"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ຄລິກເພື່ອຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ບໍ່ສາມາດອັບເດດການຕັ້ງຄ່າລ່ວງໜ້າໄດ້"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ຄ່າທີ່ກຳນົດລ່ວງໜ້າ"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ເລືອກແລ້ວ"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ເຄື່ອງມື"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ຄຳບັນຍາຍສົດ"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"ບັນທຶກ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ປົດບລັອກໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ປົດບລັອກກ້ອງຖ່າຍຮູບອຸ​ປະ​ກອນບໍ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ຍົກເລີກການບລັອກກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນອຸ​ປະ​ກອນບໍ?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຂວາ ຫຼື ທາງລຸ່ມໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຊ້າຍ ຫຼື ທາງເທິງໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"ໃນລະຫວ່າງແບ່ງໜ້າຈໍ: ໃຫ້ປ່ຽນຈາກແອັບໜຶ່ງເປັນອີກແອັບໜຶ່ງ"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ຍ້າຍໜ້າຈໍທີ່ເປີດຢູ່ໄປມາລະຫວ່າງຈໍສະແດງຜົນຕ່າງໆ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ການປ້ອນຂໍ້ມູນ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ສະຫຼັບເປັນພາສາຖັດໄປ"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"ສະຫຼັບເປັນພາສາກ່ອນໜ້າ"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ໃຊ້ໜ້ອຍກວ່າ <xliff:g id="LENGTH">%1$d</xliff:g> ຕົວອັກສອນ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"ເປີດການສົນທະນາ"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ວິດເຈັດການສົນທະນາ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ແຕະໃສ່ການສົນທະນາໃດໜຶ່ງເພື່ອເພີ່ມມັນໃສ່ໂຮມສະກຣີນຂອງທ່ານ"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ເພື່ອຄວາມລະອຽດທີ່ສູງຂຶ້ນ, ໃຫ້ປີ້ນໂທລະສັບ"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ອຸປະກອນທີ່ພັບໄດ້ກຳລັງກາງອອກ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ອຸປະກອນທີ່ພັກໄດ້ກຳລັງປີ້ນໄປມາ"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ພັບແລ້ວ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ກາງອອກແລ້ວ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ການຊ່ວຍເຂົ້າເຖິງ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ຄີລັດ"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ປັບແຕ່ງຄີລັດ"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ກົດປຸ່ມເພື່ອກໍານົດທາງລັດ"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ທາງລັດການຊອກຫາ"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ບໍ່ມີຜົນການຊອກຫາ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ໄອຄອນຫຍໍ້ລົງ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ໄອຄອນຄຳສັ່ງ ຫຼື ປຸ່ມ Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ໄອຄອນໝາຍບວກ"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"ປັບແຕ່ງ"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ແລ້ວໆ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ໄອຄອນຂະຫຍາຍ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ຫຼື"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ບ່ອນຈັບລາກ"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ການຕັ້ງຄ່າແປ້ນພິມ"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ຕັ້ງທາງລັດ"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ຍົກເລີກ"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ກົດປຸ່ມ"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ນໍາໃຊ້ປຸ່ມປະສົມຢູ່ແລ້ວ. ໃຫ້ລອງປຸ່ມອື່ນ."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ນຳທາງໂດຍໃຊ້ແປ້ນພິມຂອງທ່ານ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ສຶກສາຄີລັດ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ນຳທາງໂດຍໃຊ້ແຜ່ນສຳຜັດຂອງທ່ານ"</string>
diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
index 34af9aae31e3..bc63895f3bc6 100644
--- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ປິດ"</item>
<item msgid="3028994095749238254">"ເປີດ"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"ບໍ່ສາມາດໃຊ້ໄດ້"</item>
+ <item msgid="6419996398343291862">"ປິດ"</item>
+ <item msgid="5908720590832378783">"ເປີດ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index aff0d3085bfa..ae85ed2060c6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Įvestis"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Klausos aparatai"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Įjungiama…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Negalima koreguoti ryškumo, nes jį valdo\n viršuje esanti programa"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatinis pasukimas"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatiškai sukti ekraną"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vietovė"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Spustelėkite, kad susietumėte naują įrenginį"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Išankstinių nustatymų atnaujinti nepavyko"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Išankstiniai nustatymai"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Pasirinkta"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Įrankiai"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitrai realiuoju laiku"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Pastaba"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Panaikinti įrenginio mikrofono blokavimą?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Panaikinti įrenginio fotoaparato blokavimą?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Panaikinti įrenginio fotoaparato ir mikrofono blokavimą?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Perjunkite į programą dešinėje arba apačioje išskaidyto ekrano režimu"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Perjunkite į programą kairėje arba viršuje išskaidyto ekrano režimu"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Išskaidyto ekrano režimu: pakeisti iš vienos programos į kitą"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Aktyvaus lango perkėlimas iš vieno ekrano į kitą"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Įvestis"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Perjungti į kitą kalbą"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Perjungti į ankstesnę kalbą"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Naudokite daugiausia <xliff:g id="LENGTH">%1$d</xliff:g> simb."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Atidaryti pokalbį"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Pokalbio valdikliai"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Palieskite pokalbį, kad pridėtumėte jį prie pagrindinio ekrano"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Kad raiška būtų geresnė, apverskite telefoną"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Lankstomasis įrenginys išlankstomas"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Lankstomasis įrenginys apverčiamas"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sulenkta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"nesulenkta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pritaikomumas"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Spartieji klavišai"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sparčiųjų klavišų tinkinimas"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Paspauskite klavišą, kad priskirtumėte spartųjį klavišą"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ieškoti sparčiųjų klavišų"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nėra jokių paieškos rezultatų"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Veiksmo arba metaduomenų klavišo piktograma"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Pliuso piktograma"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Tinkinti"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Atlikta"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Išskleidimo piktograma"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"arba"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vilkimo rankenėlė"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatūros nustatymai"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nustatyti spartųjį klavišą"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Atšaukti"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Paspauskite klavišą"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Klavišų derinys jau naudojamas. Bandykite naudoti kitą klavišą."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naršykite naudodamiesi klaviatūra"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Sužinokite apie sparčiuosius klavišus"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naršykite naudodamiesi jutikline dalimi"</string>
diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
index 124f49c7d22e..12f8b6ce02cf 100644
--- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Išjungta"</item>
<item msgid="3028994095749238254">"Įjungta"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nepasiekiama"</item>
+ <item msgid="6419996398343291862">"Išjungta"</item>
+ <item msgid="5908720590832378783">"Įjungta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b0b417675c1c..b20ab36a3896 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ievade"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Dzirdes aparāti"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Notiek ieslēgšana…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Nevar mainīt spilgtumu, jo to kontrolē\n aktīvā lietotne."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automātiska pagriešana"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automātiska ekrāna pagriešana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Atrašanās vieta"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Noklikšķiniet, lai savienotu pārī jaunu ierīci"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nevarēja atjaunināt pirmsiestatījumu"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Pirmsiestatījums"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Atlasīts"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Rīki"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitri reāllaikā"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Piezīme"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vai atbloķēt ierīces mikrofonu?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vai vēlaties atbloķēt ierīces kameru?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vai atbloķēt ierīces kameru un mikrofonu?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Sākt tūlīt"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nav paziņojumu"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nav jaunu paziņojumu"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Nogaidīšanas periods paziņojumiem ir ieslēgts"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Saņemot par daudz paziņojumu uzreiz, skaļums un brīdinājumi tiek automātiski samazināti līdz 2 min."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Izslēgt"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Atbloķējiet vecāku paziņojumu skatīšanai"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pāriet uz lietotni pa labi/lejā, kamēr izmantojat sadalīto ekrānu."</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pāriet uz lietotni pa kreisi/augšā, kamēr izmantojat sadalīto ekrānu."</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ekrāna sadalīšanas režīmā: pārvietot lietotni no viena ekrāna uz otru"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Pārvietot aktīvo logu starp displejiem"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Ievade"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Pārslēgt uz nākamo valodu"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Pārslēgt uz iepriekšējo valodu"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Izmantojiet mazāk nekā <xliff:g id="LENGTH">%1$d</xliff:g> rakstzīmes."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Atvērt sarunu"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Sarunu logrīki"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Pieskarieties kādai sarunai, lai pievienotu to savam sākuma ekrānam."</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Lai izmantotu augstāku izšķirtspēju, apvērsiet tālruni"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Salokāma ierīce tiek atlocīta"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Salokāma ierīce tiek apgriezta"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"aizvērta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"atvērta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pieejamība"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Īsinājumtaustiņi"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Īsinājumtaustiņu pielāgošana"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Lai piešķirtu īsinājumtaustiņu, nospiediet taustiņu"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Meklēt saīsnes"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nav meklēšanas rezultātu"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Darbību jeb meta taustiņa ikona"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Pluszīmes ikona"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Pielāgot"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Gatavs"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Izvēršanas ikona"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vai"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vilkšanas turis"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastatūras iestatījumi"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Iestatīt īsinājumtaustiņu"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Atcelt"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nospiediet taustiņu"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Taustiņu kombinācija jau tiek izmantota. Izmēģiniet citu taustiņu."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Pārvietošanās, izmantojot tastatūru"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Uzziniet par īsinājumtaustiņiem."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Pārvietošanās, izmantojot skārienpaliktni"</string>
diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
index e5cb1758b783..14948360d102 100644
--- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Izslēgts"</item>
<item msgid="3028994095749238254">"Ieslēgts"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nav pieejams"</item>
+ <item msgid="6419996398343291862">"Izslēgts"</item>
+ <item msgid="5908720590832378783">"Ieslēgts"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e30cf21fceec..f8bfcf9296ca 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Влез"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слушни помагала"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Се вклучува…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Не може да се приспособи осветленоста бидејќи е\n контролирана од горната апликација"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматско ротирање"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматско ротирање на екранот"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за да спарите нов уред"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Не можеше да се ажурира зададената вредност"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Зададени вредности"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Избрано"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Алатки"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Автоматски титлови"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Белешка"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се одблокира пристапот до микрофонот на уредот?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се одблокира пристапот до камерата на уредот?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се одблокира пристапот до камерата и микрофонот на уредот?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Започни сега"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Нема известувања"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Нема нови известувања"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"„Подискретни известувања“ сега е вклучена"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Јачината на звукот и известувањата на уредот се намалуваат автоматски до 2 минути кога добивате премногу известувања одеднаш."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Исклучи"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Отклучете за да ги видите старите известувања"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Префрлете се на апликацијата десно или долу при користењето поделен екран"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Префрлете се на апликацијата лево или горе при користењето поделен екран"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"При поделен екран: префрлете ги аплик. од едната на другата страна"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Движете го активниот прозорец меѓу екраните"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Внесување"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Префрлете на следниот јазик"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Префрлете на претходниот јазик"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Употребете помалку од <xliff:g id="LENGTH">%1$d</xliff:g> знаци"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Започни разговор"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Виџети за разговор"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Допрете разговор за да го додадете на почетниот екран"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Отворете го телефонот за да добиете повисока резолуција"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Преклопувачки уред се отклопува"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Преклопувачки уред се врти"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворен"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворен"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Пристапност"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Кратенки од тастатура"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Приспособете ги кратенките од тастатурата"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Притиснете го копчето за да доделите кратенка"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пребарувајте кратенки"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Нема резултати од пребарување"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за собирање"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Икона за дејство или копче за дејство"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Икона плус"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Приспособете"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Готово"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширување"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Рачка за влечење"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Поставки за тастатурата"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Поставете кратенка"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Откажи"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Притиснете го копчето"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Комбинацијата на копчиња веќе се користи. Обидете се со друго копче."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Движете се со користење на тастатурата"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете ги кратенките од тастатурата"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Движете се со користење на допирната подлога"</string>
diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
index 61539d62baf7..17545c332b63 100644
--- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Исклучено"</item>
<item msgid="3028994095749238254">"Вклучено"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Недостапно"</item>
+ <item msgid="6419996398343291862">"Исклучено"</item>
+ <item msgid="5908720590832378783">"Вклучено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 42f67c6558c2..54364c804581 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ഇൻപുട്ട്"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ശ്രവണ സഹായികൾ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ഓണാക്കുന്നു…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"തെളിച്ചം അഡ്‌ജസ്റ്റ് ചെയ്യാനാകില്ല, അത്\n നിയന്ത്രിക്കുന്നത് ഏറ്റവും മുകളിലുള്ള ആപ്പാണ്"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"സ്‌ക്രീൻ സ്വയമേവ തിരിയൽ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"സ്‌ക്രീൻ സ്വയമേവ തിരിക്കുക"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ലൊക്കേഷൻ"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"പുതിയ ഉപകരണം ജോടിയാക്കാൻ ക്ലിക്ക് ചെയ്യുക"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"പ്രീസെറ്റ് അപ്ഡേറ്റ് ചെയ്യാനായില്ല"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"പ്രീസെറ്റ്"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"തിരഞ്ഞെടുത്തു"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ടൂളുകൾ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"തത്സമയ ക്യാപ്ഷൻ"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"കുറിപ്പ്"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ഉപകരണ മൈക്രോഫോൺ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ഉപകരണ ക്യാമറ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ഉപകരണ ക്യാമറയോ മൈക്രോഫോണോ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"ഇപ്പോൾ ആരംഭിക്കുക"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"അറിയിപ്പുകൾ ഒന്നുമില്ല"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"പുതിയ അറിയിപ്പുകളൊന്നുമില്ല"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"അറിയിപ്പിന്റെ ശബ്ദം കുറയ്ക്കൽ ഇപ്പോൾ ഓണാണ്"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"നിരവധി അറിയിപ്പ് ഒരുമിച്ച് ലഭിക്കുമ്പോൾ, ഉപകരണത്തിന്റെ ശബ്‌ദവും മുന്നറിയിപ്പും 2 മിനിറ്റ് വരെ സ്വയമേവ കുറയ്ക്കും."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ഓഫാക്കുക"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"പഴയ അറിയിപ്പുകൾ കാണാൻ അൺലോക്ക് ചെയ്യുക"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ വലതുവശത്തെ/താഴത്തെ ആപ്പിലേക്ക് മാറുക"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ ഇടതുവശത്തെ/മുകളിലെ ആപ്പിലേക്ക് മാറൂ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"സ്‌ക്രീൻ വിഭജന മോഡിൽ: ഒരു ആപ്പിൽ നിന്ന് മറ്റൊന്നിലേക്ക് മാറുക"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"സജീവ വിൻഡോകൾ ഡിസ്‌പ്ലേകൾക്ക് ഇടയിൽ നീക്കുക"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ഇൻപുട്ട്"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"അടുത്ത ഭാഷയിലേക്ക് മാറുക"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"മുമ്പത്തെ ഭാഷയിലേക്ക് മാറുക"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>-ൽ കുറവ് പ്രതീകങ്ങൾ ഉപയോഗിക്കുക"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"സംഭാഷണം തുറക്കുക"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"സംഭാഷണ വിജറ്റുകൾ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"നിങ്ങളുടെ ഹോം സ്‌ക്രീനിൽ ചേർക്കാൻ സംഭാഷണത്തിൽ ടാപ്പ് ചെയ്യുക"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ഉയർന്ന റെസല്യൂഷന്, ഫോൺ ഫ്ലിപ്പ് ചെയ്യുക"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം അൺഫോൾഡ് ആകുന്നു"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം, കറങ്ങുന്ന വിധത്തിൽ ഫ്ലിപ്പ് ആകുന്നു"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ഫോൾഡ് ചെയ്തത്"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"അൺഫോൾഡ് ചെയ്തത്"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ഉപയോഗസഹായി"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"കീബോഡ് കുറുക്കുവഴികൾ"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"കീബോർഡ് കുറുക്കുവഴികൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"കുറുക്കുവഴി അസൈൻ ചെയ്യാൻ കീ അമർത്തുക"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"തിരയൽ കുറുക്കുവഴികൾ"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"തിരയൽ ഫലങ്ങളൊന്നുമില്ല"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ആക്ഷൻ/മെറ്റാ കീ ഐക്കൺ"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"പ്ലസ് ഐക്കൺ"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"ഇഷ്‌ടാനുസൃതമാക്കുക"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"പൂർത്തിയായി"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"വികസിപ്പിക്കൽ ഐക്കൺ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"അല്ലെങ്കിൽ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"വലിച്ചിടുന്നതിനുള്ള ഹാൻഡിൽ"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"കീബോർഡ് ക്രമീകരണം"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"കുറുക്കുവഴി സജ്ജീകരിക്കുക"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"റദ്ദാക്കുക"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"കീ അമർത്തുക"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"കീ കോമ്പിനേഷൻ ഇതിനകം ഉപയോഗത്തിലുണ്ട്. മറ്റൊരു കീ പരീക്ഷിക്കുക."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"നിങ്ങളുടെ കീബോർഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"കീബോർഡ് കുറുക്കുവഴികൾ മനസ്സിലാക്കുക"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"നിങ്ങളുടെ ടച്ച്‌പാഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
index c1278d46440f..689fe85bf3e6 100644
--- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ഓഫാണ്"</item>
<item msgid="3028994095749238254">"ഓണാണ്"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"ലഭ്യമല്ല"</item>
+ <item msgid="6419996398343291862">"ഓഫാണ്"</item>
+ <item msgid="5908720590832378783">"ഓണാണ്"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index c87f98acd3e9..0e2dc23e88c1 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Оролт"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Сонсголын төхөөрөмж"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Асааж байна…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Гэрэлтүүлгийг\nдавуу эрхтэй аппаас хянаж байгаа тул тохируулах боломжгүй"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматаар эргэх"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Дэлгэцийг автоматаар эргүүлэх"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Байршил"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Шинэ төхөөрөмж хослуулахын тулд товшино уу"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Урьдчилсан тохируулгыг шинэчилж чадсангүй"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Урьдчилсан тохируулга"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Сонгосон"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Хэрэгсэл"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Шууд тайлбар"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Тэмдэглэл"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Төхөөрөмжийн микрофоныг блокоос гаргах уу?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Төхөөрөмжийн камерыг блокоос гаргах уу?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Төхөөрөмжийн камер болон микрофоныг блокоос гаргах уу?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Одоо эхлүүлэх"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Мэдэгдэл байхгүй"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Шинэ мэдэгдэл алга"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Мэдэгдлийн хөргөлт одоо асаалттай байна"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Таныг хэт олон мэдэгдэл нэг дор авахад таны төхөөрөмжийн дууны түвшин болон дохиог 2 хүртэлх минутын турш автоматаар багасгадаг."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Унтраах"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Хуучин мэдэгдлийг харах бол түгжээг тайл"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Дэлгэц хуваахыг ашиглаж байхдаа баруун талд эсвэл доор байх апп руу сэлгэ"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Дэлгэц хуваахыг ашиглаж байхдаа зүүн талд эсвэл дээр байх апп руу сэлгэ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Дэлгэц хуваах үеэр: аппыг нэгээс нөгөөгөөр солих"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Идэвхтэй цонхыг дэлгэц хооронд зөөх"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Оролт"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Дараагийн хэл рүү сэлгэх"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Өмнөх хэл рүү сэлгэх"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>-с цөөн тэмдэгт ашиглана уу"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Хийцийн дугаарыг түр санах ойд хуулсан."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Харилцан яриаг нээх"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Харилцан ярианы виджетүүд"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Үндсэн нүүрэндээ нэмэх харилцан яриаг товшино уу"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Илүү өндөр нягтрал авах бол утсыг хөнтөрнө үү"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Эвхэгддэг төхөөрөмжийг дэлгэж байна"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Эвхэгддэг төхөөрөмжийг хөнтөрч байна"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"эвхсэн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"дэлгэсэн"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Хандалт"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Товчлуурын шууд холбоос"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Товчлуурын шууд холбоосыг өөрчлөх"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Товчлол оноохын тулд товч дарна уу"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Товчлолууд хайх"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ямар ч хайлтын илэрц байхгүй"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Хураах дүрс тэмдэг"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Үйлдлийн товч буюу өөрөөр Мета товчийн дүрс тэмдэг"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Нэмэх дүрс тэмдэг"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Өөрчлөх"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Болсон"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"эсвэл"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Чирэх бариул"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Гарын тохиргоо"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Товчлол тохируулах"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Цуцлах"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Товч дарна уу"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Товчийн хослолыг аль хэдийн ашиглаж байна. Өөр товч туршиж үзнэ үү."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Гараа ашиглан шилжих"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Товчлуурын шууд холбоосыг мэдэж аваарай"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Мэдрэгч самбараа ашиглан шилжээрэй"</string>
diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
index da890cc5a157..94e393961988 100644
--- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Унтраалттай"</item>
<item msgid="3028994095749238254">"Асаалттай"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Боломжгүй"</item>
+ <item msgid="6419996398343291862">"Унтраалттай"</item>
+ <item msgid="5908720590832378783">"Асаалттай"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 204399c77b96..cd9062252425 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"श्रवणयंत्रे"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सुरू करत आहे…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ब्राइटनेस ॲडजस्ट करू शकत नाही, कारण तो\n टॉप ॲपद्वारे नियंत्रित केला जात आहे"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ऑटो-रोटेट स्क्रीन"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नवीन डिव्हाइस पेअर करण्यासाठी क्लिक करा"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"प्रीसेट अपडेट करता आले नाही"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"प्रीसेट"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"निवडला आहे"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"टूल"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"लाइव्ह कॅप्शन"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"टीप"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिव्हाइसचा मायक्रोफोन अनब्लॉक करायचा आहे का?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिव्हाइसचा कॅमेरा अनब्लॉक करायचा आहे का?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिव्हाइसचा कॅमेरा आणि मायक्रोफोन अनब्लॉक करायचा आहे का?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन वापरताना उजवीकडील किंवा खालील अ‍ॅपवर स्विच करा"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन वापरताना डावीकडील किंवा वरील अ‍ॅपवर स्विच करा"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रीनदरम्यान: एक अ‍ॅप दुसऱ्या अ‍ॅपने बदला"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ॲक्टिव्ह विंडो डिस्प्लेदरम्यान हलवा"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"इनपुट"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"पुढील भाषेवर स्विच करा"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"मागील भाषेवर स्विच करा"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> वर्णांपेक्षा कमी वर्ण वापरा"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"संभाषण उघडा"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"संभाषण विजेट"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"तुमच्या होम स्क्रीन वर संभाषण जोडण्यासाठी त्यावर टॅप करा"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"उच्च रेझोल्यूशनसाठी, फोन फ्लिप करा"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड करता येण्यासारखे डिव्हाइस अनफोल्ड केले जात आहे"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड करता येण्यासारखे डिव्हाइस आजूबाजूला फ्लिप केले जात आहे"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड केलेले"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"फोल्ड न केलेले"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"अ‍ॅक्सेसिबिलिटी"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"कीबोर्ड शॉर्टकट कस्टमाइझ करा"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"शॉर्टकट असाइन करण्यासाठी की प्रेस करा"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शोधण्यासाठी शॉर्टकट"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"कोणतेही शोध परिणाम नाहीत"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"कृती किंवा मेटा की आयकन"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"अधिक आयकन"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"कस्टमाइझ करा"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"पूर्ण झाले"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"विस्तार करा आयकन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"किंवा"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ड्रॅग हॅंडल"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"कीबोर्ड सेटिंग्ज"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"शॉर्टकट सेट करा"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द करा"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"की प्रेस करा"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"की कॉम्बिनेशन आधीपासून वापरले जात आहे. दुसरी की वापरून पहा."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"तुमचा कीबोर्ड वापरून नेव्हिगेट करा"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट जाणून घ्या"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"तुमचा टचपॅड वापरून नेव्हिगेट करा"</string>
diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
index 3ea25a68922b..cbaefb9367c2 100644
--- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"बंद आहे"</item>
<item msgid="3028994095749238254">"सुरू आहे"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"उपलब्ध नाही"</item>
+ <item msgid="6419996398343291862">"बंद आहे"</item>
+ <item msgid="5908720590832378783">"सुरू आहे"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index ce2b3f07c547..c108fc476da0 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Alat bantu pendengaran"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Menghidupkan…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Tidak dapat melaraskan kecerahan kerana peranti\n dikawal oleh apl popular"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoputar"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoputar skrin"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menggandingkan peranti baharu"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Tidak dapat mengemaskinikan pratetapan"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Pratetapan"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Dipilih"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alatan"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sari Kata Langsung"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Nyahsekat mikrofon peranti?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Nyahsekat kamera peranti?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Nyahsekat kamera dan mikrofon peranti?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Tukar kepada apl di sebelah kanan/bawah semasa menggunakan skrin pisah"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Tukar kepada apl di sebelah kiri/atas semasa menggunakan skrin pisah"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Semasa skrin pisah: gantikan apl daripada satu apl kepada apl lain"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Alihkan tetingkap aktif antara paparan"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Beralih kepada bahasa seterusnya"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Beralih kepada bahasa sebelumnya"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gunakan kurang daripada <xliff:g id="LENGTH">%1$d</xliff:g> aksara"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widget perbualan"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Ketik perbualan untuk menambahkan perbualan itu pada skrin Utama anda"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Untuk peleraian lebih tinggi, balikkan telefon"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Peranti boleh lipat dibuka"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Peranti boleh lipat diterbalikkan"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"terlipat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tidak terlipat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kebolehaksesan"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan papan kekunci"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sesuaikan pintasan papan kekunci"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tekan kekunci untuk menetapkan pintasan"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Tiada hasil carian"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikon kekunci tindakan atau Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikon tambah"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Sesuaikan"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Selesai"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Pemegang seret"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tetapan Papan Kekunci"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tetapkan pintasan"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Batal"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tekan kekunci"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Gabungan kekunci sudah digunakan. Cuba kekunci lain."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigasi menggunakan papan kekunci"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ketahui pintasan papan kekunci"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigasi menggunakan pad sentuh anda"</string>
@@ -1449,17 +1445,17 @@
<string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat apl terbaharu"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
- <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Leret ke kiri atau ke kanan menggunakan tiga jari pada pad sentuh anda"</string>
+ <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Leret ke kiri atau ke kanan menggunakan tiga jari pada pad sentuh"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bagus!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah melengkapkan gerak isyarat undur."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah melengkapkan gerak isyarat kembali."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Akses laman utama"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Leret ke atas dengan tiga jari pada pad sentuh anda"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bagus!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Anda telah melengkapkan gerak isyarat akses laman utama"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Lihat apl terbaharu"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Leret ke atas dan tahan menggunakan tiga jari pada pad sentuh anda"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Leret ke atas dan tahan menggunakan tiga jari pada pad sentuh"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Syabas!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda melengkapkan gerak isyarat lihat apl terbaharu."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah melengkapkan gerak isyarat lihat apl terbaharu."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua apl"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan kekunci tindakan pada papan kekunci anda"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Syabas!"</string>
diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
index 51f215b31931..3c78bccfef53 100644
--- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Mati"</item>
<item msgid="3028994095749238254">"Hidup"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Tidak tersedia"</item>
+ <item msgid="6419996398343291862">"Mati"</item>
+ <item msgid="5908720590832378783">"Hidup"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index a3568f2b56bb..ce52f4e4e024 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"အဝင်"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"နားကြားကိရိယာ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ဖွင့်နေသည်…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"၎င်းကို ထိပ်ဆုံးရှိအက်ပ်က\n ထိန်းချုပ်နေသဖြင့် တောက်ပမှုကို ပြင်ဆင်၍မရပါ"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"အော်တို-လည်"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"မျက်နှာပြင်အား အလိုအလျောက်လှည့်ခြင်း"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"တည်နေရာ"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"စက်အသစ် တွဲချိတ်ရန် နှိပ်ပါ"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"အသင့်သုံးကို အပ်ဒိတ်လုပ်၍မရပါ"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ကြိုတင်သတ်မှတ်ချက်"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ရွေးထားသည်"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"တူးလ်များ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"တိုက်ရိုက်စာတန်း"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"မှတ်စု"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"စက်၏မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"စက်၏ကင်မရာကို ပြန်ဖွင့်မလား။"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"စက်၏ကင်မရာနှင့် မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"ယခု စတင်ပါ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"အကြောင်းကြားချက် မရှိပါ"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"အကြောင်းကြားချက်သစ် မရှိပါ"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"အကြောင်းကြားချက် သတိပေးမှု လျှော့ချခြင်း ဖွင့်လိုက်ပြီ"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"အကြောင်းကြားချက်များစွာ တစ်ပြိုင်နက်ရပါက သင့်စက်၏ အသံနှင့် သတိပေးချက်ကို ၂ မိနစ်ကြာသည်အထိ အလိုအလျောက်လျှော့ချသည်။"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ပိတ်ရန်"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"အကြောင်းကြားချက်ဟောင်းကြည့်ရန် လော့ခ်ဖွင့်ပါ"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"မျက်နှာပြင်ခွဲ၍ပြသခြင်း သုံးစဉ် ညာ (သို့) အောက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးစဉ် ဘယ် (သို့) အထက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"မျက်နှာပြင် ခွဲ၍ပြသစဉ်- အက်ပ်တစ်ခုကို နောက်တစ်ခုနှင့် အစားထိုးရန်"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"လက်ရှိဝင်းဒိုးကို ပြကွက်များအကြား ရွှေ့ခြင်း"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"စာရိုက်ခြင်း"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"နောက်ဘာသာစကားသို့ ပြောင်းရန်"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"ယခင်ဘာသာစကားသို့ ပြောင်းရန်"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"အက္ခရာ <xliff:g id="LENGTH">%1$d</xliff:g> လုံးအောက် သုံးရန်"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်ပုံအမှတ်"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"စကားဝိုင်းကို ဖွင့်ရန်"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"စကားဝိုင်း ဝိဂျက်များ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"စကားဝိုင်းကို သင်၏ ‘ပင်မစာမျက်နှာ’ သို့ထည့်ရန် တို့ပါ"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ပုံရိပ် ပိုမိုပြတ်သားစေရန် ဖုန်းကို တစ်ဖက်သို့ လှန်လိုက်ပါ"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ခေါက်နိုင်သောစက်ကို ဖြန့်လိုက်သည်"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ခေါက်နိုင်သောစက်ကို တစ်ဘက်သို့ လှန်လိုက်သည်"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ခေါက်ထားသည်"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ဖြန့်ထားသည်"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"အများသုံးနိုင်မှု"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"လက်ကွက်ဖြတ်လမ်းများ"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"လက်ကွက်ဖြတ်လမ်းများကို စိတ်ကြိုက်လုပ်ခြင်း"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ဖြတ်လမ်းသတ်မှတ်ရန် ကီးကို နှိပ်ပါ"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ဖြတ်လမ်းများ ရှာရန်"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ရှာဖွေမှုရလဒ် မရှိပါ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"လျှော့ပြရန် သင်္ကေတ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"လုပ်ဆောင်ချက် (သို့) Meta ကီးသင်္ကေတ"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"အပေါင်းသင်္ကေတ"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"စိတ်ကြိုက်လုပ်ရန်"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ပြီးပြီ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ပိုပြရန် သင်္ကေတ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"သို့မဟုတ်"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ဖိဆွဲအထိန်း"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ကီးဘုတ်ဆက်တင်များ"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ဖြတ်လမ်း သတ်မှတ်ရန်"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"မလုပ်တော့"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ကီးကို နှိပ်ပါ"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ကီးပေါင်းစပ်ခြင်းကို သုံးနေပြီးဖြစ်သည်။ အခြားကီးကို စမ်းကြည့်ပါ။"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"သင့်ကီးဘုတ်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"လက်ကွက်ဖြတ်လမ်းများကို လေ့လာပါ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"သင့်တာ့ချ်ပက်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string>
@@ -1461,7 +1456,7 @@
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"သင့်တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"တော်ပါပေသည်။"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"မကြာသေးမီကအက်ပ်များကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ။"</string>
- <string name="tutorial_action_key_title" msgid="8172535792469008169">"အက်ပ်အားလုံးကို ကြည့်ရန်"</string>
+ <string name="tutorial_action_key_title" msgid="8172535792469008169">"အက်ပ်အားလုံးကို ကြည့်ခြင်း"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ကီးဘုတ်တွင် လုပ်ဆောင်ချက်ကီး နှိပ်ပါ"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"အလွန်ကောင်းပါသည်။"</string>
<string name="tutorial_action_key_success_body" msgid="1688986269491357832">"အက်ပ်အားလုံးကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ"</string>
diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml
index 7af75166de11..9675cb5b46b4 100644
--- a/packages/SystemUI/res/values-my/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ပိတ်"</item>
<item msgid="3028994095749238254">"ဖွင့်"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"မရနိုင်ပါ"</item>
+ <item msgid="6419996398343291862">"ပိတ်"</item>
+ <item msgid="5908720590832378783">"ဖွင့်"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 38b267332f47..db352a5fc4b0 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Innenhet"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Slår på …"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Kan ikke justere lysstyrken, fordi den\n kontrolleres av appen på toppen"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotér automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotér skjermen automatisk"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sted"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klikk for å koble til en ny enhet"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Kunne ikke oppdatere forhåndsinnstillingen"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forhåndsinnstilling"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valgt"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Verktøy"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Direkteteksting"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Merknad"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du oppheve blokkeringen av enhetsmikrofonen?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du oppheve blokkeringen av enhetskameraet?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du oppheve blokkeringen av enhetskameraet og -mikrofonen?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Start nå"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ingen varsler"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Ingen nye varsler"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Nå er varseldempingen slått på"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Enhetsvolumet og varsler reduseres automatisk i opptil 2 min når du får for mange varsler samtidig."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Slå av"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Lås opp for å se eldre varsler"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bytt til appen til høyre eller under mens du bruker delt skjerm"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bytt til appen til venstre eller over mens du bruker delt skjerm"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"I delt skjerm: Bytt ut en app"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Flytt det aktive vinduet mellom skjermer"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Skrivespråk"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Bytt til neste språk"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Bytt til forrige språk"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Bruk færre enn <xliff:g id="LENGTH">%1$d</xliff:g> tegn"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Åpen samtale"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Samtalemoduler"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Trykk på en samtale for å legge den til på startskjermen"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Brett ut telefonen for å få høyere oppløsning"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En foldbar enhet blir brettet ut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En foldbar enhet blir snudd"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"lagt sammen"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"åpen"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tilgjengelighet"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Hurtigtaster"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tilpass hurtigtastene"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Trykk på tasten for å tilordne hurtigtasten"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snarveier til søk"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ingen søkeresultater"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Handlings- eller Meta-tast-ikon"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plussikon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Tilpass"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Ferdig"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vis-ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Håndtak"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastaturinnstillinger"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Angi hurtigtast"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Avbryt"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Trykk på tasten"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tastekombinasjonen brukes allerede. Prøv en annen tast."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger med tastaturet"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lær deg hurtigtaster"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger med styreflaten"</string>
diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
index 3ed1a4e4aa7a..bd5b69279714 100644
--- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Av"</item>
<item msgid="3028994095749238254">"På"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Utilgjengelig"</item>
+ <item msgid="6419996398343291862">"Av"</item>
+ <item msgid="5908720590832378783">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 82f9aca68198..2c1d7271ac19 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -73,7 +73,7 @@
<string name="learn_more" msgid="4690632085667273811">"थप जान्नुहोस्"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string>
<string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"एक्स्टेन्ड अनलक अफ गरिएको छ"</string>
- <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string>
+ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै फोटो पठाइयो"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"कार्य प्रोफाइलमा स्क्रिनसट सेभ गरिँदै छ…"</string>
<string name="screenshot_saving_private_profile" msgid="8934706048497093297">"निजी प्रोफाइलमा स्क्रिनसट सेभ गरिँदै छ"</string>
@@ -116,7 +116,7 @@
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"तपाईंले आफ्नो पूरै स्क्रिन रेकर्ड गरिरहेका बेला तपाईंको स्क्रिनमा देखाइने सबै सामग्री रेकर्ड गरिन्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"तपाईंले यो एप रेकर्ड गरिरहेका बेला यो एपमा देखाइने वा प्ले गरिने सबै सामग्री रेकर्ड गरिन्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"स्क्रिन रेकर्ड गर्नुहोस्"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"रेकर्ड गर्न छनौट गर्नुहोस्"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"रेकर्ड गर्न एप छनौट गर्नुहोस्"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"अडियो रेकर्ड गर्नुहोस्"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिभाइसको अडियो"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"तपाईंको डिभाइसका सङ्गीत, कल र रिङटोन जस्ता साउन्ड"</string>
@@ -311,7 +311,7 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"डिस्कनेक्ट गर्नुहोस्"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"एक्टिभेट गर्नुहोस्"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"भोलि स्वतः अन गर्नुहोस्"</string>
- <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक सेयर र Find My Device जस्ता सुविधाहरू प्रयोग गर्न ब्लुटुथ चाहिन्छ"</string>
+ <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक सेयर र Find My Device जस्ता सुविधाहरू प्रयोग गर्न ब्लुटुथ अन गर्नु पर्ने हुन्छ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लुटुथ भोलि बिहान अन हुने छ"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"अडियो सेयर गर्नुहोस्"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"अडियो सेयर गरिँदै छ"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"हियरिङ डिभाइसहरू"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सक्रिय गर्दै…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"टप एपले चमक नियन्त्रण गरिरहेकाले\n चमक मिलाउन मिल्दैन"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अटो रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"लोकेसन"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नयाँ डिभाइसमा कनेक्ट गर्न क्लिक गर्नुहोस्"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"प्रिसेट अपडेट गर्न सकिएन"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"पूर्वनिर्धारित"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"चयन गरिएको छ"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"टुल"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"लाइभ क्याप्सन"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"नोट"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिभाइसको माइक्रोफोन अनब्लक गर्ने हो?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिभाइसको क्यामेरा अनब्लक गर्ने हो?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिभाइसको क्यामेरा र माइक्रोफोन अनब्लक गर्ने हो?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा दायाँ वा तलको एप चलाउनुहोस्"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा बायाँ वा माथिको एप चलाउनुहोस्"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रिन प्रयोग गरिएका बेला: एउटा स्क्रिनमा भएको एप अर्कोमा लैजानुहोस्"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"सक्रिय विन्डोलाई एउटा डिस्प्लेबाट सारेर अर्को डिस्प्लेमा लैजानुहोस्"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"इनपुट"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"अर्को भाषा प्रयोग गर्नुहोस्"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"अघिल्लो भाषा प्रयोग गर्नुहोस्"</string>
@@ -1006,7 +1005,7 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi‑Fi अफ छ"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ब्लुटुथ अफ छ"</string>
- <string name="dnd_is_off" msgid="3185706903793094463">"बाधा नपुर्‍याउनुहोस् नामक विकल्प निष्क्रिय छ"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"बाधा नपुर्‍याउनुहोस् नामक विकल्प अफ छ"</string>
<string name="dnd_is_on" msgid="7009368176361546279">"Do Not Disturb अन छ"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"कुनै स्वचालित नियमले बाधा नपुऱ्याउनुहोस् नामक विकल्पलाई सक्रियो गऱ्यो (<xliff:g id="ID_1">%s</xliff:g>)।"</string>
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"कुनै एपले बाधा नपुऱ्याउनुहोस् नामक विकल्पलाई सक्रिय गऱ्यो (<xliff:g id="ID_1">%s</xliff:g>)।"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> वटा भन्दा कम वर्ण प्रयोग गर्नुहोस्"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"वार्तालाप खोल्नुहोस्"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"वार्तालापसम्बन्धी विजेटहरू"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"कुनै वार्तालाप होम स्क्रिनमा हाल्न उक्त वार्तालापमा ट्याप गर्नुहोस्"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"उच्च रिजोल्युसनको सेल्फी खिच्न फोन फ्लिप गर्नुहोस्"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड गर्न मिल्ने डिभाइस अनफोल्ड गरेको देखाइएको एनिमेसन"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड गर्न मिल्ने डिभाइस यताउता पल्टाएर देखाइएको एनिमेसन"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड गरिएको"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"अनफोल्ड गरिएको"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सर्वसुलभता"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"किबोर्डका सर्टकटहरू"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"किबोर्डका सर्टकटहरू कस्टमाइज गर्नुहोस्"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"सर्टकट असाइन गर्न की थिच्नुहोस्"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"खोजका सर्टकटहरू"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"कुनै पनि खोज परिणाम भेटिएन"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"एक्सन वा Meta कीको आइकन"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"प्लस आइकन"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"कस्टमाइज गर्नुहोस्"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"पूरा भयो"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\"एक्स्पान्ड गर्नुहोस्\" आइकन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"वा"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ड्र्याग ह्यान्डल"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"किबोर्डसम्बन्धी सेटिङ"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"सर्टकट सेट गर्नुहोस्"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द गर्नुहोस्"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"की थिच्नुहोस्"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"यो की कम्बिनेसन प्रयोग गरिसकिएको छ। अर्कै की प्रयोग गरी हेर्नुहोस्।"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"किबोर्ड प्रयोग गरी नेभिगेट गर्नुहोस्"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"किबोर्डका सर्टकटहरू प्रयोग गर्न सिक्नुहोस्"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचप्याड प्रयोग गरी नेभिगेट गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
index 2350c67d2bcf..2dd209d8565b 100644
--- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"अफ छ"</item>
<item msgid="3028994095749238254">"अन छ"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"उपलब्ध छैन"</item>
+ <item msgid="6419996398343291862">"अफ छ"</item>
+ <item msgid="5908720590832378783">"अन छ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3e0b5d9d144d..0d195a3b40d7 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hoortoestellen"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aanzetten…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Kan de helderheid niet aanpassen omdat deze wordt\n beheerd door de bovenste app"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Scherm automatisch draaien"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locatie"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nieuw apparaat te koppelen"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Kan voorinstelling niet updaten"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Voorinstelling"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Geselecteerd"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live ondertiteling"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notitie"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Microfoon van apparaat niet meer blokkeren?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Apparaatcamera niet meer blokkeren?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blokkeren van apparaatcamera en -microfoon opheffen?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Naar de app rechts of onderaan gaan als je een gesplitst scherm gebruikt"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Naar de app links of bovenaan gaan als je een gesplitst scherm gebruikt"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Tijdens gesplitst scherm: een app vervangen door een andere"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Actief venster verplaatsen tussen schermen"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Invoer"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Overschakelen naar volgende taal"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Overschakelen naar vorige taal"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gebruik minder dan <xliff:g id="LENGTH">%1$d</xliff:g> tekens"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummer naar klembord gekopieerd."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Gesprekswidgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tik op een gesprek om het toe te voegen aan je startscherm"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Draai de telefoon om voor een hogere resolutie"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Opvouwbaar apparaat wordt uitgevouwen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Opvouwbaar apparaat wordt gedraaid"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dichtgevouwen"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opengevouwen"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toegankelijkheid"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Sneltoetsen"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sneltoetsen aanpassen"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Druk op de toets om de sneltoets toe te wijzen"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sneltoetsen zoeken"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Geen zoekresultaten"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icoon voor actie- of metatoets"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plusicoon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Aanpassen"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Klaar"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icoon voor uitvouwen"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handgreep voor slepen"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Toetsenbordinstellingen"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Sneltoets instellen"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuleren"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Druk op een toets"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Toetsencombinatie is al in gebruik. Probeer een andere toets."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeren met je toetsenbord"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer sneltoetsen die je kunt gebruiken"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeren met je touchpad"</string>
diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
index 4193463cae8e..221749c2c90b 100644
--- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Uit"</item>
<item msgid="3028994095749238254">"Aan"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Niet beschikbaar"</item>
+ <item msgid="6419996398343291862">"Uit"</item>
+ <item msgid="5908720590832378783">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 980c47d13883..181315ba045c 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ଇନପୁଟ୍"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ଅନ୍ ହେଉଛି…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ଟପ ଆପ ଦ୍ୱାରା ଉଜ୍ଜ୍ୱଳତା ନିୟନ୍ତ୍ରିତ\nହେଉଥିବା ଯୋଗୁଁ ଏହାକୁ ଆଡଜଷ୍ଟ କରିପାରିବେ ନାହିଁ"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ଅଟୋ-ରୋଟେଟ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ଅଟୋ-ରୋଟେଟ ସ୍କ୍ରିନ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ଲୋକେସନ"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ନୂଆ ଡିଭାଇସ ପେୟାର କରିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ପ୍ରିସେଟକୁ ଅପଡେଟ କରାଯାଇପାରିଲା ନାହିଁ"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ପ୍ରିସେଟ"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ଚୟନ କରାଯାଇଛି"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ଟୁଲ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ଲାଇଭ କେପ୍ସନ"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"ନୋଟ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ କରିବେ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ଡିଭାଇସର କେମେରାକୁ ଅନବ୍ଲକ କରିବେ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ଡିଭାଇସର କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"କୌଣସି ନୂଆ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ନାହିଁ"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"ବିଜ୍ଞପ୍ତି କୁଲଡାଉନ ବର୍ତ୍ତମାନ ଚାଲୁ ଅଛି"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ଆପଣ ଥରକେ ଏକାଧିକ ବିଜ୍ଞପ୍ତି ପ୍ରାପ୍ତ କଲେ ଆପଣଙ୍କ ଡିଭାଇସର ଭଲ୍ୟୁମ ଓ ଆଲର୍ଟ ସ୍ୱତଃ 2 ମିନିଟ ପର୍ଯ୍ୟନ୍ତ କମ ହୁଏ।"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ପୁରୁଣା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଦେଖିବାକୁ ଅନଲକ କରନ୍ତୁ"</string>
@@ -699,7 +698,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ନଏଜ କଣ୍ଟ୍ରୋଲ"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"ସ୍ପାସିଅଲ ଅଡିଓ"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"ବନ୍ଦ ଅଛି"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"ନିଶ୍ଚିତ ହୋଇଛି"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"ଠିକ ହୋଇଯାଇଛି"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ହେଡ ଟ୍ରାକିଂ"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"ରିଙ୍ଗର୍ ମୋଡ୍ ବଦଳାଇବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="volume_ringer_mode" msgid="6867838048430807128">"ରିଂଗର ମୋଡ"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ଡାହାଣପଟର ବା ତଳର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ବାମପଟର ବା ଉପରର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ସମୟରେ: କୌଣସି ଆପକୁ ଗୋଟିଏରୁ ଅନ୍ୟ ଏକ ଆପରେ ବଦଳାନ୍ତୁ"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ସକ୍ରିୟ ୱିଣ୍ଡୋକୁ ଡିସପ୍ଲେଗୁଡ଼ିକ ମଧ୍ୟରେ ମୁଭ କରନ୍ତୁ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ଇନପୁଟ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ପରବର୍ତ୍ତୀ ଭାଷାକୁ ସୁଇଚ କରନ୍ତୁ"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"ପୂର୍ବବର୍ତ୍ତୀ ଭାଷାକୁ ସୁଇଚ କରନ୍ତୁ"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>ଟିରୁ କମ କେରେକ୍ଟର ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"ବାର୍ତ୍ତାଳାପ ଖୋଲନ୍ତୁ"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ବାର୍ତ୍ତାଳାପ ୱିଜେଟଗୁଡ଼ିକ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ଏକ ବାର୍ତ୍ତାଳାପକୁ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନରେ ଯୋଗ କରିବା ପାଇଁ ସେଥିରେ ଟାପ କରନ୍ତୁ"</string>
@@ -1291,7 +1291,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ଟାଇଲ୍ ଯୋଗ କର ନାହିଁ"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ୟୁଜର ଚୟନ କରନ୍ତୁ"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{#ଟି ଆପ ସକ୍ରିୟ ଅଛି}other{#ଟି ଆପ ସକ୍ରିୟ ଅଛି}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# ଆପ ସକ୍ରିୟ ଅଛି}other{# ଆପ ସକ୍ରିୟ ଅଛି}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"ନୂଆ ସୂଚନା"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ସକ୍ରିୟ ଆପ୍ସ"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"ଆପଣ ଏହି ଆପ୍ସକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ ସେଗୁଡ଼ିକ ସକ୍ରିୟ ରହିଥାଏ ଏବଂ ଚାଲୁଥାଏ। ଏହା ସେଗୁଡ଼ିକର କାର୍ଯ୍ୟକ୍ଷମତାକୁ ଉନ୍ନତ କରେ, କିନ୍ତୁ ଏହା ମଧ୍ୟ ବେଟେରୀ ଲାଇଫକୁ ପ୍ରଭାବିତ କରିପାରେ।"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ଉଚ୍ଚ ରିଜୋଲ୍ୟୁସନ ପାଇଁ ଫୋନକୁ ଫ୍ଲିପ କରନ୍ତୁ"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରାଯାଉଛି"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଫ୍ଲିପ କରାଯାଉଛି"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ଫୋଲ୍ଡେଡ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ଅନଫୋଲ୍ଡେଡ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ଆକ୍ସେସିବିଲିଟୀ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"କୀବୋର୍ଡ ସର୍ଟକଟ"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"କୀବୋର୍ଡ ସର୍ଟକଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ସର୍ଟକଟ ଆସାଇନ କରିବା ପାଇଁ କୀ\'କୁ ଦବାନ୍ତୁ"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ସର୍ଚ୍ଚ ସର୍ଟକଟ"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"କୌଣସି ସର୍ଚ୍ଚ ଫଳାଫଳ ନାହିଁ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ଆଇକନକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ଆକ୍ସନ କିମ୍ବା ମେଟା କୀ ଆଇକନ"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ପ୍ଲସ ଆଇକନ"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ହୋଇଗଲା"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ଆଇକନକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"କିମ୍ବା"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ଡ୍ରାଗ ହେଣ୍ଡେଲ"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"କୀବୋର୍ଡ ସେଟିଂ"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ସର୍ଟକଟ ସେଟ କରନ୍ତୁ"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ବାତିଲ କରନ୍ତୁ"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"କୀ ଦବାନ୍ତୁ"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"କୀ କମ୍ବିନେସନ ପୂର୍ବରୁ ବ୍ୟବହାର କରାଯାଉଛି। ଅନ୍ୟ ଏକ କୀ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ।"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ଆପଣଙ୍କ କୀବୋର୍ଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"କୀବୋର୍ଡ ସର୍ଟକଟଗୁଡ଼ିକ ବିଷୟରେ ଜାଣନ୍ତୁ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ଆପଣଙ୍କ ଟଚପେଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string>
@@ -1457,11 +1452,11 @@
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ବଢ଼ିଆ କାମ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ଆପଣ \'ହୋମକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string>
- <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରନ୍ତୁ"</string>
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ବର୍ତ୍ତମାନର ଆପ୍ସକୁ ଭ୍ୟୁ କରନ୍ତୁ"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିକୁ ବ୍ୟବହାର କରି ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ବଢ଼ିଆ କାମ!"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ଆପଣ ବର୍ତ୍ତମାନର ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
- <string name="tutorial_action_key_title" msgid="8172535792469008169">"ସମସ୍ତ ଆପ ଭ୍ୟୁ କରନ୍ତୁ"</string>
+ <string name="tutorial_action_key_title" msgid="8172535792469008169">"ସବୁ ଆପ ଭ୍ୟୁ କରନ୍ତୁ"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ବହୁତ ବଢ଼ିଆ!"</string>
<string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ଆପଣ ସମସ୍ତ ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index 35afd612e6b6..8d230739caf7 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ବନ୍ଦ ଅଛି"</item>
<item msgid="3028994095749238254">"ଚାଲୁ ଅଛି"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"ଅନୁପଲବ୍ଧ"</item>
+ <item msgid="6419996398343291862">"ବନ୍ଦ ଅଛି"</item>
+ <item msgid="5908720590832378783">"ଚାଲୁ ଅଛି"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 8cc9f6e57939..5b9919ef97b6 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ਇਨਪੁੱਟ"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ਚਮਕ ਨੂੰ ਵਿਵਸਥਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਕਿਉਂਕਿ ਇਹ ਪਹਿਲਾਂ ਚੱਲ ਰਹੀ ਐਪ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕਰਨ ਕਰਕੇ \n ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ਸਵੈ-ਘੁਮਾਓ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ਸਕ੍ਰੀਨ ਨੂੰ ਆਪਣੇ ਆਪ ਘੁੰਮਾਓ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ਟਿਕਾਣਾ"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"\'ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ\' \'ਤੇ ਕਲਿੱਕ ਕਰੋ"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ਪ੍ਰੀਸੈੱਟ ਨੂੰ ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ਪ੍ਰੀਸੈੱਟ"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ਚੁਣਿਆ ਗਿਆ"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ਟੂਲ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ਲਾਈਵ ਸੁਰਖੀਆਂ"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"ਨੋਟ-ਕਥਨ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰੇ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰੇ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"ਹੁਣੇ ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"ਕੋਈ ਨਵੀਂ ਸੂਚਨਾ ਨਹੀਂ ਹੈ"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"ਨੋਟੀਫ਼ਿਕੇਸ਼ਨ ਕੂਲਡਾਊਨ ਹੁਣ ਚਾਲੂ ਹੈ"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ਇੱਕ ਵਾਰ \'ਚ ਕਈ ਸੂਚਨਾਵਾਂ ਮਿਲਣ \'ਤੇ, ਡੀਵਾਈਸ ਦੀ ਅਵਾਜ਼ ਅਤੇ ਅਲਰਟ ਵੱਧੋ-ਵੱਧ 2 ਮਿੰਟਾਂ ਲਈ ਆਪਣੇ-ਆਪ ਘੱਟ ਜਾਂਦੇ ਹਨ।"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ਬੰਦ ਕਰੋ"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ਪੁਰਾਣੀਆਂ ਸੂਚਨਾਵਾਂ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਸੱਜੇ ਜਾਂ ਹੇਠਾਂ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਖੱਬੇ ਜਾਂ ਉੱਪਰ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੌਰਾਨ: ਇੱਕ ਐਪ ਨਾਲ ਦੂਜੀ ਐਪ ਨੂੰ ਬਦਲੋ"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ਕਿਰਿਆਸ਼ੀਲ ਵਿੰਡੋ ਨੂੰ ਇੱਕ ਤੋਂ ਦੂਜੇ ਡਿਸਪਲੇ \'ਤੇ ਲਿਜਾਓ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ਇਨਪੁੱਟ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ਅਗਲੀ ਭਾਸ਼ਾ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"ਪਿਛਲੀ ਭਾਸ਼ਾ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> ਤੋਂ ਘੱਟ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਵਰਤੋ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ਗੱਲਬਾਤ ਵਿਜੇਟ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਕਿਸੇ ਗੱਲਬਾਤ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ਉੱਚ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਲਈ, ਫ਼ੋਨ ਨੂੰ ਫਲਿੱਪ ਕਰੋ"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਖੋਲ੍ਹਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਆਲੇ-ਦੁਆਲੇ ਫਲਿੱਪ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ਅਣਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,31 +1418,24 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ਪਹੁੰਚਯੋਗਤਾ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ਸ਼ਾਰਟਕੱਟ ਨਿਰਧਾਰਿਤ ਕਰਨ ਲਈ ਕੁੰਜੀ ਦਬਾਓ"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ਸ਼ਾਰਟਕੱਟ ਖੋਜੋ"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ਕੋਈ ਖੋਜ ਨਤੀਜਾ ਨਹੀਂ ਮਿਲਿਆ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ਪ੍ਰਤੀਕ ਨੂੰ ਸਮੇਟੋ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ਕਾਰਵਾਈ ਜਾਂ Meta ਕੁੰਜੀ ਪ੍ਰਤੀਕ"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ਜੋੜ-ਚਿੰਨ੍ਹ ਦਾ ਪ੍ਰਤੀਕ"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ਹੋ ਗਿਆ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ਪ੍ਰਤੀਕ ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ਜਾਂ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ਘਸੀਟਣ ਵਾਲਾ ਹੈਂਡਲ"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ਕੀ-ਬੋਰਡ ਸੈਟਿੰਗਾਂ"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ਸ਼ਾਰਟਕੱਟ ਸੈੱਟ ਕਰੋ"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ਰੱਦ ਕਰੋ"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ਕੁੰਜੀ ਦਬਾਓ"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ਕੁੰਜੀ ਸੁਮੇਲ ਪਹਿਲਾਂ ਹੀ ਵਰਤੋਂ ਵਿੱਚ ਹੈ। ਕੋਈ ਹੋਰ ਕੁੰਜੀ ਨੂੰ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ਆਪਣੇ ਕੀ-ਬੋਰਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
- <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਬਾਰੇ ਜਾਣੋ"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ਕੀ-ਬੋਰਡ ਦੇ ਸ਼ਾਰਟਕੱਟਾਂ ਬਾਰੇ ਜਾਣੋ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ਆਪਣੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ਟੱਚਪੈਡ ਇਸ਼ਾਰਿਆਂ ਬਾਰੇ ਜਾਣੋ"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ਆਪਣੇ ਕੀ-ਬੋਰਡ ਅਤੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
index ab2f8abdd739..0f53e5d933df 100644
--- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ਬੰਦ ਹੈ"</item>
<item msgid="3028994095749238254">"ਚਾਲੂ ਹੈ"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"ਉਪਲਬਧ ਨਹੀਂ"</item>
+ <item msgid="6419996398343291862">"ਬੰਦ"</item>
+ <item msgid="5908720590832378783">"ਚਾਲੂ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c183116e3528..e41d16f82785 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Wejście"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparaty słuchowe"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Włączam…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Nie można dostosować jasności, ponieważ jest ona\nkontrolowana przez aplikację na pierwszym planie"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoobracanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoobracanie ekranu"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokalizacja"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknij, aby sparować nowe urządzenie"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nie udało się zaktualizować gotowego ustawienia"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Gotowe ustawienie"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Wybrano"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Narzędzia"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Napisy na żywo"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notatka"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokować mikrofon urządzenia?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokować aparat urządzenia?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokować aparat i mikrofon urządzenia?"</string>
@@ -561,8 +561,8 @@
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ma wyłączoną tę opcję"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Wybieranie aplikacji do udostępniania"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Włączyć przesyłanie treści wyświetlanych na ekranie?"</string>
- <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Przesyłanie obrazu z jednej aplikacji"</string>
- <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Przesyłanie obrazu z całego ekranu"</string>
+ <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Przesyłanie obrazu z 1 aplikacji"</string>
+ <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Przesyłanie całego ekranu"</string>
<string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Kiedy przesyłasz treści z całego ekranu, widoczny jest cały obraz z wyświetlacza. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
<string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Kiedy przesyłasz obraz z aplikacji, widoczne jest wszystko to, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Prześlij ekran"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Przełącz się na aplikację po prawej lub poniżej na podzielonym ekranie"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Przełącz się na aplikację po lewej lub powyżej na podzielonym ekranie"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Podczas podzielonego ekranu: zastępowanie aplikacji"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Przenieś aktywne okno na inny ekran"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Wprowadzanie"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Przełącz na następny język"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Przełącz na poprzedni język"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Wpisz mniej znaków niż <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widżety rozmów"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Kliknij rozmowę, aby dodać ją do ekranu głównego"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Odwróć telefon, aby uzyskać wyższą rozdzielczość"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Składane urządzenie jest rozkładane"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Składane urządzenie jest obracane"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"po zamknięciu"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"po otwarciu"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ułatwienia dostępu"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Skróty klawiszowe"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Dostosuj skróty klawiszowe"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Naciśnij klawisz, aby przypisać skrót"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Brak wyników wyszukiwania"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona klawisza działania/meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona plusa"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Dostosuj"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Gotowe"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozwijania"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"lub"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Uchwyt do przeciągania"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ustawienia klawiatury"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ustaw skrót"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anuluj"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Naciśnij klawisz"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacja klawiszy jest już używana. Użyj innego klawisza."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nawiguj za pomocą klawiatury"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Dowiedz się więcej o skrótach klawiszowych"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nawiguj za pomocą touchpada"</string>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index d3191b0f6631..c9eb500c3e9c 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Wyłączono"</item>
<item msgid="3028994095749238254">"Włączone"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Niedostępny"</item>
+ <item msgid="6419996398343291862">"Wyłączony"</item>
+ <item msgid="5908720590832378783">"Włączony"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index f1dd9a4b27b1..72e593c06718 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Não é possível ajustar o brilho, porque ele está sendo\n controlado pelo app principal"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Não foi possível atualizar a predefinição"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predefinição"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selecionado"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Legenda instantânea"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Observação"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Desativado"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Não definido"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gerenciar nas configurações"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum modo ativo}=1{{mode} está ativo}one{# modo está ativo}many{# de modos estão ativos}other{# modos estão ativos}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum ativo}=1{{mode} ativo}one{# modo ativo}many{# de modos ativos}other{# modos ativos}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Você não será perturbado por sons e vibrações, exceto alarmes, lembretes, eventos e chamadas de pessoas especificadas. No entanto, você ouvirá tudo o que decidir reproduzir, como músicas, vídeos e jogos."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Você não será perturbado por sons e vibrações, exceto alarmes. No entanto, você ouvirá tudo o que decidir reproduzir, como músicas, vídeos e jogos."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string>
@@ -563,8 +563,8 @@
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Transmitir a tela?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Transmitir um app"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Transmitir tela inteira"</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Quando você está transmitindo a tela inteira, tudo nela fica visível. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Quando você transmite um app, todas as informações visíveis ou abertas nele ficam visíveis. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Durante a transmissão, tudo que está na sua tela fica visível. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Quando você transmite um app, todas as informações visíveis ou abertas nele vão aparecer. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Transmitir tela"</string>
<string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Escolha um app para transmitir"</string>
<string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Começar a compartilhar?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"O recurso de atenuar notificações está ativado"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e alertas são reduzidos por até 2 min quando você recebe muitas notificações juntas."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desativar"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie p/ acessar notificações antigas"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para o app à direita ou abaixo ao usar a tela dividida"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mudar para o app à esquerda ou acima ao usar a tela dividida"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mover janela ativa entre telas"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Mudar para o próximo idioma"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Mudar para o idioma anterior"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Toque em uma conversa para adicioná-la à tela inicial"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para uma resolução maior, vire o smartphone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar atalhos de teclado"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pressione a tecla para atribuir o atalho"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ícone da tecla de ação"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ícone de adição"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Concluir"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Alça de arrastar"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configurações do teclado"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Definir atalho"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pressione a tecla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Essa combinação de teclas já está em uso. Tente outra tecla."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string>
@@ -1458,7 +1453,7 @@
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Muito bem!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Você concluiu o gesto para acessar a tela inicial"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver os apps recentes"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima e pressione com 3 dedos no touchpad"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima com 3 dedos e mantenha"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index e315bad6bf80..9ddc41ca4b24 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desativar"</item>
<item msgid="3028994095749238254">"Ativar"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Indisponível"</item>
+ <item msgid="6419996398343291862">"Desativado"</item>
+ <item msgid="5908720590832378783">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 03c32a834721..460d55304e1e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"A ativar..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Não é possível ajustar o brilho porque está a ser\n controlado pela app principal"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotação auto."</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rodar o ecrã automaticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para sincronizar um novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Não foi possível atualizar a predefinição"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predefinição"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selecionado"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Legendas instantâneas"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmara do dispositivo?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Quer desbloquear a câmara e o microfone?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Desativado"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Não definido"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gerir nas definições"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum modo ativo}=1{{mode} está ativo}many{# modos estão ativos}other{# modos estão ativos}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum modo ativo}=1{{mode} ativo}many{# modos ativos}other{# modos ativos}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Não é incomodado por sons e vibrações, exceto de alarmes, lembretes, eventos e autores de chamadas que especificar. Continua a ouvir tudo o que optar por reproduzir, incluindo música, vídeos e jogos."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Não é incomodado por sons e vibrações, exceto de alarmes. Continua a ouvir tudo o que optar por reproduzir, incluindo música, vídeos e jogos."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para a app à direita ou abaixo enquanto usa o ecrã dividido"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mude para a app à esquerda ou acima enquanto usa o ecrã dividido"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Durante o ecrã dividido: substituir uma app por outra"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mova a janela ativa entre ecrãs"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Mudar para idioma seguinte"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Mudar para idioma anterior"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use menos de <xliff:g id="LENGTH">%1$d</xliff:g> carateres"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Toque numa conversa para a adicionar ao ecrã principal"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para uma resolução superior, inverta o telemóvel"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável a ser desdobrado"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável a ser virado ao contrário"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos de teclado"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalize os atalhos de teclado"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Prima a tecla para atribuir o atalho"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado da pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ícone da tecla Meta ou de ação"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ícone de mais"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Concluir"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Indicador para arrastar"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Definições do teclado"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Configurar atalho"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prima a tecla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"A combinação de teclas já está a ser usada. Experimente outra tecla."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue com o teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos de teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue com o touchpad"</string>
@@ -1457,7 +1453,7 @@
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"É assim mesmo!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Concluiu o gesto para aceder ao ecrã principal"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver apps recentes"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize rapidamente para cima e mantenha premido com 3 dedos no touchpad"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize rapidamente para cima sem soltar com 3 dedos no touchpad"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Concluiu o gesto para ver as apps recentes."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas as apps"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index deb6783e1b23..5baa61c136dc 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desativados"</item>
<item msgid="3028994095749238254">"Ativados"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Indisponível"</item>
+ <item msgid="6419996398343291862">"Desativado"</item>
+ <item msgid="5908720590832378783">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index f1dd9a4b27b1..72e593c06718 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Não é possível ajustar o brilho, porque ele está sendo\n controlado pelo app principal"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Não foi possível atualizar a predefinição"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predefinição"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selecionado"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Legenda instantânea"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Observação"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Desativado"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Não definido"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gerenciar nas configurações"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum modo ativo}=1{{mode} está ativo}one{# modo está ativo}many{# de modos estão ativos}other{# modos estão ativos}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum ativo}=1{{mode} ativo}one{# modo ativo}many{# de modos ativos}other{# modos ativos}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Você não será perturbado por sons e vibrações, exceto alarmes, lembretes, eventos e chamadas de pessoas especificadas. No entanto, você ouvirá tudo o que decidir reproduzir, como músicas, vídeos e jogos."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Você não será perturbado por sons e vibrações, exceto alarmes. No entanto, você ouvirá tudo o que decidir reproduzir, como músicas, vídeos e jogos."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string>
@@ -563,8 +563,8 @@
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Transmitir a tela?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Transmitir um app"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Transmitir tela inteira"</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Quando você está transmitindo a tela inteira, tudo nela fica visível. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Quando você transmite um app, todas as informações visíveis ou abertas nele ficam visíveis. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Durante a transmissão, tudo que está na sua tela fica visível. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Quando você transmite um app, todas as informações visíveis ou abertas nele vão aparecer. Por isso, tenha cuidado com senhas, detalhes da forma de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Transmitir tela"</string>
<string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Escolha um app para transmitir"</string>
<string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Começar a compartilhar?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"O recurso de atenuar notificações está ativado"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e alertas são reduzidos por até 2 min quando você recebe muitas notificações juntas."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desativar"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie p/ acessar notificações antigas"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para o app à direita ou abaixo ao usar a tela dividida"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mudar para o app à esquerda ou acima ao usar a tela dividida"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mover janela ativa entre telas"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Mudar para o próximo idioma"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Mudar para o idioma anterior"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Toque em uma conversa para adicioná-la à tela inicial"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para uma resolução maior, vire o smartphone"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar atalhos de teclado"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pressione a tecla para atribuir o atalho"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ícone da tecla de ação"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ícone de adição"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Concluir"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Alça de arrastar"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configurações do teclado"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Definir atalho"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pressione a tecla"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Essa combinação de teclas já está em uso. Tente outra tecla."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string>
@@ -1458,7 +1453,7 @@
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Muito bem!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Você concluiu o gesto para acessar a tela inicial"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver os apps recentes"</string>
- <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima e pressione com 3 dedos no touchpad"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima com 3 dedos e mantenha"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string>
<string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index e315bad6bf80..9ddc41ca4b24 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Desativar"</item>
<item msgid="3028994095749238254">"Ativar"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Indisponível"</item>
+ <item msgid="6419996398343291862">"Desativado"</item>
+ <item msgid="5908720590832378783">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5b3190fef48c..42fd14b1b9c2 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Intrare"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparate auditive"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Se activează..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Nu se poate ajusta luminozitatea deoarece este\n controlată de aplicația de top"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotire automată"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotirea automată a ecranului"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locație"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Dă clic pentru a asocia un nou dispozitiv"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nu s-a putut actualiza presetarea"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Presetare"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selectat"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Instrumente"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitrări live"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notă"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblochezi microfonul dispozitivului?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblochezi camera dispozitivului?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblochezi camera și microfonul dispozitivului?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Începe acum"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nicio notificare"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nicio notificare nouă"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Reducerea sunetului notificărilor este activată"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volumul și alertele dispozitivului sunt reduse automat timp de până la 2 min. când primești prea multe notificări odată"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Dezactivează"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Deblochează ca să vezi notificări vechi"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Treci la aplicația din dreapta sau de mai jos cu ecranul împărțit"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Treci la aplicația din stânga sau de mai sus cu ecranul împărțit"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"În modul ecran împărțit: înlocuiește o aplicație cu alta"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Mută fereastra activă de pe un ecran pe altul"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Introducere"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Comută la următoarea limbă"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Comută la limba anterioară"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Folosește maximum <xliff:g id="LENGTH">%1$d</xliff:g> caractere"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Deschide conversația"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Widgeturi pentru conversație"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Atinge o conversație ca să o adaugi pe ecranul de pornire"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Pentru o rezoluție mai mare, deschide telefonul"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispozitiv pliabil care este desfăcut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispozitiv pliabil care este întors"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"închis"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"deschis"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilitate"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Comenzi rapide de la tastatură"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizează comenzile rapide de la tastatură"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Apasă tasta pentru a atribui comanda rapidă"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Comenzi directe de căutare"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Niciun rezultat al căutării"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Pictograma pentru acțiune sau tastă Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Pictograma plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizează"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Gata"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Pictograma de extindere"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"sau"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ghidaj de tragere"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Setările tastaturii"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Setează o comandă rapidă"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anulează"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Apasă tasta"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinația de taste este deja folosită. Încearcă altă tastă."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navighează folosind tastatura"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Învață comenzile rapide de la tastatură"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navighează folosind touchpadul"</string>
diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
index fa950c30850a..528b112c72a6 100644
--- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Dezactivat"</item>
<item msgid="3028994095749238254">"Activat"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Indisponibil"</item>
+ <item msgid="6419996398343291862">"Dezactivat"</item>
+ <item msgid="5908720590832378783">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 665bd26a386e..866cb5e8f602 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -113,8 +113,8 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Записывать одно приложение"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Записывать весь экран"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Записывать весь экран: %s"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Во время записи всего экрана все данные и действия, которые на нем показываются, попадают на видео. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Во время записи приложения все данные и действия, которые показываются в его окне, попадают на видео. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"На видео попадет все, что будет происходить на экране. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"На видео попадет все, что происходит в выбранном приложении. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Запись экрана"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Выбор приложения для записи экрана"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Записывать аудио"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Устройство ввода"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слуховые аппараты"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включение…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Невозможно изменить яркость,\nтак как она регулируется общими настройками."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоповорот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоповорот экрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Геолокация"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Нажмите, чтобы подключить новое устройство"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Не удалось обновить набор настроек."</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Набор настроек"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Выбрано"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Инструменты"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Автоматические субтитры"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Заметка"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблокировать микрофон устройства?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблокировать камеру устройства?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблокировать камеру и микрофон устройства?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Отключено"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"Не задано"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Открыть настройки"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Включено 0 режимов}=1{Включен режим \"{mode}\"}one{Включен # режим}few{Включено # режима}many{Включено # режимов}other{Включено # режима}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{0 режимов}=1{Режим \"{mode}\"}one{# режим}few{# режима}many{# режимов}other{# режима}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Вас не будут отвлекать звуки и вибрация, за исключением сигналов будильника, напоминаний, уведомлений о мероприятиях и звонков от помеченных контактов. Вы по-прежнему будете слышать включенную вами музыку, видео, игры и т. д."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Вас не будут отвлекать звуки и вибрация, за исключением сигналов будильника. Вы по-прежнему будете слышать включенную вами музыку, видео, игры и т. д."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Настроить"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Начать"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Нет уведомлений."</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Новых уведомлений нет"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Снижение громкости уведомлений включено"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Если придет слишком много уведомлений, на две минуты громкость и количество оповещений уменьшатся."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Отключить"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Разблокируйте, чтобы увидеть уведомления"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Перейти к приложению справа или внизу на разделенном экране"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Перейти к приложению слева или вверху на разделенном экране"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"В режиме разделения экрана заменить одно приложение другим"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Переместить активное окно между экранами"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Ввод"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Выбрать следующий язык"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Выбрать предыдущий язык"</string>
@@ -1006,7 +1004,7 @@
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Модуль Wi-Fi отключен"</string>
- <string name="bt_is_off" msgid="7436344904889461591">"Модуль Bluetooth отключен."</string>
+ <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth отключен"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"Режим \"Не беспокоить\" отключен"</string>
<string name="dnd_is_on" msgid="7009368176361546279">"Режим \"Не беспокоить\" включен"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Режим \"Не беспокоить\" был включен специальным правилом (<xliff:g id="ID_1">%s</xliff:g>)."</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Максимальное количество символов – <xliff:g id="LENGTH">%1$d</xliff:g>."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Открытый чат"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Виджеты разговоров"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Нажмите на разговор, чтобы добавить его на главный экран"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Переверните телефон и используйте основную камеру, чтобы делать снимки с более высоким разрешением."</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складное устройство в разложенном виде"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перевернутое складное устройство"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"устройство сложено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"устройство разложено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Специальные возможности"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Быстрые клавиши"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Как настроить быстрые клавиши"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Нажмите клавишу, чтобы назначить быструю команду."</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Найти быстрые клавиши"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ничего не найдено"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Значок клавиши Meta для выполнения действия"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Значок плюса"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Настроить"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Готово"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Развернуть\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер перемещения"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Настройки клавиатуры"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Задать сочетание клавиш"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Отмена"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Нажмите клавишу"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Это сочетание клавиш уже используется. Попробуйте другое."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигация с помощью клавиатуры"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Узнайте о сочетаниях клавиш."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигация с помощью сенсорной панели"</string>
diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
index cd12baeadbb2..43d3e2ac31ed 100644
--- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Отключены"</item>
<item msgid="3028994095749238254">"Включены"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Недоступно"</item>
+ <item msgid="6419996398343291862">"Отключено"</item>
+ <item msgid="5908720590832378783">"Включено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 0df5d4494e67..0ccd61c41905 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ආදානය"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ශ්‍රවණාධාරක"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ක්‍රියාත්මක කරමින්…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ඉහළ යෙදුම මඟින් එය පාලනය වන නිසා\nදීප්තිය ගැළපුම් කළ නොහැක"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ස්වයංක්‍රීය කරකැවීම"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ස්වයංක්‍රීයව-භ්‍රමණය වන තිරය"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"නව උපාංගය යුගල කිරීමට ක්ලික් කරන්න"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"පෙර සැකසීම යාවත්කාලීන කළ නොහැකි විය"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"පෙරසැකසුම"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"තෝරන ලදි"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"මෙවලම්"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"සජීවී සිරස්තල"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"සටහන"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්‍රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"උපාංග කැමරාව අවහිර කිරීම ඉවත් කරන්නද?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"උපාංග කැමරාව සහ මයික්‍රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"දැන් අරඹන්න"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"දැනුම්දීම් නැත"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"නව දැනුම්දීම් නැත"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"දැනුම්දීම් සිසිල් කිරීම දැන් ක්‍රියාත්මකයි"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ඔබට එකවර දැනුම්දීම් වැඩි ප්‍රමාණයක් ලැබෙන විට ඔබේ උපාංග පරිමාව සහ ඇඟවීම් මිනිත්තු 2ක් දක්වා ස්වයංක්‍රීයව අඩු වේ."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ක්‍රියාවිරහිත කරන්න"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"පැරණි දැනුම්දීම් බැලීමට අගුළු හරින්න"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"බෙදුම් තිරය භාවිත කරන අතරතුර දකුණේ හෝ පහළින් ඇති යෙදුමට මාරු වන්න"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"බෙදුම් තිරය භාවිත කරන අතරතුර වමේ හෝ ඉහළ ඇති යෙදුමට මාරු වන්න"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"බෙදුම් තිරය අතරතුර: යෙදුමක් එකකින් තවත් එකක් ප්‍රතිස්ථාපනය කරන්න"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"සක්‍රිය කවුළුව සංදර්ශක අතර ගෙන යන්න"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ආදානය"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"මීළඟ භාෂාවට මාරු වන්න"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"පෙර භාෂාවට මාරු වන්න"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"අනුලකුණු <xliff:g id="LENGTH">%1$d</xliff:g>කට වඩා අඩුවෙන් භාවිතා කරන්න"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"සංවාදය විවෘත කරන්න"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"සංවාද විජට්"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ඔබගේ මුල් තිරයට එය එක් කිරීමට සංවාදයක් තට්ටු කරන්න"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ඉහළ විභේදනය සඳහා, දුරකථනය හරවන්න"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"දිග හැරෙමින් පවතින නැමිය හැකි උපාංගය"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"වටා පෙරළෙමින් තිබෙන නැමිය හැකි උපාංගය"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"නැවූ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"නොනැවූ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ප්‍රවේශ්‍යතාව"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"යතුරු පුවරු කෙටි මං"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"යතුරුපුවරු කෙටිමං අභිරුචිකරණය කරන්න"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"කෙටි මග පැවරීමට යතුර ඔබන්න"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"කෙටි මං සොයන්න"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"සෙවීම් ප්‍රතිඵල නැත"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"හැකුළුම් නිරූපකය"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ක්‍රියාව හෝ Meta යතුරු නිරූපකය"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ධන නිරූපකය"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"අභිරුචිකරණය කරන්න"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"නිමයි"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"දිගහැරීම් නිරූපකය"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"හෝ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ඇදීම් හැඬලය"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"යතුරු පුවරු සැකසීම්"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"කෙටිමඟ සකසන්න"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"අවලංගු කරන්න"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"යතුර ඔබන්න"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"යතුරු සංයෝජනය දැනටමත් භාවිත වේ. වෙනත් යතුරක් උත්සාහ කරන්න."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ඔබේ යතුරු පුවරුව භාවිතයෙන් සංචාලනය කරන්න"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"යතුරුපුවරු කෙටිමං ඉගෙන ගන්න"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ඔබේ ස්පර්ශ පෑඩ් භාවිතයෙන් සංචාලනය කරන්න"</string>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index 595575d7eebc..91280e1e00bd 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ක්‍රියාවිරහිතයි"</item>
<item msgid="3028994095749238254">"ක්‍රියාත්මකයි"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"ලබා ගත නොහැක"</item>
+ <item msgid="6419996398343291862">"ක්‍රියාවිරහිතයි"</item>
+ <item msgid="5908720590832378783">"ක්‍රියාත්මකයි"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 7331ba015726..cc59beafe025 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Načúvadlá"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapína sa…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Jas sa nedá upraviť, pretože ho \n ovláda horná aplikácia"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčanie obrazovky"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zariadenie"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Predvoľbu sa nepodarilo aktualizovať"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predvoľba"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Vybrané"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Nástroje"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Živý prepis"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Poznámka"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Chcete odblokovať mikrofón zariadenia?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Chcete odblokovať kameru zariadenia?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Chcete odblokovať fotoaparát a mikrofón zariadenia?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Spustiť"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Žiadne upozornenia"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Žiadne nové upozornenia"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Stlmenie upozornení je zapnuté"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Keď dostanete priveľa upozornení naraz, až na dve minúty sa zníži hlasitosť zariadenia a upozornenia sa obmedzia."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Vypnúť"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Odomknutím zobrazíte staršie upozornenia"</string>
@@ -700,7 +699,7 @@
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Priestorový zvuk"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Vypnuté"</string>
<string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Pevné"</string>
- <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Sled. polohy hlavy"</string>
+ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Sledovanie hlavy"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Režim zvonenia zmeníte klepnutím"</string>
<string name="volume_ringer_mode" msgid="6867838048430807128">"režim zvonenia"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prechod na aplikáciu vpravo alebo dole pri rozdelenej obrazovke"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prechod na aplikáciu vľavo alebo hore pri rozdelenej obrazovke"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Počas rozdelenej obrazovky: nahradenie aplikácie inou"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Presun aktívneho okna medzi obrazovkami"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vstup"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Prepnutie na ďalší jazyk"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Prepnutie na predchádzajúci jazyk"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Použite menej znakov než <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Miniaplikácie konverzácií"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Klepnite na konverzáciu a pridajte ju tak na plochu"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Ak chcete vyššie rozlíšenie, prevráťte telefón"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozloženie skladacieho zariadenia"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Prevrátenie skladacieho zariadenia"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zložené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,55 +1418,48 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Dostupnosť"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové skratky"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prispôsobenie klávesových skratiek"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Stlačením klávesa priraďte skratku"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prehľadávať skratky"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Žiadne výsledky vyhľadávania"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona akčného klávesa alebo metaklávesa"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Prispôsobiť"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Hotovo"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalenia"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"alebo"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Presúvadlo"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavenia klávesnice"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
- <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Prechádzajte pomocou klávesnice"</string>
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastaviť skratku"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Zrušiť"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Stlačte kláves"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinácia klávesov sa už používa. Skúste iný kláves."</string>
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Pohybujte sa v systéme pomocou klávesnice"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte sa klávesové skratky"</string>
- <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Prechádzajte pomocou touchpadu"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Pohybujte sa v systéme pomocou touchpadu"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Naučte sa gestá touchpadu"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Prechádzajte pomocou klávesnice a touchpadu"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte sa gestá touchpadu, klávesové skratky a ďalšie funkcie"</string>
- <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Prejsť späť"</string>
+ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Prechod späť"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Prejsť na plochu"</string>
<string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazenie nedávnych aplikácií"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejsť späť"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Potiahnite troma prstami na touchpade doľava alebo doprava"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Výborne!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Dokončili ste gesto na prechod späť."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Použili ste gesto na prechod späť."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Prechod na plochu"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Potiahnite troma prstami na touchpade nahor"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Skvelé!"</string>
- <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Dokončili ste gesto na prechod na plochu"</string>
+ <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Použili ste gesto na prechod na plochu."</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Zobrazenie nedávnych aplikácií"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Potiahnite troma prstami na touchpade nahor a pridržte"</string>
<string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Skvelé!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dokončili ste gesto na zobrazenie nedávnych aplikácií."</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Použili ste gesto na zobrazenie nedávnych aplikácií."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"Zobrazenie všetkých aplikácií"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stlačte na klávesnici akčný kláves"</string>
- <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Výborne!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Dokončili ste gesto na zobrazenie všetkých aplikácií"</string>
+ <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Dobre!"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Použili ste gesto na zobrazenie všetkých aplikácií."</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládanie domácnosti"</string>
diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
index 607c2215642b..0b0b89483188 100644
--- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Vypnuté"</item>
<item msgid="3028994095749238254">"Zapnuté"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nedostupné"</item>
+ <item msgid="6419996398343291862">"Vypnuté"</item>
+ <item msgid="5908720590832378783">"Zapnuté"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index d0b0a9ddd0a3..38f1e5a1fb6d 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vhodna naprava"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Vklapljanje …"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Svetlosti ni mogoče prilagoditi, ker jo\n nadzoruje aplikacija na vrhu"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Samodejno sukanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Samodejno sukanje zaslona"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite za seznanitev nove naprave"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Prednastavljenih vrednosti ni bilo mogoče posodobiti"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Prednastavljeno"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Izbrano"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Orodja"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Samodejni podnapisi"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Opomba"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite odblokirati mikrofon v napravi?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite odblokirati fotoaparat v napravi?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite odblokirati fotoaparat in mikrofon v napravi?"</string>
@@ -561,8 +561,8 @@
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogočila to možnost"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Izbira aplikacije za deljenje"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Želite predvajati vsebino zaslona?"</string>
- <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Predvajanje vsebine ene aplikacije"</string>
- <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Predvajanje vsebine celotnega zaslona"</string>
+ <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Predvajanje ene aplikacije"</string>
+ <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Predvajanje celotnega zaslona"</string>
<string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Pri predvajanju vsebine celotnega zaslona je vidno vse na zaslonu. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
<string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Pri predvajanju vsebine aplikacije je vidno vse, kar je prikazano ali predvajano v tej aplikaciji. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Predvajanje zaslona"</string>
@@ -699,7 +699,7 @@
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Prostorski zvok"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Izklopljeno"</string>
<string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Fiksno"</string>
- <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Spremljanje premikov glave"</string>
+ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Spremljanje glave"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Dotaknite se, če želite spremeniti način zvonjenja."</string>
<string name="volume_ringer_mode" msgid="6867838048430807128">"način zvonjenja"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izklop zvoka"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Preklop na aplikacijo desno ali spodaj med uporabo razdeljenega zaslona"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Preklop na aplikacijo levo ali zgoraj med uporabo razdeljenega zaslona"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Pri razdeljenem zaslonu: medsebojna zamenjava aplikacij"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Premikanje aktivnega okna med zasloni"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vnos"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Preklop na naslednji jezik"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Preklop na prejšnji jezik"</string>
@@ -1202,8 +1201,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvočniki in zasloni"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predlagane naprave"</string>
- <string name="media_input_group_title" msgid="2057057473860783021">"Vhodno"</string>
- <string name="media_output_group_title" msgid="6789001895863332576">"Izhodno"</string>
+ <string name="media_input_group_title" msgid="2057057473860783021">"Vhod"</string>
+ <string name="media_output_group_title" msgid="6789001895863332576">"Izhod"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Ustavi deljeno sejo za premik predstavnosti v drugo napravo."</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Ustavi"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako deluje oddajanje"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Uporabite manj kot <xliff:g id="LENGTH">%1$d</xliff:g> znakov."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Pripomočki za pogovore"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Dotaknite se pogovora, da ga dodate na začetni zaslon."</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za višjo ločljivost obrnite telefon"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Razpiranje zložljive naprave"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Obračanje zložljive naprave"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zaprto"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"razprto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Dostopnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Bližnjične tipke"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagajanje bližnjičnih tipk"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite tipko za dodelitev bližnjice"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Iskanje po bližnjicah"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ni rezultatov iskanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona tipke za dejanje ali metapodatke"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona znaka plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Prilagodi"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Končano"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ali"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ročica za vlečenje"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavitve tipkovnice"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastavite bližnjico"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Prekliči"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipko"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacija tipk je že v uporabi. Poskusite z drugo tipko."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krmarjenje s tipkovnico"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Učenje bližnjičnih tipk"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krmarjenje s sledilno ploščico"</string>
diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
index fddaea615bab..f9ccbb1fde86 100644
--- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Izklopljeno"</item>
<item msgid="3028994095749238254">"Vklopljeno"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Ni na voljo"</item>
+ <item msgid="6419996398343291862">"Izklopljeno"</item>
+ <item msgid="5908720590832378783">"Vklopljeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 428caf08c81d..9ed8bf29d630 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Hyrja"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparatet e dëgjimit"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Po aktivizohet…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Ndriçimi nuk mund të rregullohet pasi\n po kontrollohet nga aplikacioni i sipërm"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rrotullim automatik"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rrotullimi automatik i ekranit"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vendndodhja"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliko për të çiftuar një pajisje të re"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Paravendosja nuk mund të përditësohej"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Paravendosja"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Zgjedhur"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Veglat"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Titrat në çast"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Shënim"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Të zhbllokohet mikrofoni i pajisjes?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Të zhbllokohet kamera e pajisjes?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Të zhbllokohen kamera dhe mikrofoni i pajisjes?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Fillo tani"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Asnjë njoftim"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nuk ka njoftime të reja"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Reduktimi i njoftimeve është aktiv tani"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volumi i pajisjes dhe sinjalizimet zvogëlohen automatikisht për deri në 2 minuta kur merr shumë njoftime në të njëjtën kohë."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Çaktivizo"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Shkyç për të parë njoftimet e vjetra"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Kalo tek aplikacioni djathtas ose poshtë kur përdor ekranin e ndarë"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Kalo tek aplikacioni në të majtë ose sipër kur përdor ekranin e ndarë"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Gjatë ekranit të ndarë: zëvendëso një aplikacion me një tjetër"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Zhvendose dritaren aktive mes ekraneve"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Hyrja"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Kalo te gjuha tjetër"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Kalo te gjuha e mëparshme"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Përdor më pak se <xliff:g id="LENGTH">%1$d</xliff:g> karaktere"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Hap bisedën"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Miniaplikacionet e bisedave"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Trokit te një bisedë dhe shtoje në ekranin bazë"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Për rezolucion më të lartë, përmbys telefonin"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Pajisja e palosshme duke u hapur"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Pajisja e palosshme duke u rrotulluar"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"palosur"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"shpalosur"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qasshmëria"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Shkurtoret e tastierës"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizo shkurtoret e tastierës"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Shtyp tastin për të caktuar shkurtoren"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kërko për shkurtoret"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Asnjë rezultat kërkimi"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona e tastit të veprimit ose tastit Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona e plusit"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizo"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"U krye"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona e zgjerimit"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ose"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Doreza e zvarritjes"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Cilësimet e tastierës"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Cakto shkurtoren"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anulo"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Shtyp tastin"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinimi i tasteve është tashmë në përdorim. Provo një tast tjetër."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigo duke përdorur tastierën tënde"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Mëso shkurtoret e tastierës"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigo duke përdorur bllokun me prekje"</string>
@@ -1450,7 +1445,7 @@
<string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Shiko aplikacionet e fundit"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"U krye"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kthehu prapa"</string>
- <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Rrëshqit shpejt majtas ose djathtas duke përdorur tre gishta në bllokun me prekje."</string>
+ <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Rrëshqit shpejt majtas ose djathtas duke përdorur tre gishta në bllokun me prekje"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bukur!"</string>
<string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"E ke përfunduar gjestin e kthimit prapa."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Shko tek ekrani bazë"</string>
diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
index b30c8e7847de..1ab4f01c56e2 100644
--- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Joaktive"</item>
<item msgid="3028994095749238254">"Aktive"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Nuk ofrohen"</item>
+ <item msgid="6419996398343291862">"Joaktive"</item>
+ <item msgid="5908720590832378783">"Aktive"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 63b3e9a4f38d..102c452fc54a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Унос"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слушни апарати"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Укључује се..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Не можете да прилагодите осветљеност јер је\n контролише апликација у врху"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аутоматска ротација"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аутоматско ротирање екрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликните да бисте упарили нов уређај"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ажурирање задатих подешавања није успело"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Унапред одређена подешавања"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Изабрано"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Алатке"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Титл уживо"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Белешка"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Желите да одблокирате микрофон уређаја?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Желите да одблокирате камеру уређаја?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Желите да одблокирате камеру и микрофон уређаја?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пређи у апликацију здесна или испод док је подељен екран"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пређите у апликацију слева или изнад док користите подељени екран"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"У режиму подељеног екрана: замена једне апликације другом"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Премести активан прозор на следећи екран"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Унос"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Пређи на следећи језик"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Пређи на претходни језик"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Користите мањи број знакова од <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Отворите конверзацију"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Виџети за конверзацију"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Додирните конверзацију да бисте је додали на почетни екран"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"За већу резолуцију обрните телефон"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Уређај на преклоп се отвара"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Уређај на преклоп се обрће"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Приступачност"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Тастерске пречице"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Прилагодите тастерске пречице"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Притисните тастер да бисте доделили пречицу"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Претражите пречице"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Нема резултата претраге"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Икона тастера за радњу или мета тастера"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Икона знака плус"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Прилагоди"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Готово"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширивање"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер за превлачење"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Подешавања тастатуре"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Подеси пречицу"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Откажи"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Притисните тастер"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Комбинација тастера се већ користи. Пробајте са другим тастером."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Крећите се помоћу тастатуре"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Сазнајте више о тастерским пречицама"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Крећите се помоћу тачпеда"</string>
@@ -1450,7 +1446,7 @@
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Превуците улево или удесно са три прста на тачпеду"</string>
- <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Свака част!"</string>
+ <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Супер!"</string>
<string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Довршили сте покрет за повратак."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Иди на почетни екран"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Превуците нагоре са три прста на тачпеду"</string>
diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
index 2a2e07459243..ec5f10f63e1a 100644
--- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Искључено"</item>
<item msgid="3028994095749238254">"Укључено"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Недоступно"</item>
+ <item msgid="6419996398343291862">"Искључено"</item>
+ <item msgid="5908720590832378783">"Укључено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index bffd40b6c5fe..c2ac21691aa1 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingång"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörapparater"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverar …"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Det går inte att justera ljusstyrkan eftersom den\n styrs av den översta appen"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotera automatiskt"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotera skärmen automatiskt"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Plats"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicka för att parkoppla en ny enhet"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Det gick inte att uppdatera förinställningen"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Förinställning"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Markerad"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Verktyg"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Anteckning"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vill du återaktivera enhetens mikrofon?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vill du återaktivera enhetens kamera?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vill du återaktivera enhetens kamera och mikrofon?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Starta nu"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Inga aviseringar"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Det finns inga nya aviseringar"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Nu är dämpning av aviseringar på"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Enheten sänker volymen och minimerar aviseringar i upp till två minuter när du får för många aviseringar samtidigt."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Inaktivera"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Lås upp för att se äldre aviseringar"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Byt till appen till höger eller nedanför när du använder delad skärm"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Byt till appen till vänster eller ovanför när du använder delad skärm"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Med delad skärm: ersätt en app med en annan"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Flytta det aktiva fönstret mellan skärmar"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Inmatning"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Byt till nästa språk"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Byt till föregående språk"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Använd färre än <xliff:g id="LENGTH">%1$d</xliff:g> tecken"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Konversationswidgetar"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tryck på en konversation för att lägga till den på startskärmen"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Vänd telefonen för högre upplösning"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En vikbar enhet viks upp"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En vikbar enhet vänds"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"hopvikt"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"uppvikt"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tillgänglighet"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Kortkommandon"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Anpassa kortkommandon"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tryck på tangenten för att ange kortkommando"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sökgenvägar"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Inga sökresultat"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikon för åtgärdstangent"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plusikon"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Anpassa"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Klar"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handtag"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tangentbordsinställningar"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ange kortkommando"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Avbryt"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tryck på tangenten"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tangentkombinationen används redan. Testa en annan tangent."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigera med tangentbordet"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lär dig kortkommandon"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigera med styrplattan"</string>
diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
index b72f404c710f..e9da8053759d 100644
--- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Av"</item>
<item msgid="3028994095749238254">"På"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Inte tillgängligt"</item>
+ <item msgid="6419996398343291862">"Av"</item>
+ <item msgid="5908720590832378783">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 2140a8ae06bb..3418907ea44c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vifaa vya kuingiza sauti"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Visaidizi vya kusikia"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inawasha..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Imeshindwa kurekebisha mwangaza kwa sababu\n inadhibitiwa na programu inayotumika"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Zungusha kiotomatiki"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Skrini ijizungushe kiotomatiki"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Mahali"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Bofya ili uunganishe kifaa kipya"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Imeshindwa kusasisha mipangilio iliyowekwa mapema"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Mipangilio iliyowekwa mapema"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Umechagua"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Zana"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Manukuu Papo Hapo"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Dokezo"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Ungependa kuwacha kuzuia maikrofoni ya kifaa?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Ungependa kuacha kuzuia kamera ya kifaa?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Ungependa kuwacha kuzuia kamera na maikrofoni ya kifaa?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Anza sasa"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Hakuna arifa"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Hakuna arifa mpya"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Mipangilio ya kutuliza arifa imewashwa"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Arifa na sauti hupunguzwa kiotomatiki kwenye kifaa chako kwa hadi dakika 2 unapopokea arifa nyingi kwa wakati mmoja."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Zima"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Fungua ili uone arifa za zamani"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Badilisha ili uende kwenye programu iliyo kulia au chini unapotumia hali ya kugawa skrini"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Badilisha uende kwenye programu iliyo kushoto au juu unapotumia hali ya kugawa skrini"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ukigawanya skrini: badilisha kutoka programu moja hadi nyingine"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Hamisha dirisha linalotumika kati ya skrini moja na nyingine"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vifaa vya kuingiza data"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Badilisha utumie lugha inayofuata"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Badilisha utumie lugha iliyotangulia"</string>
@@ -1203,7 +1201,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Spika na Skrini"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Vifaa Vilivyopendekezwa"</string>
- <string name="media_input_group_title" msgid="2057057473860783021">"Vifaa vya kuingiza data"</string>
+ <string name="media_input_group_title" msgid="2057057473860783021">"Vifaa vya kuingiza maudhui"</string>
<string name="media_output_group_title" msgid="6789001895863332576">"Vifaa vya kutoa maudhui"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Simamisha kipindi unachoshiriki ili uhamishie maudhui kwenye kifaa kingine"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Simamisha"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Hupaswi kuzidi herufi <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Fungua mazungumzo"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Wijeti za mazungumzo"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Gusa mazungumzo ili uyaweke kwenye Skrini yako ya kwanza"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Kwa ubora wa juu, geuza simu"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Kifaa kinachokunjwa kikikunjuliwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Kifaa kinachokunjwa kikigeuzwa"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kimekunjwa"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kimefunguliwa"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,31 +1418,24 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ufikivu"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Mikato ya kibodi"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Weka mapendeleo ya mikato ya kibodi"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Bonyeza kitufe ukabidhi njia ya mkato"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Njia mkato za kutafutia"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Hamna matokeo ya utafutaji"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Aikoni ya kitufe cha Vitendo au cha Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Aikoni ya alama ya kujumlisha"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Weka mapendeleo"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Nimemaliza"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Panua aikoni"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"au"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Aikoni ya buruta"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Mipangilio ya Kibodi"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Weka njia ya mkato"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Acha"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Bonyeza kitufe"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tayari unatumia mchanganyiko huu wa vitufe. Jatibu kitufe kingine."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Kusogeza kwa kutumia kibodi yako"</string>
- <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Jifunze kuhusu mikato ya kibodi"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Fahamu kuhusu mikato ya kibodi"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Kusogeza kwa kutumia padi yako ya kugusa"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Fahamu miguso ya padi ya kugusa"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Kusogeza kwa kutumia kibodi na padi yako ya kugusa"</string>
@@ -1452,7 +1447,7 @@
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Rudi nyuma"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Telezesha vidole vitatu kushoto au kulia kwenye padi yako ya kugusa"</string>
<string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Safi!"</string>
- <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Umekamilisha ishara ya kurudi nyuma."</string>
+ <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Umekamilisha mafunzo ya miguso ya kurudi nyuma."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Nenda kwenye skrini ya kwanza"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Telezesha vidole vitatu juu kwenye padi yako ya kugusa"</string>
<string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Kazi nzuri!"</string>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index 4de75caf05ae..702af458652a 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Vimezimwa"</item>
<item msgid="3028994095749238254">"Vimewashwa"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Halipatikani"</item>
+ <item msgid="6419996398343291862">"Limezimwa"</item>
+ <item msgid="5908720590832378783">"Limewashwa"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 4a53df9c2f29..055c3a641d1b 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -20,7 +20,6 @@
<!-- keyguard-->
<dimen name="keyguard_indication_margin_bottom">25dp</dimen>
<dimen name="ambient_indication_margin_bottom">115dp</dimen>
- <dimen name="lock_icon_margin_bottom">60dp</dimen>
<!-- margin from keyguard status bar to clock. For split shade it should be
keyguard_split_shade_top_margin - status_bar_header_height_keyguard = 8dp -->
<dimen name="keyguard_clock_top_margin">8dp</dimen>
@@ -46,8 +45,6 @@
<dimen name="lockscreen_shade_max_over_scroll_amount">32dp</dimen>
- <dimen name="status_view_margin_horizontal">8dp</dimen>
-
<!-- Lockscreen shade transition values -->
<dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
<dimen name="lockscreen_shade_full_transition_distance">200dp</dimen>
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index 707bc9e535ff..f73e91af8aff 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -16,8 +16,6 @@
-->
<resources>
<dimen name="notification_panel_margin_horizontal">48dp</dimen>
- <dimen name="status_view_margin_horizontal">62dp</dimen>
-
<!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two
pages is margin * 2, and that makes tiles page not appear immediately after user swipes to
the side -->
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index 8583f0549960..41bb37efa623 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -22,8 +22,6 @@
<dimen name="keyguard_split_shade_top_margin">72dp</dimen>
- <dimen name="status_view_margin_horizontal">24dp</dimen>
-
<dimen name="qs_media_session_height_expanded">184dp</dimen>
<dimen name="qs_content_horizontal_padding">40dp</dimen>
<dimen name="qs_horizontal_margin">40dp</dimen>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index 9248d585bba7..eb570b8f76d6 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -20,8 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <dimen name="status_view_margin_horizontal">124dp</dimen>
-
<dimen name="large_screen_shade_header_left_padding">24dp</dimen>
<dimen name="qqs_layout_padding_bottom">40dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 639bc394972a..99c912ca072a 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -310,7 +310,7 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"சேமிக்கப்பட்டது"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"இணைப்பு நீக்கும்"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"செயல்படுத்தும்"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"தானாகவே நாளை இயக்கப்படும்"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"தானாகவே நாளை இயங்குதல்"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"விரைவுப் பகிர்தல், Find My Device போன்ற அம்சங்கள் புளூடூத்தைப் பயன்படுத்துகின்றன"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"நாளை காலை புளூடூத் இயக்கப்படும்"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"ஆடியோவைப் பகிர்"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"உள்ளீடு"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"செவித்துணைக் கருவி"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ஆன் செய்கிறது…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"சிறந்த ஆப்ஸால் ஒளிர்வு கட்டுப்படுத்தப்படுவதால்\n இதைச் சரிசெய்ய முடியவில்லை"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"தானாகச் சுழற்று"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"திரையைத் தானாகச் சுழற்று"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"இருப்பிடம்"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"புதிய சாதனத்தை இணைக்க கிளிக் செய்யலாம்"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"முன்னமைவைப் புதுப்பிக்க முடியவில்லை"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"முன்னமைவு"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"தேர்ந்தெடுக்கப்பட்டது"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"கருவிகள்"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"உடனடி வசனம்"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"குறிப்பு"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"சாதனத்தின் மைக்ரோஃபோனுக்கான தடுப்பை நீக்கவா?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"சாதனத்தின் கேமராவுக்கான தடுப்பை நீக்கவா?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"சாதனத்தின் கேமராவுக்கும் மைக்ரோஃபோனுக்குமான தடுப்பை நீக்கவா?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது வலது/கீழ் உள்ள ஆப்ஸுக்கு மாறுதல்"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது இடது/மேலே உள்ள ஆப்ஸுக்கு மாறுதல்"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"திரைப் பிரிப்பின்போது: ஓர் ஆப்ஸுக்குப் பதிலாக மற்றொன்றை மாற்றுதல்"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"காட்சிகளுக்கு இடையே செயலில் உள்ள சாளரத்தை நகர்த்துதல்"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"உள்ளீடு"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"அடுத்த மொழிக்கு மாற்றுதல்"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"முந்தைய மொழிக்கு மாற்றுதல்"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> எழுத்துகளுக்குக் குறைவாகப் பயன்படுத்துங்கள்"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"திறந்தநிலை உரையாடல்"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"உரையாடல் விட்ஜெட்டுகள்"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ஓர் உரையாடலை உங்கள் முகப்புத் திரையில் சேர்க்க அந்த உரையாடலைத் தட்டுங்கள்"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"உயர் தெளிவுத்திறனுக்கு, மொபைலை ஃபிளிப் செய்யுங்கள்"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"மடக்கத்தக்க சாதனம் திறக்கப்படுகிறது"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"மடக்கத்தக்க சாதனம் ஃபிளிப் செய்யப்பட்டு திருப்பப்படுகிறது"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"மடக்கப்பட்டது"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"விரிக்கப்பட்டது"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"மாற்றுத்திறன் வசதி"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"கீபோர்டு ஷார்ட்கட்கள்"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"கீபோர்டு ஷார்ட்கட்களைப் பிரத்தியேகப்படுத்துதல்"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ஷார்ட்கட்டை அமைக்க பட்டனை அழுத்துங்கள்"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ஷார்ட்கட்களைத் தேடுக"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"தேடல் முடிவுகள் இல்லை"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"சுருக்குவதற்கான ஐகான்"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ஆக்‌ஷன்/மெட்டா பட்டன் ஐகான்"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"பிளஸ் ஐகான்"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"பிரத்தியேகப்படுத்தும்"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"முடிந்தது"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"விரிவாக்குவதற்கான ஐகான்"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"அல்லது"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"இழுப்பதற்கான ஹேண்டில்"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"கீபோர்டு அமைப்புகள்"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ஷார்ட்கட்டை அமையுங்கள்"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ரத்துசெய்"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"பட்டனை அழுத்துங்கள்"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"பட்டன் சேர்க்கை ஏற்கெனவே பயன்பாட்டில் உள்ளது. வேறொரு பட்டனைப் பயன்படுத்திப் பார்க்கவும்."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"கீபோர்டைப் பயன்படுத்திச் செல்லுதல்"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"கீபோர்டு ஷார்ட்கட்கள் குறித்துத் தெரிந்துகொள்ளுங்கள்"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"டச்பேடைப் பயன்படுத்திச் செல்லுதல்"</string>
@@ -1463,7 +1459,7 @@
<string name="tutorial_action_key_title" msgid="8172535792469008169">"அனைத்து ஆப்ஸையும் காட்டு"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"உங்கள் கீபோர்டில் ஆக்‌ஷன் பட்டனை அழுத்தவும்"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"அருமை!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"அனைத்து ஆப்ஸுக்கான சைகை பயிற்சியையும் நிறைவுசெய்துவிட்டீர்கள்"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"அனைத்து ஆப்ஸையும் பார்ப்பதற்கான சைகை பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"கீபோர்டு பேக்லைட்"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"நிலை, %2$d இல் %1$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ஹோம் கன்ட்ரோல்கள்"</string>
diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
index 66cdeec01991..17cc570f6b0d 100644
--- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"முடக்கப்பட்டுள்ளது"</item>
<item msgid="3028994095749238254">"இயக்கப்பட்டுள்ளது"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"கிடைக்கவில்லை"</item>
+ <item msgid="6419996398343291862">"முடக்கப்பட்டுள்ளது"</item>
+ <item msgid="5908720590832378783">"இயக்கப்பட்டுள்ளது"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 2834196437d5..5a088231c945 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ఇన్‌పుట్"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"వినికిడి పరికరాలు"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ఆన్ చేస్తోంది…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ఇది టాప్ యాప్ ద్వారా\n కంట్రోల్ చేయబడుతున్నందున బ్రైట్‌నెస్‌ను సర్దుబాటు చేయడం సాధ్యం కాదు"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ఆటో-రొటేట్‌"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"స్క్రీన్ ఆటో-రొటేట్‌"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"లొకేషన్"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"కొత్త పరికరాన్ని పెయిర్ చేయడానికి క్లిక్ చేయండి"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ప్రీసెట్‌ను అప్‌డేట్ చేయడం సాధ్యపడలేదు"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ప్రీసెట్"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ఎంచుకోబడింది"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"టూల్స్"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"లైవ్ క్యాప్షన్"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"గమనిక"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"పరికరం మైక్రోఫోన్‌ను అన్‌బ్లాక్ చేయమంటారా?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"పరికరంలోని కెమెరాను అన్‌బ్లాక్ చేయమంటారా?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"పరికరంలోని కెమెరా, మైక్రోఫోన్‌లను అన్‌బ్లాక్ చేయమంటారా?"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"ఆఫ్‌లో ఉంది"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"సెట్ చేసి లేదు"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"సెట్టింగ్‌లలో మేనేజ్ చేయండి"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{మోడ్స్ ఏవీ యాక్టివ్‌గా లేవు}=1{{mode} యాక్టివ్‌గా ఉంది}other{# మోడ్స్ యాక్టివ్‌గా ఉన్నాయి}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{యాక్టివ్ మోడ్స్ లేవు}=1{{mode} యాక్టివ్‌గా ఉంది}other{# మోడ్స్ యాక్టివ్‌గా ఉన్నాయి}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"మీరు పేర్కొనే అలారాలు, రిమైండర్‌లు, ఈవెంట్‌లు మరియు కాలర్‌ల నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"అలారాలు నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"అనుకూలంగా మార్చండి"</string>
@@ -584,7 +584,7 @@
<string name="notification_settings_button_description" msgid="2441994740884163889">"నోటిఫికేషన్ సెట్టింగ్‌లు"</string>
<string name="notification_history_button_description" msgid="1578657591405033383">"నోటిఫికేషన్ హిస్టరీ"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"కొత్తవి"</string>
- <string name="notification_section_header_gentle" msgid="6804099527336337197">"నిశ్శబ్దం"</string>
+ <string name="notification_section_header_gentle" msgid="6804099527336337197">"సైలెంట్ మోడ్"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"నోటిఫికేషన్‌లు"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"అన్ని నిశ్శబ్ద నోటిఫికేషన్‌లను క్లియర్ చేస్తుంది"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు కుడి లేదా కింద యాప్‌నకు మారండి"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు ఎడమ లేదా పైన యాప్‌నకు మారండి"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"స్ప్లిట్ స్క్రీన్ సమయంలో: ఒక దాన్నుండి మరో దానికి యాప్ రీప్లేస్ చేయండి"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"యాక్టివ్ విండోను డిస్‌ప్లేల మధ్య తరలించండి"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ఇన్‌పుట్"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"తర్వాత భాషకు స్విచ్ అవ్వండి"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"మునుపటి భాషకు స్విచ్ అవ్వండి"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> కంటే తక్కువ అక్షరాలను ఉపయోగించండి"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్‌బోర్డ్‌కు కాపీ చేయబడింది."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"సంభాషణను తెరవండి"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"సంభాషణ విడ్జెట్‌లు"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"ఏదైనా సంభాషణను మీ మొదటి స్క్రీన్‌కు జోడించడానికి దానిని ట్యాప్ చేయండి"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"అధిక రిజల్యూషన్ కోసం, ఫోన్‌ను తిప్పండి"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"మడవగల పరికరం విప్పబడుతోంది"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"మడవగల పరికరం చుట్టూ తిప్పబడుతోంది"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"మడిచే సదుపాయం గల పరికరం"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"మడిచే సదుపాయం లేని పరికరం"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,33 +1418,26 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"యాక్సెసిబిలిటీ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"కీబోర్డ్ షార్ట్‌కట్‌లు"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"కీబోర్డ్ షార్ట్‌కట్‌లను అనుకూలంగా మార్చండి"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"షార్ట్‌కట్‌ను కేటాయించడానికి కీని నొక్కండి"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"షార్ట్‌కట్‌లను వెతకండి"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"సెర్చ్ ఫలితాలు ఏవీ లేవు"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"యాక్షన్ లేదా మెటా కీ చిహ్నం"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ప్లస్ చిహ్నం"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"అనుకూలంగా మార్చండి"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"పూర్తయింది"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"విస్తరించండి చిహ్నం"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"లేదా"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"లాగే హ్యాండిల్"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"కీబోర్డ్ సెట్టింగ్‌లు"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"షార్ట్‌కట్‌ను సెట్ చేయండి"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"రద్దు చేయండి"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"కీని నొక్కండి"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"కీ కాంబినేషన్ ఇప్పటికే వినియోగంలో ఉంది. వేరొక కీని ట్రై చేయండి."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"మీ కీబోర్డ్ ఉపయోగించి నావిగేట్ చేయండి"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"కీబోర్డ్ షార్ట్‌కట్‌ల గురించి తెలుసుకోండి"</string>
- <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"మీ టచ్‌ప్యాడ్‌ని ఉపయోగించి నావిగేట్ చేయండి"</string>
- <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"టచ్‌ప్యాడ్ సంజ్ఞ గురించి తెలుసుకోండి"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"మీ టచ్‌ప్యాడ్‌ను ఉపయోగించి నావిగేట్ చేయండి"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"టచ్‌ప్యాడ్ సంజ్ఞల గురించి తెలుసుకోండి"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"మీ కీబోర్డ్, టచ్‌ప్యాడ్‌ను ఉపయోగించి నావిగేట్ చేయండి"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"టచ్‌ప్యాడ్ సంజ్ఞలు, కీబోర్డ్ షార్ట్‌కట్‌లు, అలాగే మరిన్నింటిని గురించి తెలుసుకోండి"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"వెనుకకు వెళ్లండి"</string>
@@ -1450,7 +1446,7 @@
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"పూర్తయింది"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"వెనుకకు"</string>
<string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"మీ టచ్‌ప్యాడ్‌లో మూడు వేళ్లను ఉపయోగించి ఎడమ వైపునకు లేదా కుడి వైపునకు స్వైప్ చేయండి"</string>
- <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"పనితీరు బాగుంది!"</string>
+ <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"సూపర్!"</string>
<string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"తిరిగి వెనుకకు వెళ్ళడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్‌ను మీరు పూర్తి చేశారు."</string>
<string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"మొదటి ట్యాబ్‌కు వెళ్లండి"</string>
<string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"మీ టచ్‌ప్యాడ్‌పై మూడు వేళ్లతో పైకి స్వైప్ చేయండి"</string>
@@ -1458,12 +1454,12 @@
<string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"మీరు మొదటి స్క్రీన్‌కు వెళ్లే సంజ్ఞను పూర్తి చేశారు"</string>
<string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ఇటీవలి యాప్‌లను చూడండి"</string>
<string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"మీ టచ్‌ప్యాడ్‌లో మూడు వేళ్లను ఉపయోగించి పైకి స్వైప్ చేసి, హోల్డ్ చేయండి"</string>
- <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"పనితీరు అద్భుతంగా ఉంది!"</string>
- <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"మీరు ఇటీవలి యాప్‌ల వీక్షణ సంజ్ఞను పూర్తి చేశారు."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"చక్కగా పూర్తి చేశారు!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ఇటీవలి యాప్‌లను చూడడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్‌ను మీరు పూర్తి చేశారు."</string>
<string name="tutorial_action_key_title" msgid="8172535792469008169">"అన్ని యాప్‌లను చూడండి"</string>
<string name="tutorial_action_key_guidance" msgid="5040613427202799294">"మీ కీబోర్డ్‌లో యాక్షన్ కీని నొక్కండి"</string>
<string name="tutorial_action_key_success_title" msgid="2371827347071979571">"చక్కగా చేశారు!"</string>
- <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"మీరు అన్ని యాప్‌ల వీక్షణ సంజ్ఞను పూర్తి చేశారు"</string>
+ <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"అన్ని యాప్‌లను చూడడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్‌ను మీరు పూర్తి చేశారు"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"కీబోర్డ్ బ్యాక్‌లైట్"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dలో %1$dవ స్థాయి"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"హోమ్ కంట్రోల్స్"</string>
diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml
index 42ee13d8cc57..8a0ab4848f60 100644
--- a/packages/SystemUI/res/values-te/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ఆఫ్‌లో ఉంది"</item>
<item msgid="3028994095749238254">"ఆన్‌లో ఉంది"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"అందుబాటులో లేదు"</item>
+ <item msgid="6419996398343291862">"ఆఫ్‌లో ఉంది"</item>
+ <item msgid="5908720590832378783">"ఆన్‌లో ఉంది"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index fcfc4e2364e0..816514a9797f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"อินพุต"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"เครื่องช่วยฟัง"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"กำลังเปิด..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"ปรับความสว่างไม่ได้เนื่องจาก\nควบคุมโดยแอปที่อยู่ด้านบน"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"หมุนอัตโนมัติ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"หมุนหน้าจออัตโนมัติ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ตำแหน่ง"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"คลิกเพื่อจับคู่อุปกรณ์ใหม่"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ไม่สามารถอัปเดตค่าที่กำหนดล่วงหน้า"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ค่าที่กำหนดล่วงหน้า"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"เลือกแล้ว"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"เครื่องมือ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"คำบรรยายสด"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"จดบันทึก"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"เลิกบล็อกไมโครโฟนของอุปกรณ์ใช่ไหม"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"เลิกบล็อกกล้องของอุปกรณ์ใช่ไหม"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"เลิกบล็อกกล้องและไมโครโฟนของอุปกรณ์ใช่ไหม"</string>
@@ -454,7 +454,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"ปิด"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"ไม่ได้ตั้งค่า"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"จัดการในการตั้งค่า"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ไม่มีโหมดที่ใช้งานอยู่}=1{ใช้งานอยู่ {mode} โหมด}other{ใช้งานอยู่ # โหมด}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ไม่มีโหมดที่ใช้งานอยู่}=1{{mode} ทำงานอยู่}other{ใช้งานอยู่ # โหมด}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"คุณจะไม่ถูกรบกวนจากเสียงและการสั่น ยกเว้นเสียงนาฬิกาปลุก การช่วยเตือน กิจกรรม และผู้โทรที่ระบุไว้ คุณจะยังคงได้ยินสิ่งที่คุณเลือกเล่น เช่น เพลง วิดีโอ และเกม"</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"คุณจะไม่ถูกรบกวนจากเสียงและการสั่น ยกเว้นเสียงนาฬิกาปลุก คุณจะยังคงได้ยินสิ่งที่คุณเลือกเล่น เช่น เพลง วิดีโอ และเกม"</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"กำหนดค่า"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"เปลี่ยนไปใช้แอปทางด้านขวาหรือด้านล่างขณะใช้โหมดแยกหน้าจอ"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"เปลี่ยนไปใช้แอปทางด้านซ้ายหรือด้านบนขณะใช้โหมดแยกหน้าจอ"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"ระหว่างใช้โหมดแยกหน้าจอ: เปลี่ยนแอปหนึ่งเป็นอีกแอปหนึ่ง"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"ย้ายหน้าต่างที่ใช้งานไปยังหน้าจอต่างๆ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"อินพุต"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"เปลี่ยนเป็นภาษาถัดไป"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"เปลี่ยนเป็นภาษาก่อนหน้า"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ใช้อักขระไม่เกิน <xliff:g id="LENGTH">%1$d</xliff:g> ตัว"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"เปิดการสนทนา"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"วิดเจ็ตการสนทนา"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"แตะการสนทนาเพื่อเพิ่มไปยังหน้าจอหลัก"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"พลิกด้านโทรศัพท์เพื่อให้ได้ภาพที่มีความละเอียดมากขึ้น"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"อุปกรณ์ที่พับได้กำลังกางออก"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"อุปกรณ์ที่พับได้กำลังพลิกไปมา"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"พับ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"กางออก"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"การช่วยเหลือพิเศษ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"แป้นพิมพ์ลัด"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ปรับแต่งแป้นพิมพ์ลัด"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"กดแป้นเพื่อกำหนดแป้นพิมพ์ลัด"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ค้นหาแป้นพิมพ์ลัด"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ไม่พบผลการค้นหา"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ไอคอนการดำเนินการหรือแป้น Meta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ไอคอนเครื่องหมายบวก"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"ปรับแต่ง"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"เสร็จสิ้น"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ไอคอนขยาย"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"หรือ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"แฮนเดิลการลาก"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"การตั้งค่าแป้นพิมพ์"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ตั้งค่าแป้นพิมพ์ลัด"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ยกเลิก"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"กดแป้น"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"มีการใช้แป้นที่กดร่วมกันนี้แล้ว โปรดลองใช้แป้นอื่น"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ไปยังส่วนต่างๆ โดยใช้แป้นพิมพ์"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ดูข้อมูลเกี่ยวกับแป้นพิมพ์ลัด"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ไปยังส่วนต่างๆ โดยใช้ทัชแพด"</string>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index d249057be4da..4db59c0677c4 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"ปิด"</item>
<item msgid="3028994095749238254">"เปิด"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"ไม่พร้อมใช้งาน"</item>
+ <item msgid="6419996398343291862">"ปิด"</item>
+ <item msgid="5908720590832378783">"เปิด"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 68cc6d2fb872..3845fcd314a4 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Mga hearing aid"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ino-on…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Hindi ma-adjust ang liwanag dahil\n kinokontrol ito ng nangingibabaw na app"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"I-auto rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Awtomatikong i-rotate ang screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasyon"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"I-click para magpares ng bagong device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Hindi ma-update ang preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Napili"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Mga Tool"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Instant Caption"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Tala"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"I-unblock ang mikropono ng device?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"I-unblock ang camera ng device?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"I-unblock ang camera at mikropono ng device?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Lumipat sa app sa kanan o ibaba habang ginagamit ang split screen"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Lumipat sa app sa kaliwa o itaas habang ginagamit ang split screen"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Habang nasa split screen: magpalit-palit ng app"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Ilipat ang aktibong window sa pagitan ng mga display"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Lumipat sa susunod na wika"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Lumipat sa dating wika"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gumamit ng mas kaunti sa <xliff:g id="LENGTH">%1$d</xliff:g> (na) character"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Mga widget ng pag-uusap"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Mag-tap sa isang pag-uusap para idagdag ito sa iyong Home screen"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para sa mas mataas na resolution, i-flip ang telepono"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ina-unfold na foldable na device"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Fini-flip na foldable na device"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"naka-fold"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"hindi naka-fold"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Mga keyboard shortcut"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"I-customize ang mga keyboard shortcut"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pindutin ang key para magtalaga ng shortcut"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Walang resulta ng paghahanap"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Icon ng Action o Meta key"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Icon na plus"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"I-customize"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Tapos na"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"I-expand ang icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handle sa pag-drag"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Mga Setting ng Keyboard"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Magtakda ng shortcut"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Kanselahin"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pindutin ang key"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ginagamit na ang kumbinasyon ng key. Sumubok ng ibang key."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Mag-navigate gamit ang iyong keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Matuto ng mga keyboard shortcut"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Mag-navigate gamit ang iyong touchpad"</string>
diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
index 0e43fafd1a04..4832d1d1b0de 100644
--- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Naka-off"</item>
<item msgid="3028994095749238254">"Naka-on"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Hindi available"</item>
+ <item msgid="6419996398343291862">"Naka-off"</item>
+ <item msgid="5908720590832378783">"Naka-on"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index fd4bb451f024..45d8b4605c29 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -111,7 +111,7 @@
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Ekranınız kaydedilsin mi?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Bir uygulamayı kaydet"</string>
- <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Tüm ekranı kaydedin"</string>
+ <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Tüm ekranı kaydet"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Tüm ekranı kaydet: %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Tüm ekranınızı kaydettiğinizde ekranınızda gösterilen her şey kaydedilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Bir uygulamayı kaydettiğinizde o uygulamada gösterilen veya oynatılan her şey kaydedilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
@@ -311,7 +311,7 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"bağlantıyı kes"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"etkinleştir"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"Yarın otomatik olarak aç"</string>
- <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share ve Cihazımı Bul gibi özellikler Bluetooth\'u kullanır"</string>
+ <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share ve Cihazımı Bul gibi özellikler Bluetooth\'u kullanır."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth yarın sabah açılacak"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Sesi paylaş"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Ses paylaşılıyor"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"İşitme cihazları"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Açılıyor…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Parlaklık ayarlanamıyor, çünkü bu özellik\n en üstteki uygulama tarafından kontrol ediliyor"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Otomatik döndür"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranı otomatik döndür"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Konum"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz eşlemek için tıklayın"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Hazır ayar güncellenemedi"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Hazır Ayar"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seçili"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Araçlar"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Canlı Altyazı"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Not"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonunun engellemesi kaldırılsın mı?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerasının engellemesi kaldırılsın mı?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası ile mikrofonunun engellemesi kaldırılsın mı?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Şimdi başlat"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Bildirim yok"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Yeni bildirim yok"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Bildirim şiddetini düşürme etkin"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Aynı anda çok sayıda bildirim aldığınızda 2 dakika boyunca otomatik olarak cihazınızın sesi kısılır ve uyarıları azaltılır."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Kapat"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Eski bildirimler için kilidi açın"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran kullanırken sağdaki veya alttaki uygulamaya geçiş yap"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran kullanırken soldaki veya üstteki uygulamaya geçiş yapın"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Bölünmüş ekran etkinken: Bir uygulamayı başkasıyla değiştir"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Etkin pencereyi ekranlar arasında taşıma"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Giriş"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Sonraki dile geç"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Önceki dile geç"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"En fazla <xliff:g id="LENGTH">%1$d</xliff:g> karakter kullanın"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Görüşmeyi aç"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Görüşme widget\'ları"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Ana ekranınıza eklemek için bir görüşmeye dokunun"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Daha yüksek çözünürlük için telefonu çevirin"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Katlanabilir cihaz açılıyor"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Katlanabilir cihaz döndürülüyor"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"katlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"katlanmamış"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erişilebilirlik"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klavye kısayolları"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klavye kısayollarını özelleştirin"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Kısayol atamak için tuşa basın"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Arama kısayolları"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Arama sonucu yok"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"İşlem veya Meta tuşu simgesi"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Artı simgesi"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Özelleştir"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Bitti"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Genişlet simgesi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"veya"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Sürükleme tutamacı"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klavye Ayarları"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Kısayol ayarla"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"İptal"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tuşa basın"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tuş kombinasyonu zaten kullanılıyor. Başka bir tuş deneyin."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klavyenizi kullanarak gezinin"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klavye kısayollarını öğrenin"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Dokunmatik alanınızı kullanarak gezinin"</string>
diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
index 1e30c6d3a5c1..1c0c110baab1 100644
--- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Kapalı"</item>
<item msgid="3028994095749238254">"Açık"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Yok"</item>
+ <item msgid="6419996398343291862">"Kapalı"</item>
+ <item msgid="5908720590832378783">"Açık"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index ab5f8a42697a..4c4c80ea31a3 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -311,7 +311,7 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"від’єднати"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"активувати"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"Автоматично ввімкнути завтра"</string>
- <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Такі функції, як швидкий обмін і \"Знайти пристрій\", використовують Bluetooth"</string>
+ <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Такі функції, як \"Швидкий обмін\" і \"Знайти пристрій\", використовують Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth увімкнеться завтра вранці"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Поділитись аудіо"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Надсилання аудіо"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Джерело сигналу"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухові апарати"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Увімкнення…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Не вдається змінити яскравість, оскільки\n нею керує основний додаток"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автообертання"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично обертати екран"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Геодані"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Натисніть, щоб підключити новий пристрій"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Не вдалось оновити набір налаштувань"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Набір налаштувань"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Вибрано"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Інструменти"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Живі субтитри"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Нотатка"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Надати доступ до мікрофона?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Надати доступ до камери пристрою?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Надати доступ до камери й мікрофона?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Почати зараз"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Сповіщень немає"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Немає нових сповіщень"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Зниження гучності сповіщень увімкнено"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Коли ви отримуєте забагато сповіщень за раз, пристрій автоматично знижує їх гучність і кількість на період до 2 хвилин."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Вимкнути"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Розблокуйте, щоб переглянути старіші"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Перейти до додатка праворуч або внизу на розділеному екрані"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Під час розділення екрана перемикатися на додаток ліворуч або вгорі"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Під час розділення екрана: замінити додаток іншим"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Перемістити активне вікно між дисплеями"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Метод введення"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Вибрати наступну мову"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Вибрати попередню мову"</string>
@@ -1203,8 +1201,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Колонки й екрани"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Пропоновані пристрої"</string>
- <string name="media_input_group_title" msgid="2057057473860783021">"Введення"</string>
- <string name="media_output_group_title" msgid="6789001895863332576">"Виведення"</string>
+ <string name="media_input_group_title" msgid="2057057473860783021">"Ввід"</string>
+ <string name="media_output_group_title" msgid="6789001895863332576">"Вивід"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Зупиніть сеанс спільного доступу, щоб перенести медіаконтент на інший пристрій"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Зупинити"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як працює трансляція"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Кількість символів має бути менше ніж <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Відкрита розмова"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Віджети розмов"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Натисніть розмову, щоб додати її на головний екран"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Для вищої роздільної здатності переверніть телефон"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Розкладний пристрій у розкладеному стані"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Розкладний пристрій обертається"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складений"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"розкладений"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Доступність"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Комбінації клавіш"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Налаштуйте комбінації клавіш"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Натисніть клавішу, щоб призначити комбінацію клавіш"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Комбінації клавіш для пошуку"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Нічого не знайдено"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок згортання"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Значок клавіші дії або метаклавіші"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Значок \"плюс\""</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Налаштувати"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Готово"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок розгортання"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер переміщення"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Налаштування клавіатури"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Налаштувати комбінацію клавіш"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Скасувати"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Натисніть клавішу"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Комбінація клавіш уже використовується. Спробуйте іншу клавішу."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігація за допомогою клавіатури"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Дізнайтеся більше про комбінації клавіш"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігація за допомогою сенсорної панелі"</string>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index 6c03aea7b3af..656ccd439244 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Вимкнено"</item>
<item msgid="3028994095749238254">"Увімкнено"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Недоступно"</item>
+ <item msgid="6419996398343291862">"Вимкнено"</item>
+ <item msgid="5908720590832378783">"Увімкнено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 39aa5d1ccfcc..109f43eb5632 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ان پٹ"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعتی آلات"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"آن ہو رہا ہے…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"چمک کو ایڈجسٹ نہیں کیا جا سکتا کیونکہ اسے سرفہرست ایپ کے ذریعے \n کنٹرول کیا جا رہا ہے"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"خود کار طور پر گھمائیں"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"اسکرین کو خود کار طور پر گھمائیں"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مقام"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"نئے آلے کا جوڑا بنانے کے لیے کلک کریں"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"پہلے سے ترتیب شدہ کو اپ ڈیٹ نہیں کیا جا سکا"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"پہلے سے ترتیب شدہ"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"منتخب کردہ"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ٹولز"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"لائیو کیپشن"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"نوٹ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"آلے کا مائیکروفون غیر مسدود کریں؟"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"آلے کا کیمرا غیر مسدود کریں؟"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"آلے کا کیمرا اور مائیکروفون غیر مسدود کریں؟"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"ابھی شروع کریں"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"کوئی اطلاعات نہیں ہیں"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"کوئی نئی اطلاعات نہیں"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"ںوٹیفیکیشن کول ڈاؤن اب آن ہے"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"جب آپ کو ایک ساتھ بہت زیادہ اطلاعات موصول ہوتی ہیں تو آپ کے آلے کا والیوم اور الرٹس خودکار طور پر 2 منٹ تک کم ہو جاتے ہیں۔"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"آف کریں"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"پرانی اطلاعات دیکھنے کیلئے غیر مقفل کریں"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"اسپلٹ اسکرین کا استعمال کرتے ہوئے دائیں یا نیچے ایپ پر سوئچ کریں"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"اسپلٹ اسکرین کا استعمال کرتے ہوئے بائیں یا اوپر ایپ پر سوئچ کریں"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"اسپلٹ اسکرین کے دوران: ایک ایپ کو دوسرے سے تبدیل کریں"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"فعال ونڈو کو ڈسپلیز کے مابین منتقل کریں"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ان پٹ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"اگلی زبان پر سوئچ کریں"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"پچھلی زبان پر سوئچ کریں"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> حروف سے کم استعمال کریں"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"گفتگو کھولیں"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"گفتگو ویجیٹس"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"اسے اپنی ہوم اسکرین پر شامل کرنے کے لیے گفتگو پر تھپتھپائیں"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"زیادہ ریزولوشن کے لیے، فون پلٹائیں"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"فولڈ ہونے والے آلے کو کھولا جا رہا ہے"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"فولڈ ہونے والے آلے کو گھمایا جا رہا ہے"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"فولڈ کردہ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"اَن فولڈ کردہ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ایکسیسبیلٹی"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"کی بورڈ شارٹ کٹس"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"کی بورڈ شارٹ کٹس کو حسب ضرورت بنائیں"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"شارٹ کٹ تفویض کرنے کے لیے کلید کو دبائیں"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"تلاش کے شارٹ کٹس"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"تلاش کا کوئی نتیجہ نہیں ہے"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"‏کارروائی یا Meta کلید کا آئیکن"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"پلس کا آئیکن"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"حسب ضرورت بنائیں"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ہو گیا"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"آئیکن پھیلائیں"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"گھسیٹنے کا ہینڈل"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"کی بورڈ کی ترتیبات"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"شارٹ کٹ سیٹ کریں"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"منسوخ کریں"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"کلید کو دبائیں"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"کلیدی مجموعہ پہلے سے استعمال میں ہے۔ دوسری کلید آزمائیں۔"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"اپنے کی بورڈ کا استعمال کر کے نیویگیٹ کریں"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"کی بورڈ شارٹ کٹس جانیں"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"اپنے ٹچ پیڈ کا استعمال کر کے نیویگیٹ کریں"</string>
diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
index a213f00e496d..4aa490d927b1 100644
--- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"آف ہے"</item>
<item msgid="3028994095749238254">"آن ہے"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"دستیاب نہیں ہے"</item>
+ <item msgid="6419996398343291862">"آف"</item>
+ <item msgid="5908720590832378783">"آن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 67cc8b638a92..1c27a0055cce 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -114,7 +114,7 @@
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Butun ekranni yozib olish"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Butun ekranni yozib olish: %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Butun ekranni yozib olishda ekranda koʻrsatilgan barcha axborotlar yozib olinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Ilovani yozib olishda ilova koʻrsatilgan yoki ijro etilgan barcha axborotlar yozib olinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Ilovani yozib olishda ilovada koʻrsatilgan yoki ijro etilgan barcha axborotlar yozib olinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ekranni yozib olish"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Yozib olinadigan ilovani tanlash"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Audio yozib olish"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Kirish"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eshitish moslamalari"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Yoqilmoqda…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Yorqinlik umumiy sozlamalar orqali boshqariladi.\nUni moslash imkonsiz"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avto-burilish"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranning avtomatik burilishi"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yangi qurilmani ulash uchun bosing"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Andoza yangilanmadi"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Andoza"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Tanlangan"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Vositalar"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Jonli izoh"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Qayd"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Qurilma mikrofoni blokdan chiqarilsinmi?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Qurilma kamerasi blokdan chiqarilsinmi?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Qurilma kamerasi va mikrofoni blokdan chiqarilsinmi?"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ajratilgan ekranda oʻngdagi yoki pastdagi ilovaga almashish"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ajratilgan ekranda chapdagi yoki yuqoridagi ilovaga almashish"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ajratilgan rejimda ilovalarni oʻzaro almashtirish"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Faol oynani ekranlararo koʻchirish"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Kiritish"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Keyingi tilga almashtirish"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Avvalgi tilga almashtirish"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Kiritiladigan belgilar <xliff:g id="LENGTH">%1$d</xliff:g> tadan oshmasin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Suhbat vidjetlari"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Bosh ekranga chiqariladigan suhbat ustiga bosing"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Yuqori aniqlik uchun telefonni aylantiring"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Buklanadigan qurilma ochilmoqda"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Buklanadigan qurilma aylantirilmoqda"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"buklangan"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"buklanmagan"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qulayliklar"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tezkor tugmalar"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tezkor tugmalarni moslash"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tezkor tugma sozlash uchun tugmani bosing"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Hech narsa topilmadi"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Amal bajarish uchun Meta tugmasi belgisi"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plus belgisi"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Moslash"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Tayyor"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"yoki"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Surish dastagi"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatura sozlamalari"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tezkor tugma sozlash"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Bekor qilish"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tugmani bosing"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Bu tugmalar birikmasi band. Boshqasini ishlating."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviatura yordamida kezing"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tezkor tugmalar haqida"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Sensorli panel yordamida kezing"</string>
diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
index 5e6611c3c1d5..1c32e9fbd53b 100644
--- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Oʻchiq"</item>
<item msgid="3028994095749238254">"Yoniq"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Mavjud emas"</item>
+ <item msgid="6419996398343291862">"Yoqilmagan"</item>
+ <item msgid="5908720590832378783">"Yoniq"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 6752ceb27e97..d8e3bc0c1ffd 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Thiết bị đầu vào"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Thiết bị trợ thính"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Đang bật…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Không điều chỉnh được độ sáng vì độ sáng đang được\n ứng dụng trên cùng điều khiển"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Tự động xoay"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Nhấp để ghép nối thiết bị mới"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Không cập nhật được giá trị đặt trước"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Chế độ đặt sẵn"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Đã chọn"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Công cụ"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Phụ đề trực tiếp"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Ghi chú"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Bỏ chặn micrô của thiết bị?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Bỏ chặn camera của thiết bị?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Bỏ chặn máy ảnh và micrô của thiết bị?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Bắt đầu ngay"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Không có thông báo nào"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Không có thông báo mới"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Chế độ Giảm dần âm lượng thông báo đang bật"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Khi bạn nhận quá nhiều thông báo cùng lúc, âm lượng và cảnh báo tự động giảm trong tối đa 2 phút."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Tắt"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Mở khoá để xem thông báo cũ"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Chuyển sang ứng dụng bên phải hoặc ở dưới khi đang chia đôi màn hình"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Chuyển sang ứng dụng bên trái hoặc ở trên khi đang chia đôi màn hình"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Trong chế độ chia đôi màn hình: thay một ứng dụng bằng ứng dụng khác"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Di chuyển cửa sổ đang hoạt động giữa các màn hình"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Đầu vào"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Chuyển sang ngôn ngữ tiếp theo"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Chuyển về ngôn ngữ trước"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Hãy dùng ít hơn <xliff:g id="LENGTH">%1$d</xliff:g> ký tự"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Mở cuộc trò chuyện"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Tiện ích trò chuyện"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Nhấn vào một cuộc trò chuyện để thêm cuộc trò chuyện đó vào Màn hình chính"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Để có độ phân giải cao hơn, hãy lật điện thoại"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Thiết bị có thể gập lại đang được mở ra"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Thiết bị có thể gập lại đang được lật ngược"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gập"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"mở"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hỗ trợ tiếp cận"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Phím tắt"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tuỳ chỉnh phím tắt"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Nhấn phím để chỉ định phím tắt"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tìm lối tắt"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Không có kết quả tìm kiếm nào"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Biểu tượng phím Meta (phím hành động)"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Biểu tượng dấu cộng"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Tuỳ chỉnh"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Xong"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Biểu tượng Mở rộng"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"hoặc"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Nút kéo"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Cài đặt bàn phím"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Đặt phím tắt"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Huỷ"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nhấn phím"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tổ hợp phím đã được sử dụng. Hãy thử một phím khác."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Di chuyển bằng bàn phím"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tìm hiểu về phím tắt"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Di chuyển bằng bàn di chuột"</string>
diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
index 8aa360bbeaf7..466eb3d6017c 100644
--- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Đang tắt"</item>
<item msgid="3028994095749238254">"Đang bật"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Không có"</item>
+ <item msgid="6419996398343291862">"Đang tắt"</item>
+ <item msgid="5908720590832378783">"Đang bật"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 6e76bb7dbe4e..d9a974aad94a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -311,7 +311,7 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"断开连接"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"启用"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"明天自动开启"</string>
- <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"快速分享、查找我的设备等功能会使用蓝牙"</string>
+ <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"“快速分享”“查找我的设备”等功能会使用蓝牙"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"蓝牙将在明天早上开启"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"分享音频"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"正在分享音频"</string>
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"输入"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助听器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在开启…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"亮度无法调整,因为它正在被\n顶层应用控制"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自动屏幕旋转"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自动旋转屏幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置信息"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"点击即可与新设备配对"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"无法更新预设"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"预设"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"已选择"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"工具"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"实时字幕"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"记事"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解锁设备麦克风吗?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解锁设备摄像头吗?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解锁设备摄像头和麦克风吗?"</string>
@@ -449,7 +449,7 @@
<string name="zen_modes_dialog_title" msgid="8854640808100096934">"模式"</string>
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"完成"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"设置"</string>
- <string name="zen_mode_on" msgid="9085304934016242591">"开启"</string>
+ <string name="zen_mode_on" msgid="9085304934016242591">"已开启"</string>
<string name="zen_mode_on_with_details" msgid="7416143430557895497">"已开启 • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="zen_mode_off" msgid="1736604456618147306">"已关闭"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"未设置"</string>
@@ -871,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分屏模式时,切换到右侧或下方的应用"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分屏模式时,切换到左侧或上方的应用"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"在分屏期间:将一个应用替换为另一个应用"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"在各个显示屏之间移动活动窗口"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"输入"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"切换到下一种语言"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"切换到上一种语言"</string>
@@ -1221,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"必须少于 <xliff:g id="LENGTH">%1$d</xliff:g> 个字符"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build 号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将 Build 号复制到剪贴板。"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"开放式对话"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"对话微件"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"点按对话即可将其添加到主屏幕"</string>
@@ -1356,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"若要获得更高的分辨率,请翻转手机"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展开可折叠设备"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻转可折叠设备"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折叠状态"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"展开状态"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1415,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"无障碍功能"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"键盘快捷键"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自定义键盘快捷键"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"按下按键即可指定快捷键"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜索快捷键"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"无搜索结果"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"操作键或元键图标"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"加号图标"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"自定义"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"完成"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展开图标"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖动手柄"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"键盘设置"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"设置快捷键"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按下按键"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"按键组合已被使用,请尝试使用其他按键。"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用键盘导航"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"了解键盘快捷键"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用触控板导航"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 2259076341cf..65415f615ceb 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"已关闭"</item>
<item msgid="3028994095749238254">"已开启"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"不可用"</item>
+ <item msgid="6419996398343291862">"关闭"</item>
+ <item msgid="5908720590832378783">"开启"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 32fe2a100b69..443b8556fe18 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在開啟…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"無法調整亮度,因為\n目前是由上層應用程式控制亮度"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"㩒一下就可以配對新裝置"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"無法更新預設"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"預設"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"揀咗"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"工具"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"即時字幕"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"筆記"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解除封鎖裝置相機和麥克風嗎?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"沒有通知"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"沒有新通知"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"通知緩和功能現已啟用"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"當你在短時間內收到太多通知時,裝置就會調低音量並減少通知數量最多兩分鐘。"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"關閉"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"解鎖即可查看舊通知"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割螢幕時,切換至右邊或下方的應用程式"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割螢幕時,切換至左邊或上方的應用程式"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"使用分割螢幕期間:更換應用程式"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"在不同畫面間移動使用中的視窗"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"輸入"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"切換至下一個語言"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"切換至上一個語言"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"請使用少於 <xliff:g id="LENGTH">%1$d</xliff:g> 個字元"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"開啟對話"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"對話小工具"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"輕按對話即可新增至主畫面"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"如要提高解像度,請切換至手機後置鏡頭"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已打開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙功能"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自訂鍵盤快速鍵"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"按鍵即可指派快速鍵"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"沒有相符的搜尋結果"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"快捷操作鍵或修飾鍵圖示"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"加號圖示"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"自訂"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"完成"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖曳控點"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"鍵盤設定"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"設定快速鍵"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按鍵"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"此按鍵組合已在使用,請改用其他按鍵。"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤導覽"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"瞭解鍵盤快速鍵"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板導覽"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
index c5e05c91e5f1..0882be746b06 100644
--- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"關閉"</item>
<item msgid="3028994095749238254">"開啟"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"無法使用"</item>
+ <item msgid="6419996398343291862">"關閉"</item>
+ <item msgid="5908720590832378783">"開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 9778e7022725..4b84f25fca1b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"開啟中…"</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"無法調整亮度,因為\n目前是由上層應用程式控制亮度"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"定位"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"按一下即可配對新裝置"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"無法更新預設設定"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"預設"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"已選取"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"工具"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"即時字幕"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"筆記"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"解除封鎖裝置相機?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要將裝置的相機和麥克風解除封鎖嗎?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"沒有通知"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"沒有新通知"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"「通知冷卻」設定已開啟"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"如果一次收到過多通知,裝置就會自動降低音量並減少通知數量,持續時間最多 2 分鐘。"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"關閉"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"解鎖即可查看舊通知"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割畫面時,切換到右邊或上方的應用程式"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割畫面時,切換到左邊或上方的應用程式"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"使用分割畫面期間:更換應用程式"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"在不同畫面間移動使用中的視窗"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"輸入"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"切換到下一個語言"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"切換到上一個語言"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"不得超過 <xliff:g id="LENGTH">%1$d</xliff:g> 個半形字元"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"開放式對話"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"對話小工具"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"輕觸對話即可新增至主畫面"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"如要提高解析度,請切換至手機後置鏡頭"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開的折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已展開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自訂鍵盤快速鍵"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"按下按鍵即可指派快速鍵"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"找不到相符的搜尋結果"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"快捷操作鍵或修飾鍵圖示"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"加號圖示"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"自訂"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"完成"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖曳控點"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"鍵盤設定"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"設定快速鍵"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按下按鍵"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"這個按鍵組合已在使用中,請改用其他按鍵。"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤操作"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"學習鍵盤快速鍵"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板操作"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
index 2d34b380af52..f94b0449c598 100644
--- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"已關閉"</item>
<item msgid="3028994095749238254">"已開啟"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"無法使用"</item>
+ <item msgid="6419996398343291862">"關閉"</item>
+ <item msgid="5908720590832378783">"開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9f8cf1fe2610..4afb67d2af8f 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -326,8 +326,7 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Okokufaka"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Imishini yendlebe"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Iyavula..."</string>
- <!-- no translation found for quick_settings_brightness_unable_adjust_msg (786478497970492300) -->
- <skip />
+ <string name="quick_settings_brightness_unable_adjust_msg" msgid="786478497970492300">"Ayikwazi ukulungisa ukukhanya ngoba ilawulwa\n yi-app ephezulu"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ukuphenduka okuzenzakalelayo"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Phendula iskrini ngokuzenzakalela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Indawo"</string>
@@ -415,9 +414,10 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Chofoza ukuze ubhangqe idivayisi entsha"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ayikwazanga ukubuyekeza ukusetha ngaphambilini"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Ukusetha ngaphambilini"</string>
+ <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Okukhethiwe"</string>
+ <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Amathuluzi"</string>
<string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Okushuthwe Bukhoma"</string>
- <!-- no translation found for quick_settings_notes_label (1028004078001002623) -->
- <skip />
+ <string name="quick_settings_notes_label" msgid="1028004078001002623">"Inothi"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vulela imakrofoni yedivayisi?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vulela ikhamera yedivayisi?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vulela ikhamera yedivayisi nemakrofoni?"</string>
@@ -593,8 +593,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Qala manje"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Azikho izaziso"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Azikho izaziso ezintsha"</string>
- <!-- no translation found for adaptive_notification_edu_hun_title (2594042455998795122) -->
- <skip />
+ <string name="adaptive_notification_edu_hun_title" msgid="2594042455998795122">"Ukwehlisa umsindo wezaziso manje kuvuliwe"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Ivolumu yedivayisi yakho kanye nezexwayiso kuncishiswa ngokuzenzakalelayo imizuzu efika kwemi-2 lapho uthola izaziso eziningi kakhulu ngesikhathi esisodwa."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Vala"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Vula ukuze ubone izaziso ezindala"</string>
@@ -872,8 +871,7 @@
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Shintshela ku-app ngakwesokudla noma ngezansi ngenkathi usebenzisa uhlukanisa isikrini"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Shintshela ku-app ngakwesokunxele noma ngaphezulu ngenkathi usebenzisa ukuhlukanisa isikrini"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ngesikhathi sokuhlukaniswa kwesikrini: shintsha i-app ngenye"</string>
- <!-- no translation found for system_multitasking_move_to_next_display (6169737557526976997) -->
- <skip />
+ <string name="system_multitasking_move_to_next_display" msgid="6169737557526976997">"Hambisa iwindi elisebenzayo phakathi kwezibonisi"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Okokufaka"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Shintshela olimini olulandelayo"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Shintshela olimini lwangaphambili"</string>
@@ -1222,6 +1220,8 @@
<string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Sebenzisa isinhlamvu ezimbalwa kuneziyi-<xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
+ <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
+ <skip />
<string name="basic_status" msgid="2315371112182658176">"Vula ingxoxo"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Amawijethi wengxoxo"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Thepha ingxoxo ukuyengeza Kusikrini sakho sasekhaya"</string>
@@ -1357,6 +1357,8 @@
<string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Ukuze uthole ukulungiswa okuphezulu, phendula ifoni"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Idivayisi egoqekayo iyembulwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Idivayisi egoqekayo iphendulwa nxazonke"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kugoqiwe"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kuvuliwe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1416,29 +1418,22 @@
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ukufinyeleleka"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Izinqamuleli zekhibhodi"</string>
<string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Hlela izinqamuleli zekhibhodi ngendlela oyifisayo"</string>
- <!-- no translation found for shortcut_helper_customize_mode_sub_title (2479732335876820286) -->
- <skip />
+ <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Cindezela ukhiye ukuze unikeze isinqamuleli"</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sesha izinqamuleli"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ayikho imiphumela yosesho"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string>
- <!-- no translation found for shortcut_helper_content_description_meta_key (3989315044342124818) -->
- <skip />
- <!-- no translation found for shortcut_helper_content_description_plus_icon (6152683734278299020) -->
- <skip />
+ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Isithonjana sesenzo noma seMeta"</string>
+ <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Isithonjana sesengezo"</string>
<string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Enza ngendlela oyifisayo"</string>
<string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Kwenziwe"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Nweba isithonjana"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"noma"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Hudula isibambi"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Amasethingi Ekhibhodi"</string>
- <!-- no translation found for shortcut_helper_customize_dialog_set_shortcut_button_label (4754492225010429382) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_cancel_button_label (5595546460431741178) -->
- <skip />
- <!-- no translation found for shortcut_helper_add_shortcut_dialog_placeholder (9154297849458741995) -->
- <skip />
- <!-- no translation found for shortcut_helper_customize_dialog_error_message (5954264095841845768) -->
- <skip />
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Setha isinqamuleli"</string>
+ <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Khansela"</string>
+ <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Cindezela ukhiye"</string>
+ <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Inhlanganisela yokhiye isiyasetshenziswa kakade. Zama omunye ukhiye."</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Funa usebenzisa ikhibhodi yakho"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Funda izinqamuleli zamakhibhodi"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Funa usebenzisa iphedi yokuthinta"</string>
diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
index 1a7ce57601e3..be5c6d89b03c 100644
--- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
@@ -191,7 +191,9 @@
<item msgid="3079622119444911877">"Kuvaliwe"</item>
<item msgid="3028994095749238254">"Kuvuliwe"</item>
</string-array>
- <!-- no translation found for tile_states_notes:0 (5894333929299989301) -->
- <!-- no translation found for tile_states_notes:1 (6419996398343291862) -->
- <!-- no translation found for tile_states_notes:2 (5908720590832378783) -->
+ <string-array name="tile_states_notes">
+ <item msgid="5894333929299989301">"Ayitholakali"</item>
+ <item msgid="6419996398343291862">"Valiwe"</item>
+ <item msgid="5908720590832378783">"Vuliwe"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 48af82ad7943..42e909244f84 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -506,6 +506,12 @@
icon will be shown. -->
<string name="config_screenshotFilesApp" translatable="false"></string>
+ <!-- Recommends a UI mode for the default note-taking app when launched with
+ android.content.Intent#ACTION_CREATE_NOTE
+ 0: No UI recommendation. The note app should use its default mode
+ 1: Recommend a UI optimized for stylus input. -->
+ <integer name="config_preferredNotesMode">1</integer>
+
<!-- The component name of the screenshot editing activity that provides the App Clips flow.
The App Clips flow includes taking a screenshot, showing user screenshot cropping activity
and finally letting user send the screenshot to the calling notes app. This activity
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 67eb5b0fdf6b..411f36b73802 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -368,6 +368,9 @@
<!-- The vertical space between items in the alert selections in the inline settings -->
<dimen name="notification_guts_option_vertical_padding">16dp</dimen>
+ <!-- Extra space for guts bundle feedback button -->
+ <dimen name="notification_guts_bundle_feedback_size">48dp</dimen>
+
<dimen name="notification_importance_toggle_size">48dp</dimen>
<dimen name="notification_importance_button_separation">8dp</dimen>
<dimen name="notification_importance_drawable_padding">8dp</dimen>
@@ -788,6 +791,18 @@
<!-- Size of an avatar shown on one-line (children of a group) conversation notifications -->
<dimen name="conversation_single_line_avatar_size">24dp</dimen>
+ <!-- Size of the face pile shown on one-line (children of a group) conversation notifications
+ (2025 redesign version) -->
+ <dimen name="notification_2025_single_line_face_pile_size">16dp</dimen>
+
+ <!-- Size of the avatars within a face pile shown on one-line (children of a group) conversation
+ notifications (2025 redesign version) -->
+ <dimen name="notification_2025_single_line_face_pile_avatar_size">11dp</dimen>
+
+ <!-- Size of an avatar shown on one-line (children of a group) conversation notifications
+ (2025 redesign version) -->
+ <dimen name="notification_2025_single_line_avatar_size">16dp</dimen>
+
<!-- Border width for avatars in the face pile shown on one-line (children of a group) conversation notifications -->
<dimen name="conversation_single_line_face_pile_protection_width">1dp</dimen>
@@ -936,7 +951,6 @@
<dimen name="keyguard_translate_distance_on_swipe_up">-200dp</dimen>
<dimen name="keyguard_indication_margin_bottom">32dp</dimen>
- <dimen name="lock_icon_margin_bottom">74dp</dimen>
<dimen name="ambient_indication_margin_bottom">71dp</dimen>
@@ -1749,6 +1763,7 @@
<dimen name="ongoing_activity_chip_icon_text_padding">4dp</dimen>
<!-- The end padding for the timer text view. Only used if an embedded padding icon is used. -->
<dimen name="ongoing_activity_chip_text_end_padding_for_embedded_padding_icon">6dp</dimen>
+ <dimen name="ongoing_activity_chip_text_fading_edge_length">12dp</dimen>
<dimen name="ongoing_activity_chip_corner_radius">28dp</dimen>
<!-- Status bar user chip -->
@@ -1805,10 +1820,9 @@
<!-- Hearing devices dialog related dimensions -->
<dimen name="hearing_devices_layout_margin">12dp</dimen>
- <dimen name="hearing_devices_preset_spinner_height">72dp</dimen>
- <dimen name="hearing_devices_preset_spinner_text_padding_start">20dp</dimen>
- <dimen name="hearing_devices_preset_spinner_text_padding_vertical">15dp</dimen>
- <dimen name="hearing_devices_preset_spinner_arrow_size">24dp</dimen>
+ <dimen name="hearing_devices_small_title_padding_horizontal">16dp</dimen>
+ <dimen name="hearing_devices_preset_spinner_padding">22dp</dimen>
+ <dimen name="hearing_devices_preset_spinner_icon_size">24dp</dimen>
<dimen name="hearing_devices_preset_spinner_background_radius">28dp</dimen>
<dimen name="hearing_devices_tool_icon_size">28dp</dimen>
@@ -1956,8 +1970,6 @@
<dimen name="dream_overlay_entry_y_offset">40dp</dimen>
<dimen name="dream_overlay_exit_y_offset">40dp</dimen>
- <dimen name="status_view_margin_horizontal">0dp</dimen>
-
<!-- Media output broadcast dialog QR code picture size -->
<dimen name="media_output_qrcode_size">216dp</dimen>
<dimen name="media_output_broadcast_info">21dp</dimen>
@@ -2047,6 +2059,9 @@
<!-- UDFPS view attributes -->
<!-- UDFPS icon size in microns/um -->
<dimen name="udfps_icon_size" format="float">6000</dimen>
+ <!-- Limits the updates to at most one update per debounce duration to avoid too many
+ updates due to quick changes to padding. -->
+ <integer name="udfps_padding_debounce_duration">100</integer>
<!-- Microns/ums (1000 um = 1mm) per pixel for the given device. If unspecified, UI that
relies on this value will not be sized correctly. -->
<item name="pixel_pitch" format="float" type="dimen">-1</item>
@@ -2061,26 +2076,29 @@
<dimen name="contextual_edu_dialog_elevation">2dp</dimen>
<!-- Volume start -->
- <dimen name="volume_dialog_background_corner_radius">30dp</dimen>
<dimen name="volume_dialog_width">60dp</dimen>
- <dimen name="volume_dialog_vertical_padding">10dp</dimen>
+
+ <dimen name="volume_dialog_background_corner_radius">30dp</dimen>
+ <dimen name="volume_dialog_background_vertical_margin">-10dp</dimen>
+
<dimen name="volume_dialog_components_spacing">8dp</dimen>
<dimen name="volume_dialog_floating_sliders_spacing">8dp</dimen>
<dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen>
+ <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">-10dp</dimen>
<dimen name="volume_dialog_floating_sliders_horizontal_padding">4dp</dimen>
- <dimen name="volume_dialog_spacing">4dp</dimen>
<dimen name="volume_dialog_button_size">48dp</dimen>
- <dimen name="volume_dialog_floating_sliders_bottom_padding">48dp</dimen>
<dimen name="volume_dialog_slider_width">52dp</dimen>
<dimen name="volume_dialog_slider_height">254dp</dimen>
- <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>
- <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen>
+ <fraction name="volume_dialog_half_opened_bias">0.2</fraction>
+
+ <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
- <dimen name="volume_dialog_ringer_horizontal_padding">10dp</dimen>
<dimen name="volume_dialog_ringer_drawer_button_size">40dp</dimen>
<dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen>
- <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
<dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen>
+
+ <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>
+ <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen>
<!-- Volume end -->
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 53ab686ff0d7..713aa47970ee 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1002,6 +1002,10 @@
<string name="hearing_devices_presets_error">Couldn\'t update preset</string>
<!-- QuickSettings: Title for hearing aids presets. Preset is a set of hearing aid settings. User can apply different settings in different environments (e.g. Outdoor, Restaurant, Home) [CHAR LIMIT=40]-->
<string name="hearing_devices_preset_label">Preset</string>
+ <!-- QuickSettings: Content description for the icon that indicates the item is selected [CHAR LIMIT=NONE]-->
+ <string name="hearing_devices_spinner_item_selected">Selected</string>
+ <!-- QuickSettings: Title for related tools of hearing. [CHAR LIMIT=40]-->
+ <string name="hearing_devices_tools_label">Tools</string>
<!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40] [BACKUP_MESSAGE_ID=8916875614623730005]-->
<string name="quick_settings_hearing_devices_live_caption_title">Live Caption</string>
@@ -1332,6 +1336,10 @@
<string name="communal_widgets_disclaimer_text">To open an app using a widget, you\u2019ll need to verify it\u2019s you. Also, keep in mind that anyone can view them, even when your tablet\u2019s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here.</string>
<!-- Button for user to verify they understand the information presented. [CHAR LIMIT=50] -->
<string name="communal_widgets_disclaimer_button">Got it</string>
+ <!-- Lockscreen affordance to open glanceable hub. [CHAR LIMIT=20] -->
+ <string name="glanceable_hub_lockscreen_affordance_label">Widgets</string>
+ <!-- Text explaining that the glanceable hub affordance is disabled. [CHAR LIMIT=NONE] -->
+ <string name="glanceable_hub_lockscreen_affordance_disabled_text">To add Widgets on the lock screen as a shortcut, make sure it is enabled in settings.</string>
<!-- Related to user switcher --><skip/>
@@ -2030,6 +2038,9 @@
<!-- Text shown in notification guts for conversation notifications that don't implement the full feature -->
<string name="no_shortcut"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> doesn\u2019t support conversation features</string>
+ <!-- [CHAR LIMIT=80] Text shown in feedback button in notification guts for a bundled notification -->
+ <string name="notification_guts_bundle_feedback">Provide Bundle Feedback</string>
+
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
@@ -3210,6 +3221,9 @@
<!-- Text to display when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_copy_toast">Build number copied to clipboard.</string>
+ <!-- Text for accessibility action for copying content to clipboard [CHAR LIMIT=NONE]-->
+ <string name="copy_to_clipboard_a11y_action">copy to clipboard.</string>
+
<!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
<string name="basic_status">Open conversation</string>
<!--Title text for Conversation widget set up screen [CHAR LIMIT=180] -->
@@ -3564,6 +3578,8 @@
<string name="rear_display_accessibility_folded_animation">Foldable device being unfolded</string>
<!-- Text for education page content description for unfolded animation. [CHAR_LIMIT=NONE] -->
<string name="rear_display_accessibility_unfolded_animation">Foldable device being flipped around</string>
+ <!-- Text for a dialog telling the user that the front screen is turned on. [CHAR_LIMIT=NONE] -->
+ <string name="rear_display_unfolded_front_screen_on">Front screen turned on</string>
<!-- QuickSettings: Additional label for the auto-rotation quicksettings tile indicating that the setting corresponds to the folded posture for a foldable device [CHAR LIMIT=32] -->
<string name="quick_settings_rotation_posture_folded">folded</string>
@@ -3744,11 +3760,20 @@
is a component that shows the user which keyboard shortcuts they can use.
[CHAR LIMIT=NONE] -->
<string name="shortcut_helper_customize_mode_title">Customize keyboard shortcuts</string>
+ <!-- Title at the top of the keyboard shortcut helper remove shortcut dialog.
+ The helper is a component that shows the user which keyboard shortcuts they can use. Also
+ allows the user to add/remove custom shortcuts.[CHAR LIMIT=NONE] -->
+ <string name="shortcut_customize_mode_remove_shortcut_dialog_title">Remove shortcut?</string>
<!-- Sub title at the top of the keyboard shortcut helper customization dialog. Explains to the
user what action they need to take in the customization dialog to assign a new custom shortcut.
- The helper is a component that shows the user which keyboard shortcuts they can use.
+ The shortcut customize dialog allows users to add/remove custom shortcuts
+ [CHAR LIMIT=NONE] -->
+ <string name="shortcut_customize_mode_add_shortcut_description">Press key to assign shortcut</string>
+ <!-- Sub title at the top of the remove custom shortcut dialog. Explains to the user what action
+ they're about to take when they click remove shortcut. The shortcut customize dialog allows
+ users to add/remove custom shortcuts
[CHAR LIMIT=NONE] -->
- <string name="shortcut_helper_customize_mode_sub_title">Press key to assign shortcut</string>
+ <string name="shortcut_customize_mode_remove_shortcut_description">This will delete your custom shortcut permanently.</string>
<!-- Placeholder text shown in the search box of the keyboard shortcut helper, when the user
hasn't typed in anything in the search box yet. The helper is a component that shows the
user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
@@ -3804,6 +3829,10 @@
confirm and assign key combination to selected shortcut. The helper is a component that
shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
<string name="shortcut_helper_customize_dialog_set_shortcut_button_label">Set shortcut</string>
+ <!-- Label on the remove shortcut button in keyboard shortcut helper customize dialog, that allows user to
+ confirm and remove previously added custom shortcut. The helper is a component that
+ shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
+ <string name="shortcut_helper_customize_dialog_remove_button_label">Remove</string>
<!-- Label on the cancel button in keyboard shortcut helper customize dialog, that allows user to
cancel and exit shortcut customization dialog, returning to the main shortcut helper page.
The helper is a component that shows the user which keyboard shortcuts they can use.
@@ -3817,8 +3846,16 @@
<!-- Error message displayed when the user select a key combination that is already in use while
assigning a new custom key combination to a shortcut in shortcut helper. The helper is a
component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
- <string name="shortcut_helper_customize_dialog_error_message">Key combination already in use. Try another key.</string>
-
+ <string name="shortcut_customizer_key_combination_in_use_error_message">Key combination already in use. Try another key.</string>
+ <!-- Generic error message displayed when the user selected key combination cannot be used as
+ custom keyboard shortcut in shortcut helper. The helper is a component that shows the user
+ which keyboard shortcuts they can use and allows users to customize their keyboard
+ shortcuts. [CHAR LIMIT=NONE] -->
+ <string name="shortcut_customizer_generic_error_message">Shortcut cannot be set.</string>
+ <!-- Plus sign, used in keyboard shortcut helper to combine keys for shortcut. E.g. Ctrl + A
+ The helper is a component that shows the user which keyboard shortcuts they can use.
+ [CHAR LIMIT=NONE] -->
+ <string name="shortcut_helper_plus_symbol">+</string>
<!-- Keyboard touchpad tutorial scheduler-->
<!-- Notification title for launching keyboard tutorial [CHAR_LIMIT=100] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c69b98c8c37f..0381811e29ed 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -831,6 +831,11 @@
<item name="android:textColor">?attr/onSurfaceVariant</item>
</style>
+ <style name="TextAppearance.QSEditTitle" >
+ <item name="android:fontFamily">"gsf-title-medium-emphasized"</item>
+ <item name="android:textColor">?attr/onSurfaceVariant</item>
+ </style>
+
<style name="QSCustomizeToolbar" parent="@*android:style/Widget.DeviceDefault.Toolbar">
<item name="android:textColor">?attr/onSurface</item>
<item name="android:elevation">10dp</item>
@@ -1481,28 +1486,14 @@
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
- <style name="BluetoothTileDialog.Device.Active">
- <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
- </style>
-
- <style name="BluetoothTileDialog.DeviceName">
- <item name="android:textSize">14sp</item>
- <item name="android:textAppearance">@style/TextAppearance.Dialog.Title</item>
+ <style name="TextAppearance.BluetoothTileDialog">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:textAlignment">gravity</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
- <style name="BluetoothTileDialog.DeviceSummary">
- <item name="android:ellipsize">end</item>
- <item name="android:maxLines">2</item>
- <item name="android:textAppearance">@style/TextAppearance.Dialog.Body.Message</item>
- <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
- </style>
-
- <style name="BluetoothTileDialog.DeviceName.Active">
- <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
- </style>
-
- <style name="BluetoothTileDialog.DeviceSummary.Active">
+ <style name="TextAppearance.BluetoothTileDialog.Active">
<item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
</style>
diff --git a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml
new file mode 100644
index 000000000000..9018e5b7ed92
--- /dev/null
+++ b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/volume_dialog_constraint_set">
+
+ <Constraint
+ android:id="@id/volume_dialog_main_slider_container"
+ android:layout_width="@dimen/volume_dialog_slider_width"
+ android:layout_height="@dimen/volume_dialog_slider_height"
+ android:layout_marginEnd="@dimen/volume_dialog_components_spacing"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="0.5" />
+</ConstraintSet> \ No newline at end of file
diff --git a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml
new file mode 100644
index 000000000000..297c38873164
--- /dev/null
+++ b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/volume_dialog_half_folded_constraint_set">
+
+ <Constraint
+ android:id="@id/volume_dialog_main_slider_container"
+ android:layout_width="@dimen/volume_dialog_slider_width"
+ android:layout_height="@dimen/volume_dialog_slider_height"
+ android:layout_marginEnd="@dimen/volume_dialog_components_spacing"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="@fraction/volume_dialog_half_opened_bias" />
+</ConstraintSet> \ No newline at end of file
diff --git a/packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml b/packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml
new file mode 100644
index 000000000000..877637e0b0d8
--- /dev/null
+++ b/packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <Transition
+ android:id="@+id/transition"
+ app:constraintSetEnd="@+id/volume_dialog_ringer_drawer_open"
+ app:constraintSetStart="@+id/volume_dialog_ringer_drawer_close"
+ app:transitionEasing="path(0.05f, 0.7f, 0.1f, 1f)"
+ app:duration="400">
+ </Transition>
+
+ <ConstraintSet android:id="@+id/volume_dialog_ringer_drawer_close">
+ <Constraint
+ android:id="@+id/volume_ringer_drawer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+ </ConstraintSet>
+
+ <ConstraintSet android:id="@+id/volume_dialog_ringer_drawer_open">
+ <Constraint
+ android:id="@+id/volume_ringer_drawer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+ </ConstraintSet>
+
+</MotionScene> \ No newline at end of file
diff --git a/packages/SystemUI/res/xml/volume_dialog_scene.xml b/packages/SystemUI/res/xml/volume_dialog_scene.xml
new file mode 100644
index 000000000000..b813474490bb
--- /dev/null
+++ b/packages/SystemUI/res/xml/volume_dialog_scene.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto">
+
+ <Transition
+ motion:autoTransition="none"
+ motion:constraintSetEnd="@id/volume_dialog_half_folded_constraint_set"
+ motion:constraintSetStart="@id/volume_dialog_constraint_set"
+ motion:duration="150" />
+
+ <Include motion:constraintSet="@xml/volume_dialog_constraint_set" />
+ <Include motion:constraintSet="@xml/volume_dialog_half_folded_constraint_set" />
+</MotionScene> \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 76af813fe2f8..7d220b505aa0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -18,9 +18,11 @@ package com.android.systemui.shared.system;
import android.os.RemoteException;
import android.util.Log;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TaskSnapshot;
+import android.window.WindowAnimationState;
import com.android.internal.os.IResultReceiver;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -107,6 +109,17 @@ public class RecentsAnimationControllerCompat {
}
/**
+ * @see IRecentsAnimationController#handOffAnimation
+ */
+ public void handOffAnimation(RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
+ try {
+ mAnimationController.handOffAnimation(targets, states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to hand off animation", e);
+ }
+ }
+
+ /**
* @see IRecentsAnimationController#detachNavigationBarFromApp
*/
public void detachNavigationBarFromApp(boolean moveHomeToTop) {
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 8ed675c61edf..6ef7de4a32b5 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -16,7 +16,10 @@
package com.android.keyguard;
+import static com.android.systemui.Flags.gsfBouncer;
+
import android.content.Context;
+import android.graphics.Typeface;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -122,6 +125,9 @@ public class EmergencyButton extends Button {
textId = com.android.internal.R.string.lockscreen_emergency_call;
}
setText(textId);
+ if (gsfBouncer()) {
+ setTypeface(Typeface.create("gsf-title-medium", Typeface.NORMAL));
+ }
} else {
setVisibility(View.GONE);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 95830b5f4ed7..add459b84ac1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -44,7 +44,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.views.NavigationBarView;
import com.android.systemui.settings.DisplayTracker;
-import com.android.systemui.shade.data.repository.ShadePositionRepository;
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository;
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -66,7 +66,7 @@ public class KeyguardDisplayManager {
private final DisplayManager mDisplayService;
private final DisplayTracker mDisplayTracker;
private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
- private final Provider<ShadePositionRepository> mShadePositionRepositoryProvider;
+ private final Provider<ShadeDisplaysRepository> mShadePositionRepositoryProvider;
private final ConnectedDisplayKeyguardPresentation.Factory
mConnectedDisplayKeyguardPresentationFactory;
private final Context mContext;
@@ -112,7 +112,7 @@ public class KeyguardDisplayManager {
KeyguardStateController keyguardStateController,
ConnectedDisplayKeyguardPresentation.Factory
connectedDisplayKeyguardPresentationFactory,
- Provider<ShadePositionRepository> shadePositionRepositoryProvider,
+ Provider<ShadeDisplaysRepository> shadePositionRepositoryProvider,
@Application CoroutineScope appScope) {
mContext = context;
mNavigationBarControllerLazy = navigationBarControllerLazy;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 6bcacd023c74..fcaccd27a567 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,6 +32,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.START;
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
+import static com.android.systemui.Flags.gsfBouncer;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static java.lang.Integer.max;
@@ -51,6 +52,7 @@ import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -1335,6 +1337,9 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
true);
mUserSwitcherViewGroup = mView.findViewById(R.id.keyguard_bouncer_user_switcher);
mUserSwitcher = mView.findViewById(R.id.user_switcher_header);
+ if (gsfBouncer()) {
+ mUserSwitcher.setTypeface(Typeface.create("gsf-label-medium", Typeface.NORMAL));
+ }
}
interface UserSwitcherCallback {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 7fe4ec852045..ebde8a3057ce 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -15,11 +15,13 @@
*/
package com.android.keyguard;
+import static com.android.systemui.Flags.gsfBouncer;
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.PowerManager;
@@ -158,6 +160,9 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
int klondikeColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
.getDefaultColor();
mDigitText.setTextColor(textColor);
+ if (gsfBouncer()) {
+ mDigitText.setTypeface(Typeface.create("gsf-label-large-emphasized", Typeface.NORMAL));
+ }
mKlondikeText.setTextColor(klondikeColor);
if (mAnimator != null) mAnimator.reloadColors(getContext());
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index e91bb6aefeec..4723ab958f86 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -305,7 +305,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
}
if (mMagnificationMode != mode) {
mMagnificationMode = mode;
- mImageView.setImageResource(getIconResId(mMagnificationMode));
+ mImageView.setImageResource(getIconResId());
}
if (!mIsVisible) {
onConfigurationChanged(mContext.getResources().getConfiguration());
@@ -455,7 +455,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
}
@VisibleForTesting
- static int getIconResId(int mode) { // TODO(b/242233514): delete non used param
+ static int getIconResId() {
return R.drawable.ic_open_in_new_window;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt b/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt
index 60d80efe6426..3f717e282a61 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.accessibility.extradim
+import android.os.Handler
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.animation.Expandable
@@ -32,18 +33,21 @@ constructor(
private val extraDimDialogDelegateProvider: Provider<ExtraDimDialogDelegate>,
private val mActivityStarter: ActivityStarter,
private val dialogTransitionAnimator: DialogTransitionAnimator,
+ private val mainHandler: Handler,
) {
private var dialog: SystemUIDialog? = null
@JvmOverloads
fun dismissKeyguardIfNeededAndShowDialog(expandable: Expandable? = null) {
- mActivityStarter.executeRunnableDismissingKeyguard(
- { showRemoveExtraDimShortcutsDialog(expandable) },
- /* cancelAction= */ null,
- /* dismissShade= */ false,
- /* afterKeyguardGone= */ true,
- /* deferred= */ false,
- )
+ mainHandler.post {
+ mActivityStarter.executeRunnableDismissingKeyguard(
+ { showRemoveExtraDimShortcutsDialog(expandable) },
+ /* cancelAction= */ null,
+ /* dismissShade= */ true,
+ /* afterKeyguardGone= */ true,
+ /* deferred= */ false,
+ )
+ }
}
/** Show the dialog for removing all Extra Dim shortcuts. */
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 1978bb89b5b2..1f21af80cebb 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -35,10 +35,9 @@ import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.Visibility;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -114,10 +113,9 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
private SystemUIDialog mDialog;
private RecyclerView mDeviceList;
private List<DeviceItem> mHearingDeviceItemList;
+ private View mPresetLayout;
private Spinner mPresetSpinner;
- private ArrayAdapter<String> mPresetInfoAdapter;
- private Button mPairButton;
- private LinearLayout mRelatedToolsContainer;
+ private HearingDevicesSpinnerAdapter mPresetInfoAdapter;
private final HearingDevicesPresetsController.PresetCallback mPresetCallback =
new HearingDevicesPresetsController.PresetCallback() {
@Override
@@ -245,7 +243,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
mPresetsController.getAllPresetInfo();
final int activePresetIndex = mPresetsController.getActivePresetIndex();
refreshPresetInfoAdapter(presetInfos, activePresetIndex);
- mPresetSpinner.setVisibility(
+ mPresetLayout.setVisibility(
(activeHearingDevice != null && activeHearingDevice.isConnectedHapClientDevice()
&& !mPresetInfoAdapter.isEmpty()) ? VISIBLE : GONE);
});
@@ -291,14 +289,13 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
}
mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DIALOG_SHOW, mLaunchSourceId);
- mPairButton = dialog.requireViewById(R.id.pair_new_device_button);
mDeviceList = dialog.requireViewById(R.id.device_list);
+ mPresetLayout = dialog.requireViewById(R.id.preset_layout);
mPresetSpinner = dialog.requireViewById(R.id.preset_spinner);
- mRelatedToolsContainer = dialog.requireViewById(R.id.related_tools_container);
setupDeviceListView(dialog);
setupPresetSpinner(dialog);
- setupPairNewDeviceButton(dialog, mShowPairNewDevice ? VISIBLE : GONE);
+ setupPairNewDeviceButton(dialog);
if (com.android.systemui.Flags.hearingDevicesDialogRelatedTools()) {
setupRelatedToolsView(dialog);
}
@@ -353,11 +350,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
mHearingDeviceItemList);
mPresetsController.setHearingDeviceIfSupportHap(activeHearingDevice);
- mPresetInfoAdapter = new ArrayAdapter<>(dialog.getContext(),
- R.layout.hearing_devices_preset_spinner_selected,
- R.id.hearing_devices_preset_option_text);
- mPresetInfoAdapter.setDropDownViewResource(
- R.layout.hearing_devices_preset_dropdown_item);
+ mPresetInfoAdapter = new HearingDevicesSpinnerAdapter(dialog.getContext());
mPresetSpinner.setAdapter(mPresetInfoAdapter);
// disable redundant Touch & Hold accessibility action for Switch Access
@@ -378,6 +371,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
mPresetSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ mPresetInfoAdapter.setSelected(position);
mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PRESET_SELECT,
mLaunchSourceId);
mPresetsController.selectPreset(
@@ -389,14 +383,17 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
// Do nothing
}
});
- mPresetSpinner.setVisibility(
+ mPresetLayout.setVisibility(
(activeHearingDevice != null && activeHearingDevice.isConnectedHapClientDevice()
&& !mPresetInfoAdapter.isEmpty()) ? VISIBLE : GONE);
}
- private void setupPairNewDeviceButton(SystemUIDialog dialog, @Visibility int visibility) {
- if (visibility == VISIBLE) {
- mPairButton.setOnClickListener(v -> {
+ private void setupPairNewDeviceButton(SystemUIDialog dialog) {
+ final Button pairButton = dialog.requireViewById(R.id.pair_new_device_button);
+
+ pairButton.setVisibility(mShowPairNewDevice ? VISIBLE : GONE);
+ if (mShowPairNewDevice) {
+ pairButton.setOnClickListener(v -> {
mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR, mLaunchSourceId);
dismissDialogIfExists();
final Intent intent = new Intent(Settings.ACTION_HEARING_DEVICE_PAIRING_SETTINGS);
@@ -404,12 +401,11 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
mDialogTransitionAnimator.createActivityTransitionController(dialog));
});
- } else {
- mPairButton.setVisibility(GONE);
}
}
private void setupRelatedToolsView(SystemUIDialog dialog) {
+
final Context context = dialog.getContext();
final List<ToolItem> toolItemList = new ArrayList<>();
final String[] toolNameArray;
@@ -430,15 +426,20 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
} catch (Resources.NotFoundException e) {
Log.i(TAG, "No hearing devices related tool config resource");
}
+
+ final View toolsLayout = dialog.requireViewById(R.id.tools_layout);
+ toolsLayout.setVisibility(toolItemList.isEmpty() ? GONE : VISIBLE);
+
+ final LinearLayout toolsContainer = dialog.requireViewById(R.id.tools_container);
for (int i = 0; i < toolItemList.size(); i++) {
- View view = createHearingToolView(context, toolItemList.get(i));
- mRelatedToolsContainer.addView(view);
+ View view = createHearingToolView(context, toolItemList.get(i), toolsContainer);
+ toolsContainer.addView(view);
if (i != toolItemList.size() - 1) {
final int spaceSize = context.getResources().getDimensionPixelSize(
R.dimen.hearing_devices_layout_margin);
Space space = new Space(context);
space.setLayoutParams(new LinearLayout.LayoutParams(spaceSize, 0));
- mRelatedToolsContainer.addView(space);
+ toolsContainer.addView(space);
}
}
}
@@ -453,6 +454,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
for (int position = 0; position < size; position++) {
if (presetInfos.get(position).getIndex() == activePresetIndex) {
mPresetSpinner.setSelection(position, /* animate= */ false);
+ mPresetInfoAdapter.setSelected(position);
}
}
}
@@ -493,9 +495,9 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
}
@NonNull
- private View createHearingToolView(Context context, ToolItem item) {
- View view = LayoutInflater.from(context).inflate(R.layout.hearing_tool_item,
- mRelatedToolsContainer, false);
+ private View createHearingToolView(Context context, ToolItem item, ViewGroup container) {
+ View view = LayoutInflater.from(context).inflate(R.layout.hearing_tool_item, container,
+ false);
ImageView icon = view.requireViewById(R.id.tool_icon);
TextView text = view.requireViewById(R.id.tool_name);
view.setContentDescription(item.getToolName());
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java
index 9367cb5c0198..e47e4b27d58a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java
@@ -138,19 +138,18 @@ public class HearingDevicesListAdapter extends RecyclerView.Adapter<RecyclerView
Pair<Drawable, String> iconPair = item.getIconWithDescription();
if (iconPair != null) {
- Drawable drawable = iconPair.getFirst().mutate();
- drawable.setTint(tintColor);
+ Drawable drawable = iconPair.getFirst();
mIconView.setImageDrawable(drawable);
mIconView.setContentDescription(iconPair.getSecond());
}
mNameView.setTextAppearance(
- item.isActive() ? R.style.BluetoothTileDialog_DeviceName_Active
- : R.style.BluetoothTileDialog_DeviceName);
+ item.isActive() ? R.style.TextAppearance_BluetoothTileDialog_Active
+ : R.style.TextAppearance_BluetoothTileDialog);
mNameView.setText(item.getDeviceName());
mSummaryView.setTextAppearance(
- item.isActive() ? R.style.BluetoothTileDialog_DeviceSummary_Active
- : R.style.BluetoothTileDialog_DeviceSummary);
+ item.isActive() ? R.style.TextAppearance_BluetoothTileDialog_Active
+ : R.style.TextAppearance_BluetoothTileDialog);
mSummaryView.setText(item.getConnectionSummary());
mGearIcon.getDrawable().mutate().setTint(tintColor);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java
new file mode 100644
index 000000000000..28d742cfa49b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 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.hearingaid;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.res.R;
+
+/**
+ * An ArrayAdapter which was used by Spinner in hearing devices dialog.
+ */
+public class HearingDevicesSpinnerAdapter extends ArrayAdapter<String> {
+
+ private final Context mContext;
+ private int mSelectedPosition;
+
+ public HearingDevicesSpinnerAdapter(@NonNull Context context) {
+ super(context, R.layout.hearing_devices_spinner_view,
+ R.id.hearing_devices_spinner_text);
+ setDropDownViewResource(R.layout.hearing_devices_spinner_dropdown_view);
+ mContext = context;
+ }
+
+ @Override
+ public View getDropDownView(int position, @Nullable View convertView,
+ @NonNull ViewGroup parent) {
+
+ View view = super.getDropDownView(position, convertView, parent);
+
+ final boolean isSelected = position == mSelectedPosition;
+ view.setBackgroundResource(isSelected
+ ? R.drawable.hearing_devices_spinner_selected_background
+ : R.drawable.bluetooth_tile_dialog_bg_off);
+
+ View checkIcon = view.findViewById(R.id.hearing_devices_spinner_check_icon);
+ if (checkIcon != null) {
+ checkIcon.setVisibility(isSelected ? VISIBLE : GONE);
+ }
+
+ TextView text = view.findViewById(R.id.hearing_devices_spinner_text);
+ if (text != null) {
+ int tintColor = Utils.getColorAttr(mContext,
+ isSelected ? com.android.internal.R.attr.materialColorOnPrimaryContainer
+ : com.android.internal.R.attr.materialColorOnSurface).getDefaultColor();
+ text.setTextColor(tintColor);
+ }
+ return view;
+ }
+
+ /**
+ * Sets the selected position into this adapter. The selected item will have different UI in
+ * the dropdown view.
+ *
+ * @param position the selected position
+ */
+ public void setSelected(int position) {
+ mSelectedPosition = position;
+ notifyDataSetChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
index fb00d6e16dcc..db4d613a9101 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
@@ -52,6 +52,8 @@ import com.android.systemui.util.display.DisplayHelper;
import com.google.common.util.concurrent.ListenableFuture;
+import kotlin.Unit;
+
import kotlinx.coroutines.Job;
import java.util.Collection;
@@ -87,7 +89,7 @@ public class TouchMonitor {
private final ConfigurationInteractor mConfigurationInteractor;
private final Lifecycle mLifecycle;
- private Rect mExclusionRect = null;
+ private Rect mExclusionRect = new Rect();
private ISystemGestureExclusionListener mGestureExclusionListener;
@@ -298,9 +300,18 @@ public class TouchMonitor {
public void onSystemGestureExclusionChanged(int displayId,
Region systemGestureExclusion,
Region systemGestureExclusionUnrestricted) {
- mExclusionRect = systemGestureExclusion.getBounds();
+ final Rect bounds = systemGestureExclusion.getBounds();
+ if (!mExclusionRect.equals(bounds)) {
+ mExclusionRect = bounds;
+ mLogger.i(msg -> "Exclusion rect updated to " + msg.getStr1(),
+ msg -> {
+ msg.setStr1(bounds.toString());
+ return Unit.INSTANCE;
+ });
+ }
}
};
+ mLogger.i("Registering system gesture exclusion listener");
mWindowManagerService.registerSystemGestureExclusionListener(
mGestureExclusionListener, mDisplayId);
} catch (RemoteException e) {
@@ -320,11 +331,12 @@ public class TouchMonitor {
* Destroys any active {@link InputSession}.
*/
private void stopMonitoring(boolean force) {
- mExclusionRect = null;
+ mExclusionRect = new Rect();
if (bouncerAreaExclusion()) {
mBackgroundExecutor.execute(() -> {
try {
if (mGestureExclusionListener != null) {
+ mLogger.i("Unregistering system gesture exclusion listener");
mWindowManagerService.unregisterSystemGestureExclusionListener(
mGestureExclusionListener, mDisplayId);
mGestureExclusionListener = null;
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index e63472684585..1176cb0523c1 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -19,6 +19,7 @@ import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
import static com.android.settingslib.flags.Flags.newStatusBarIcons;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.Flags.gsfQuickSettings;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -33,6 +34,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.provider.Settings;
@@ -384,6 +386,9 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
}
float fontHeight = mBatteryPercentView.getPaint().getFontMetricsInt(null);
mBatteryPercentView.setLineHeight(TypedValue.COMPLEX_UNIT_PX, fontHeight);
+ if (gsfQuickSettings()) {
+ mBatteryPercentView.setTypeface(Typeface.create("gsf-label-large", Typeface.NORMAL));
+ }
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
addView(mBatteryPercentView, new LayoutParams(
LayoutParams.WRAP_CONTENT,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
index abbbd730c47e..976329580c60 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
@@ -36,8 +36,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlin.math.max
/** Encapsulates business logic for interacting with the UDFPS overlay. */
@SysUISingleton
@@ -124,8 +126,9 @@ constructor(
udfpsOverlayParams.map { params ->
val sensorWidth = params.nativeSensorBounds.right - params.nativeSensorBounds.left
val nativePadding = (sensorWidth - iconSize) / 2
- (nativePadding * params.scaleFactor).toInt()
- }
+ // padding can be negative when udfpsOverlayParams has not been initialized yet.
+ max(0, (nativePadding * params.scaleFactor).toInt())
+ }.distinctUntilChanged()
companion object {
private const val TAG = "UdfpsOverlayInteractor"
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
index a9c5c69ca26e..d7a0fc9770ee 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
@@ -100,7 +100,7 @@ internal constructor(
initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
cachedContentHeight: Int,
dialogCallback: BluetoothTileDialogCallback,
- dimissListener: Runnable
+ dimissListener: Runnable,
): BluetoothTileDialogDelegate
}
@@ -135,7 +135,7 @@ internal constructor(
object : AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
- info: AccessibilityNodeInfo
+ info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.addAction(
@@ -144,7 +144,7 @@ internal constructor(
context.getString(
R.string
.quick_settings_bluetooth_audio_sharing_button_accessibility
- )
+ ),
)
)
}
@@ -180,7 +180,7 @@ internal constructor(
dialog: SystemUIDialog,
deviceItem: List<DeviceItem>,
showSeeAll: Boolean,
- showPairNewDevice: Boolean
+ showPairNewDevice: Boolean,
) {
withContext(mainDispatcher) {
val start = systemClock.elapsedRealtime()
@@ -207,7 +207,7 @@ internal constructor(
internal fun onBluetoothStateUpdated(
dialog: SystemUIDialog,
isEnabled: Boolean,
- uiProperties: BluetoothTileDialogViewModel.UiProperties
+ uiProperties: BluetoothTileDialogViewModel.UiProperties,
) {
getToggleView(dialog).apply {
isChecked = isEnabled
@@ -221,7 +221,7 @@ internal constructor(
internal fun onBluetoothAutoOnUpdated(
dialog: SystemUIDialog,
isEnabled: Boolean,
- @StringRes infoResId: Int
+ @StringRes infoResId: Int,
) {
getAutoOnToggle(dialog).isChecked = isEnabled
getAutoOnToggleInfoTextView(dialog).text = dialog.context.getString(infoResId)
@@ -231,7 +231,7 @@ internal constructor(
dialog: SystemUIDialog,
visibility: Int,
label: String?,
- isActive: Boolean
+ isActive: Boolean,
) {
getAudioSharingButtonView(dialog).apply {
this.visibility = visibility
@@ -339,14 +339,14 @@ internal constructor(
object : DiffUtil.ItemCallback<DeviceItem>() {
override fun areItemsTheSame(
deviceItem1: DeviceItem,
- deviceItem2: DeviceItem
+ deviceItem2: DeviceItem,
): Boolean {
return deviceItem1.cachedBluetoothDevice == deviceItem2.cachedBluetoothDevice
}
override fun areContentsTheSame(
deviceItem1: DeviceItem,
- deviceItem2: DeviceItem
+ deviceItem2: DeviceItem,
): Boolean {
return deviceItem1.type == deviceItem2.type &&
deviceItem1.cachedBluetoothDevice == deviceItem2.cachedBluetoothDevice &&
@@ -394,7 +394,7 @@ internal constructor(
internal fun bind(
item: DeviceItem,
- deviceItemOnClickCallback: BluetoothTileDialogCallback
+ deviceItemOnClickCallback: BluetoothTileDialogCallback,
) {
container.apply {
isEnabled = item.isEnabled
@@ -409,14 +409,14 @@ internal constructor(
com.android.settingslib.Utils.getColorAttr(
context,
if (item.isActive) InternalR.attr.materialColorOnPrimaryContainer
- else InternalR.attr.materialColorOnSurface
+ else InternalR.attr.materialColorOnSurface,
)
.defaultColor
// update icons
iconView.apply {
item.iconWithDescription?.let {
- setImageDrawable(it.first.apply { mutate()?.setTint(tintColor) })
+ setImageDrawable(it.first)
contentDescription = it.second
}
}
@@ -427,25 +427,25 @@ internal constructor(
// update text styles
nameView.setTextAppearance(
- if (item.isActive) R.style.BluetoothTileDialog_DeviceName_Active
- else R.style.BluetoothTileDialog_DeviceName
+ if (item.isActive) R.style.TextAppearance_BluetoothTileDialog_Active
+ else R.style.TextAppearance_BluetoothTileDialog
)
summaryView.setTextAppearance(
- if (item.isActive) R.style.BluetoothTileDialog_DeviceSummary_Active
- else R.style.BluetoothTileDialog_DeviceSummary
+ if (item.isActive) R.style.TextAppearance_BluetoothTileDialog_Active
+ else R.style.TextAppearance_BluetoothTileDialog
)
accessibilityDelegate =
object : AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
- info: AccessibilityNodeInfo
+ info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.addAction(
AccessibilityAction(
AccessibilityAction.ACTION_CLICK.id,
- item.actionAccessibilityLabel
+ item.actionAccessibilityLabel,
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
index 292137377f55..92f05803f7cf 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
@@ -57,7 +57,6 @@ abstract class DeviceItemFactory {
companion object {
@JvmStatic
fun createDeviceItem(
- context: Context,
cachedDevice: CachedBluetoothDevice,
type: DeviceItemType,
connectionSummary: String,
@@ -71,9 +70,7 @@ abstract class DeviceItemFactory {
deviceName = cachedDevice.name,
connectionSummary = connectionSummary,
iconWithDescription =
- BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).let {
- Pair(it.first, it.second)
- },
+ cachedDevice.drawableWithDescription.let { Pair(it.first, it.second) },
background = background,
isEnabled = !cachedDevice.isBusy,
actionAccessibilityLabel = actionAccessibilityLabel,
@@ -96,7 +93,6 @@ internal open class ActiveMediaDeviceItemFactory : DeviceItemFactory() {
override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
return createDeviceItem(
- context,
cachedDevice,
DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE,
cachedDevice.connectionSummary ?: "",
@@ -122,7 +118,6 @@ internal class AudioSharingMediaDeviceItemFactory(
override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
return createDeviceItem(
- context,
cachedDevice,
DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
@@ -153,7 +148,6 @@ internal class AvailableAudioSharingMediaDeviceItemFactory(
override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
return createDeviceItem(
- context,
cachedDevice,
DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
context.getString(
@@ -191,7 +185,6 @@ open class AvailableMediaDeviceItemFactory : DeviceItemFactory() {
override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
return createDeviceItem(
- context,
cachedDevice,
DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
@@ -232,7 +225,6 @@ internal class ConnectedDeviceItemFactory : DeviceItemFactory() {
override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
return createDeviceItem(
- context,
cachedDevice,
DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
@@ -262,7 +254,6 @@ internal open class SavedDeviceItemFactory : DeviceItemFactory() {
override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
return createDeviceItem(
- context,
cachedDevice,
DeviceItemType.SAVED_BLUETOOTH_DEVICE,
cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
index 79a11ee88826..ad49fd03c577 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
@@ -17,11 +17,13 @@
package com.android.systemui.bouncer.ui
import android.content.Context
+import android.graphics.Typeface
import android.util.AttributeSet
import android.widget.LinearLayout
import com.android.keyguard.BouncerKeyguardMessageArea
import com.android.keyguard.KeyguardMessageArea
import com.android.keyguard.KeyguardMessageAreaController
+import com.android.systemui.Flags
import com.android.systemui.res.R
class BouncerMessageView : LinearLayout {
@@ -37,10 +39,20 @@ class BouncerMessageView : LinearLayout {
var secondaryMessageView: BouncerKeyguardMessageArea? = null
var primaryMessage: KeyguardMessageAreaController<KeyguardMessageArea>? = null
var secondaryMessage: KeyguardMessageAreaController<KeyguardMessageArea>? = null
+
override fun onFinishInflate() {
super.onFinishInflate()
primaryMessageView = findViewById(R.id.bouncer_primary_message_area)
secondaryMessageView = findViewById(R.id.bouncer_secondary_message_area)
+
+ if (Flags.gsfBouncer()) {
+ primaryMessageView?.apply {
+ typeface = Typeface.create("gsf-title-large-emphasized", Typeface.NORMAL)
+ }
+ secondaryMessageView?.apply {
+ typeface = Typeface.create("gsf-title-medium-emphasized", Typeface.NORMAL)
+ }
+ }
}
fun init(factory: KeyguardMessageAreaController.Factory) {
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index 917a4ff9036b..5bad9fc9c5d7 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -16,6 +16,7 @@
package com.android.systemui.brightness.ui.compose
+import android.view.MotionEvent
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
@@ -24,6 +25,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -31,7 +33,6 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
@@ -41,6 +42,7 @@ import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
@@ -61,6 +63,7 @@ import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.qs.ui.compose.borderOnFocus
import com.android.systemui.res.R
import com.android.systemui.utils.PolicyRestriction
@@ -102,11 +105,12 @@ private fun BrightnessSlider(
null
}
- val overriddenByAppState by if (Flags.showToastWhenAppControlBrightness()) {
- viewModel.brightnessOverriddenByWindow.collectAsStateWithLifecycle()
- } else {
- mutableStateOf(false)
- }
+ val overriddenByAppState =
+ if (Flags.showToastWhenAppControlBrightness()) {
+ viewModel.brightnessOverriddenByWindow.collectAsStateWithLifecycle().value
+ } else {
+ false
+ }
PlatformSlider(
value = animatedValue,
@@ -160,7 +164,7 @@ private fun BrightnessSlider(
if (interaction is DragInteraction.Start && overriddenByAppState) {
viewModel.showToast(
context,
- R.string.quick_settings_brightness_unable_adjust_msg
+ R.string.quick_settings_brightness_unable_adjust_msg,
)
}
}
@@ -213,9 +217,22 @@ fun BrightnessSliderContainer(
coroutineScope.launch { viewModel.onDrag(Drag.Stopped(GammaBrightness(it))) }
},
modifier =
- Modifier.then(if (viewModel.showMirror) Modifier.drawInOverlay() else Modifier)
+ Modifier.borderOnFocus(
+ color = MaterialTheme.colorScheme.secondary,
+ cornerSize = CornerSize(32.dp),
+ )
+ .then(if (viewModel.showMirror) Modifier.drawInOverlay() else Modifier)
.sliderBackground(containerColor)
- .fillMaxWidth(),
+ .fillMaxWidth()
+ .pointerInteropFilter {
+ if (
+ it.actionMasked == MotionEvent.ACTION_UP ||
+ it.actionMasked == MotionEvent.ACTION_CANCEL
+ ) {
+ viewModel.emitBrightnessTouchForFalsing()
+ }
+ false
+ },
formatter = viewModel::formatValue,
hapticsViewModelFactory = viewModel.hapticsViewModelFactory,
)
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
index 1630ee58449f..7df71550d43d 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
@@ -16,12 +16,14 @@
package com.android.systemui.brightness.ui.viewmodel
-import androidx.compose.runtime.getValue
import android.content.Context
import androidx.annotation.StringRes
+import androidx.compose.runtime.getValue
import com.android.systemui.brightness.domain.interactor.BrightnessPolicyEnforcementInteractor
import com.android.systemui.brightness.domain.interactor.ScreenBrightnessInteractor
import com.android.systemui.brightness.shared.model.GammaBrightness
+import com.android.systemui.classifier.Classifier
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
@@ -52,6 +54,7 @@ constructor(
private val brightnessPolicyEnforcementInteractor: BrightnessPolicyEnforcementInteractor,
val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
private val brightnessMirrorShowingInteractor: BrightnessMirrorShowingInteractor,
+ private val falsingInteractor: FalsingInteractor,
@Assisted private val supportsMirroring: Boolean,
private val brightnessWarningToast: BrightnessWarningToast,
) : ExclusiveActivatable() {
@@ -87,6 +90,10 @@ constructor(
brightnessWarningToast.show(viewContext, resId)
}
+ fun emitBrightnessTouchForFalsing() {
+ falsingInteractor.isFalseTouch(Classifier.BRIGHTNESS_SLIDER)
+ }
+
/**
* As a brightness slider is dragged, the corresponding events should be sent using this method.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
index 57e9ade30bb5..074b64e0fab0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
@@ -23,6 +23,7 @@ import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorActual
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.FalsingManager.Penalty
import javax.inject.Inject
/**
@@ -63,12 +64,13 @@ constructor(
* Inserts the given [result] into the falsing system, affecting future runs of the classifier
* as if this was a result that had organically happened before.
*/
- fun updateFalseConfidence(
- result: FalsingClassifier.Result,
- ) = collector.updateFalseConfidence(result)
+ fun updateFalseConfidence(result: FalsingClassifier.Result) =
+ collector.updateFalseConfidence(result)
/** Returns `true` if the gesture should be rejected. */
- fun isFalseTouch(
- @Classifier.InteractionType interactionType: Int,
- ): Boolean = manager.isFalseTouch(interactionType)
+ fun isFalseTouch(@Classifier.InteractionType interactionType: Int): Boolean =
+ manager.isFalseTouch(interactionType)
+
+ /** Returns `true` if the tap gesture should be rejected */
+ fun isFalseTap(@Penalty penalty: Int): Boolean = manager.isFalseTap(penalty)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 4f9443efd857..d648b9c6442b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -18,16 +18,19 @@ package com.android.systemui.communal
import android.os.UserHandle
import android.provider.Settings
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
import com.android.internal.logging.UiEventLogger
import com.android.systemui.CoreStartable
+import com.android.systemui.Flags.communalHubOnMobile
import com.android.systemui.Flags.communalSceneKtfRefactor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.CommunalScenes.isCommunal
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.dagger.SysUISingleton
@@ -35,7 +38,6 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dock.DockManager
-import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -62,7 +64,6 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
/**
@@ -83,7 +84,6 @@ constructor(
private val systemSettings: SystemSettings,
centralSurfacesOpt: Optional<CentralSurfaces>,
private val notificationShadeWindowController: NotificationShadeWindowController,
- private val featureFlagsClassic: FeatureFlagsClassic,
@Application private val applicationScope: CoroutineScope,
@Background private val bgScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
@@ -168,7 +168,7 @@ constructor(
communalInteractor.userActivity.emitOnStart(),
) { scene, _ ->
// Only timeout if we're on the hub is open.
- scene == CommunalScenes.Communal
+ scene.isCommunal()
}
.collectLatest { shouldTimeout ->
cancelHubTimeout()
@@ -182,7 +182,7 @@ constructor(
.sample(communalSceneInteractor.currentScene, ::Pair)
.collectLatest { (isDreaming, scene) ->
this@CommunalSceneStartable.isDreaming = isDreaming
- if (scene == CommunalScenes.Communal && isDreaming && timeoutJob == null) {
+ if (scene.isCommunal() && isDreaming && timeoutJob == null) {
// If dreaming starts after timeout has expired, ex. if dream restarts under
// the hub, just close the hub immediately.
communalSceneInteractor.changeScene(
@@ -217,6 +217,9 @@ constructor(
communalSceneInteractor.changeScene(
newScene = CommunalScenes.Blank,
loggingReason = "hub timeout",
+ transitionKey =
+ if (communalHubOnMobile()) CommunalTransitionKeys.SimpleFade
+ else null,
)
uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index 428b83ddbb3a..ae08f2b8c45e 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -98,16 +98,17 @@ constructor(
transitionKey: TransitionKey? = null,
keyguardState: KeyguardState? = null,
) {
- if (SceneContainerFlag.isEnabled) {
- return sceneInteractor.changeScene(
- toScene = newScene.toSceneContainerSceneKey(),
- loggingReason = loggingReason,
- transitionKey = transitionKey,
- sceneState = keyguardState,
- )
- }
-
applicationScope.launch("$TAG#changeScene") {
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.changeScene(
+ toScene = newScene.toSceneContainerSceneKey(),
+ loggingReason = loggingReason,
+ transitionKey = transitionKey,
+ sceneState = keyguardState,
+ )
+ return@launch
+ }
+
if (currentScene.value == newScene) return@launch
logger.logSceneChangeRequested(
from = currentScene.value,
@@ -125,16 +126,17 @@ constructor(
newScene: SceneKey,
loggingReason: String,
delayMillis: Long = 0,
- keyguardState: KeyguardState? = null
+ keyguardState: KeyguardState? = null,
) {
- if (SceneContainerFlag.isEnabled) {
- return sceneInteractor.snapToScene(
- toScene = newScene.toSceneContainerSceneKey(),
- loggingReason = loggingReason,
- )
- }
-
applicationScope.launch("$TAG#snapToScene") {
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.snapToScene(
+ toScene = newScene.toSceneContainerSceneKey(),
+ loggingReason = loggingReason,
+ )
+ return@launch
+ }
+
delay(delayMillis)
if (currentScene.value == newScene) return@launch
logger.logSceneChangeRequested(
@@ -161,10 +163,7 @@ constructor(
} else {
repository.currentScene
.pairwiseBy(initialValue = repository.currentScene.value) { from, to ->
- logger.logSceneChangeCommitted(
- from = from,
- to = to,
- )
+ logger.logSceneChangeCommitted(from = from, to = to)
to
}
.stateIn(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt
index 7cfad60b84cd..6423f8f7783b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt
@@ -30,6 +30,7 @@ constructor(
@Named(LOGGABLE_PREFIXES) private val loggablePrefixes: List<String>,
private val statsLogProxy: StatsLogProxy,
) {
+
/** Logs an add widget event for metrics. No-op if widget is not loggable. */
fun logAddWidget(componentName: String, rank: Int?) {
if (!componentName.isLoggable()) {
@@ -69,11 +70,21 @@ constructor(
)
}
+ fun logResizeWidget(componentName: String, rank: Int, spanY: Int = 0) {
+ if (!componentName.isLoggable()) {
+ return
+ }
+
+ statsLogProxy.writeCommunalHubWidgetEventReported(
+ SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__RESIZE,
+ componentName,
+ rank = rank,
+ spanY = spanY,
+ )
+ }
+
/** Logs loggable widgets and the total widget count as a [StatsEvent]. */
- fun logWidgetsSnapshot(
- statsEvents: MutableList<StatsEvent>,
- componentNames: List<String>,
- ) {
+ fun logWidgetsSnapshot(statsEvents: MutableList<StatsEvent>, componentNames: List<String>) {
val loggableComponentNames = componentNames.filter { it.isLoggable() }.toTypedArray()
statsEvents.add(
statsLogProxy.buildCommunalHubSnapshotStatsEvent(
@@ -95,6 +106,7 @@ constructor(
action: Int,
componentName: String,
rank: Int,
+ spanY: Int = 0,
)
/** Builds a [SysUiStatsLog.COMMUNAL_HUB_SNAPSHOT] stats event. */
@@ -112,12 +124,14 @@ class CommunalStatsLogProxyImpl @Inject constructor() : CommunalMetricsLogger.St
action: Int,
componentName: String,
rank: Int,
+ spanY: Int,
) {
SysUiStatsLog.write(
SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED,
action,
componentName,
rank,
+ spanY,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
index e562dfcbbc74..7f15944f61e7 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
@@ -18,9 +18,16 @@ package com.android.systemui.communal.shared.model
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
/** Definition of the possible scenes for the communal UI. */
+@Deprecated(
+ "CommunalScenes are deprecated when SceneContainerFlag is enabled. " +
+ "Use com.android.systemui.scene.shared.model.Scenes instead. " +
+ "Use SceneKey.toSceneContainerSceneKey() to map legacy scenes to scene container scenes. " +
+ "Use SceneKey.isCommunal() to check whether a scene is a communal scene."
+)
object CommunalScenes {
/** The default scene, shows nothing and is only there to allow swiping to communal. */
@JvmField val Blank = SceneKey("blank")
@@ -40,9 +47,8 @@ object CommunalScenes {
* The rules are simple:
* - A legacy communal scene maps to a communal scene in the Scene Transition Framework (STF).
* - A legacy blank scene means that the communal scene layout does not render anything so
- * whatever is beneath the layout is shown. That usually means lockscreen or dream, both of
- * which are represented by the lockscreen scene in STF (but different keyguard states in
- * KTF).
+ * whatever is beneath the layout is shown. That usually means lockscreen or dream, both in
+ * STL are represented by the home scene family.
*/
fun SceneKey.toSceneContainerSceneKey(): SceneKey {
if (!isCommunalScene() || !SceneContainerFlag.isEnabled) {
@@ -51,8 +57,13 @@ object CommunalScenes {
return when (this) {
Communal -> Scenes.Communal
- Blank -> Scenes.Lockscreen
+ Blank -> SceneFamilies.Home
else -> throw Throwable("Unrecognized communal scene: $this")
}
}
+
+ /** Checks whether this is a communal scene based on whether [SceneContainerFlag] is enabled. */
+ fun SceneKey.isCommunal(): Boolean {
+ return if (SceneContainerFlag.isEnabled) this == Scenes.Communal else this == Communal
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index e25ea4cbfb25..5ecf2e6b2551 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -29,6 +29,7 @@ import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
@@ -43,6 +44,7 @@ abstract class BaseCommunalViewModel(
val communalSceneInteractor: CommunalSceneInteractor,
private val communalInteractor: CommunalInteractor,
val mediaHost: MediaHost,
+ val mediaCarouselController: MediaCarouselController,
) {
val currentScene: Flow<SceneKey> = communalSceneInteractor.currentScene
@@ -178,7 +180,13 @@ abstract class BaseCommunalViewModel(
* alongside the resize, in case resizing also requires re-ordering. This ensures the
* re-ordering is done in the same database transaction as the resize.
*/
- open fun onResizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {}
+ open fun onResizeWidget(
+ appWidgetId: Int,
+ spanY: Int,
+ widgetIdToRankMap: Map<Int, Int>,
+ componentName: ComponentName,
+ rank: Int,
+ ) {}
/** Called as the UI requests opening the widget editor with an optional preselected widget. */
open fun onOpenWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean = false) {}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 6508e4b574a3..736ed5c7d336 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -46,6 +46,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.res.R
@@ -82,7 +83,14 @@ constructor(
private val accessibilityManager: AccessibilityManager,
private val packageManager: PackageManager,
@Named(LAUNCHER_PACKAGE) private val launcherPackage: String,
-) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) {
+ mediaCarouselController: MediaCarouselController,
+) :
+ BaseCommunalViewModel(
+ communalSceneInteractor,
+ communalInteractor,
+ mediaHost,
+ mediaCarouselController,
+ ) {
private val logger = Logger(logBuffer, "CommunalEditModeViewModel")
@@ -141,8 +149,19 @@ constructor(
override fun onReorderWidgets(widgetIdToRankMap: Map<Int, Int>) =
communalInteractor.updateWidgetOrder(widgetIdToRankMap)
- override fun onResizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+ override fun onResizeWidget(
+ appWidgetId: Int,
+ spanY: Int,
+ widgetIdToRankMap: Map<Int, Int>,
+ componentName: ComponentName,
+ rank: Int,
+ ) {
communalInteractor.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+ metricsLogger.logResizeWidget(
+ componentName = componentName.flattenToString(),
+ rank = rank,
+ spanY = spanY,
+ )
}
override fun onReorderWidgetStart() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
index 623937305921..34962305ff2a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
@@ -31,6 +31,7 @@ import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransit
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
@@ -41,6 +42,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
@@ -60,7 +62,7 @@ constructor(
glanceableHubToDreamTransitionViewModel: GlanceableHubToDreamingTransitionViewModel,
communalInteractor: CommunalInteractor,
private val communalSceneInteractor: CommunalSceneInteractor,
- keyguardTransitionInteractor: KeyguardTransitionInteractor
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
) {
/**
* Snaps to [CommunalScenes.Communal], showing the glanceable hub immediately without any
@@ -89,7 +91,7 @@ constructor(
keyguardTransitionInteractor
.transition(
edge = Edge.create(from = Scenes.Communal),
- edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB)
+ edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB),
)
.filter {
it.to == KeyguardState.OCCLUDED &&
@@ -114,21 +116,24 @@ constructor(
// from
// the hub, then pressing power twice to go back to the lock screen.
communalSceneInteractor.isCommunalVisible,
- merge(
- lockscreenToGlanceableHubTransitionViewModel.showUmo,
- glanceableHubToLockscreenTransitionViewModel.showUmo,
- dreamToGlanceableHubTransitionViewModel.showUmo,
- glanceableHubToDreamTransitionViewModel.showUmo,
- showUmoFromOccludedToGlanceableHub,
- showUmoFromGlanceableHubToOccluded,
- )
- .onStart { emit(false) }
- )
+ // TODO(b/378942852): polish UMO transitions when scene container is enabled
+ if (SceneContainerFlag.isEnabled) flowOf(true)
+ else
+ merge(
+ lockscreenToGlanceableHubTransitionViewModel.showUmo,
+ glanceableHubToLockscreenTransitionViewModel.showUmo,
+ dreamToGlanceableHubTransitionViewModel.showUmo,
+ glanceableHubToDreamTransitionViewModel.showUmo,
+ showUmoFromOccludedToGlanceableHub,
+ showUmoFromGlanceableHubToOccluded,
+ )
+ .onStart { emit(false) },
+ ),
)
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false
+ initialValue = false,
)
/** Whether to show communal when exiting the occluded state. */
@@ -145,8 +150,7 @@ constructor(
val recentsBackgroundColor: Flow<Color?> =
combine(showCommunalFromOccluded, communalColors.backgroundColor) {
showCommunalFromOccluded,
- backgroundColor,
- ->
+ backgroundColor ->
if (showCommunalFromOccluded) {
backgroundColor
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 7990450f6ac8..9cd6465266d4 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -21,6 +21,7 @@ import android.content.res.Resources
import android.os.Bundle
import android.view.View
import android.view.accessibility.AccessibilityNodeInfo
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
@@ -38,6 +39,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.controls.ui.view.MediaHostState
@@ -72,7 +74,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
/** The default view model used for showing the communal hub. */
@OptIn(ExperimentalCoroutinesApi::class)
@@ -95,7 +96,14 @@ constructor(
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
@CommunalLog logBuffer: LogBuffer,
private val metricsLogger: CommunalMetricsLogger,
-) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) {
+ mediaCarouselController: MediaCarouselController,
+) :
+ BaseCommunalViewModel(
+ communalSceneInteractor,
+ communalInteractor,
+ mediaHost,
+ mediaCarouselController,
+ ) {
private val logger = Logger(logBuffer, "CommunalViewModel")
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 4cdf28670eab..38cfb9b333a8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -25,10 +25,13 @@ import com.android.systemui.back.domain.interactor.BackActionInteractor
import com.android.systemui.biometrics.BiometricNotificationService
import com.android.systemui.bouncer.domain.startable.BouncerStartable
import com.android.systemui.clipboardoverlay.ClipboardListener
+import com.android.systemui.complication.ComplicationTypesUpdater
+import com.android.systemui.complication.DreamClockTimeComplication
import com.android.systemui.controls.dagger.StartControlsStartableModule
import com.android.systemui.dagger.qualifiers.PerUser
import com.android.systemui.dreams.AssistantAttentionMonitor
import com.android.systemui.dreams.DreamMonitor
+import com.android.systemui.dreams.DreamOverlayRegistrant
import com.android.systemui.dreams.homecontrols.system.HomeControlsDreamStartable
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.haptics.msdl.MSDLCoreStartable
@@ -328,4 +331,26 @@ abstract class SystemUICoreStartableModule {
@IntoMap
@ClassKey(MSDLCoreStartable::class)
abstract fun bindMSDLCoreStartable(impl: MSDLCoreStartable): CoreStartable
+
+ /** Inject into DreamOverlay. */
+ @Binds
+ @IntoMap
+ @ClassKey(DreamOverlayRegistrant::class)
+ abstract fun bindDreamOverlayRegistrant(
+ dreamOverlayRegistrant: DreamOverlayRegistrant
+ ): CoreStartable
+
+ /** Inject into DreamClockTimeComplication.Registrant */
+ @Binds
+ @IntoMap
+ @ClassKey(DreamClockTimeComplication.Registrant::class)
+ abstract fun bindDreamClockTimeComplicationRegistrant(
+ registrant: DreamClockTimeComplication.Registrant
+ ): CoreStartable
+
+ /** Inject into ComplicationTypesUpdater. */
+ @Binds
+ @IntoMap
+ @ClassKey(ComplicationTypesUpdater::class)
+ abstract fun bindComplicationTypesUpdater(updater: ComplicationTypesUpdater): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 4447dff7af00..b7d3c9253f51 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -100,7 +100,7 @@ import com.android.systemui.qs.QSFragmentStartableModule;
import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.recordissue.RecordIssueModule;
-import com.android.systemui.retail.dagger.RetailModeModule;
+import com.android.systemui.retail.RetailModeModule;
import com.android.systemui.scene.shared.model.SceneContainerConfig;
import com.android.systemui.scene.shared.model.SceneDataSource;
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator;
diff --git a/packages/SystemUI/src/com/android/systemui/development/data/repository/DevelopmentSettingRepository.kt b/packages/SystemUI/src/com/android/systemui/development/data/repository/DevelopmentSettingRepository.kt
new file mode 100644
index 000000000000..a8fa9797ebfd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/development/data/repository/DevelopmentSettingRepository.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 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.development.data.repository
+
+import android.content.pm.UserInfo
+import android.os.Build
+import android.os.UserManager
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.kotlin.emitOnStart
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+class DevelopmentSettingRepository
+@Inject
+constructor(
+ private val globalSettings: GlobalSettings,
+ private val userManager: UserManager,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
+ private val settingFlow = globalSettings.observerFlow(SETTING)
+
+ /**
+ * Indicates whether development settings is enabled for this user. The conditions are:
+ * * Setting is enabled (defaults to true in eng builds)
+ * * User is an admin
+ * * User is not restricted from Debugging features.
+ */
+ fun isDevelopmentSettingEnabled(userInfo: UserInfo): Flow<Boolean> {
+ return settingFlow
+ .emitOnStart()
+ .map { checkDevelopmentSettingEnabled(userInfo) }
+ .flowOn(backgroundDispatcher)
+ }
+
+ private suspend fun checkDevelopmentSettingEnabled(userInfo: UserInfo): Boolean {
+ val hasUserRestriction =
+ withContext(backgroundDispatcher) {
+ userManager.hasUserRestrictionForUser(
+ UserManager.DISALLOW_DEBUGGING_FEATURES,
+ userInfo.userHandle,
+ )
+ }
+ val isSettingEnabled =
+ withContext(backgroundDispatcher) {
+ globalSettings.getInt(SETTING, DEFAULT_ENABLED) != 0
+ }
+ val isAdmin = userInfo.isAdmin
+ return isAdmin && !hasUserRestriction && isSettingEnabled
+ }
+
+ private companion object {
+ val DEFAULT_ENABLED = if (Build.TYPE == "eng") 1 else 0
+
+ const val SETTING = Settings.Global.DEVELOPMENT_SETTINGS_ENABLED
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt b/packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt
new file mode 100644
index 000000000000..4d786fe76bc1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 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.development.domain.interactor
+
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.res.Resources
+import android.os.Build
+import android.os.UserHandle
+import com.android.internal.R as InternalR
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.development.data.repository.DevelopmentSettingRepository
+import com.android.systemui.development.shared.model.BuildNumber
+import com.android.systemui.res.R as SystemUIR
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.user.utils.UserScopedService
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapConcat
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.withContext
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class BuildNumberInteractor
+@Inject
+constructor(
+ repository: DevelopmentSettingRepository,
+ @Main resources: Resources,
+ private val userRepository: UserRepository,
+ private val clipboardManagerProvider: UserScopedService<ClipboardManager>,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
+
+ /**
+ * Build number, or `null` if Development Settings is not enabled for the current user.
+ *
+ * @see DevelopmentSettingRepository.isDevelopmentSettingEnabled
+ */
+ val buildNumber: Flow<BuildNumber?> =
+ userRepository.selectedUserInfo
+ .flatMapConcat { userInfo -> repository.isDevelopmentSettingEnabled(userInfo) }
+ .map { enabled -> buildText.takeIf { enabled } }
+
+ private val buildText =
+ BuildNumber(
+ resources.getString(
+ InternalR.string.bugreport_status,
+ Build.VERSION.RELEASE_OR_CODENAME,
+ Build.ID,
+ )
+ )
+
+ private val clipLabel = resources.getString(SystemUIR.string.build_number_clip_data_label)
+
+ private val currentUserHandle: UserHandle
+ get() = userRepository.getSelectedUserInfo().userHandle
+
+ /**
+ * Copy to the clipboard the build number for the current user.
+ *
+ * This can be performed regardless of the current user having Development Settings enabled
+ */
+ suspend fun copyBuildNumber() {
+ withContext(backgroundDispatcher) {
+ clipboardManagerProvider
+ .forUser(currentUserHandle)
+ .setPrimaryClip(ClipData.newPlainText(clipLabel, buildText.value))
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/development/shared/model/BuildNumber.kt b/packages/SystemUI/src/com/android/systemui/development/shared/model/BuildNumber.kt
new file mode 100644
index 000000000000..5bd713fc4840
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/development/shared/model/BuildNumber.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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.development.shared.model
+
+@JvmInline value class BuildNumber(val value: String)
diff --git a/packages/SystemUI/src/com/android/systemui/development/ui/compose/BuildNumber.kt b/packages/SystemUI/src/com/android/systemui/development/ui/compose/BuildNumber.kt
new file mode 100644
index 000000000000..72e1cede0002
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/development/ui/compose/BuildNumber.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.development.ui.compose
+
+import androidx.compose.foundation.basicMarquee
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.material3.Text
+import androidx.compose.material3.minimumInteractiveComponentSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalHapticFeedback
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.onLongClick
+import androidx.compose.ui.semantics.semantics
+import com.android.systemui.communal.ui.compose.extensions.detectLongPressGesture
+import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel
+import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.res.R
+
+@Composable
+fun BuildNumber(
+ viewModelFactory: BuildNumberViewModel.Factory,
+ textColor: Color,
+ modifier: Modifier = Modifier,
+) {
+ val viewModel = rememberViewModel(traceName = "BuildNumber") { viewModelFactory.create() }
+
+ val buildNumber = viewModel.buildNumber
+
+ if (buildNumber != null) {
+ val haptics = LocalHapticFeedback.current
+ val copyToClipboardActionLabel = stringResource(id = R.string.copy_to_clipboard_a11y_action)
+
+ Text(
+ text = buildNumber.value,
+ modifier =
+ modifier
+ .focusable()
+ .wrapContentWidth()
+ // Using this instead of combinedClickable because this node should not support
+ // single click
+ .pointerInput(Unit) {
+ detectLongPressGesture {
+ haptics.performHapticFeedback(HapticFeedbackType.LongPress)
+ viewModel.onBuildNumberLongPress()
+ }
+ }
+ .semantics {
+ onLongClick(copyToClipboardActionLabel) {
+ viewModel.onBuildNumberLongPress()
+ true
+ }
+ }
+ .basicMarquee(iterations = 1, initialDelayMillis = 2000)
+ .minimumInteractiveComponentSize(),
+ color = textColor,
+ maxLines = 1,
+ )
+ } else {
+ Spacer(modifier)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt b/packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt
new file mode 100644
index 000000000000..68c51ea80ffd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 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.development.ui.viewmodel
+
+import androidx.compose.runtime.getValue
+import com.android.systemui.development.domain.interactor.BuildNumberInteractor
+import com.android.systemui.development.shared.model.BuildNumber
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.receiveAsFlow
+import kotlinx.coroutines.launch
+
+/** View model for UI that (optionally) shows the build number and copies it on long press. */
+class BuildNumberViewModel
+@AssistedInject
+constructor(private val buildNumberInteractor: BuildNumberInteractor) : ExclusiveActivatable() {
+
+ private val hydrator = Hydrator("BuildNumberViewModel")
+
+ private val copyRequests = Channel<Unit>()
+
+ val buildNumber: BuildNumber? by
+ hydrator.hydratedStateOf(
+ traceName = "buildNumber",
+ initialValue = null,
+ source = buildNumberInteractor.buildNumber,
+ )
+
+ fun onBuildNumberLongPress() {
+ copyRequests.trySend(Unit)
+ }
+
+ override suspend fun onActivated(): Nothing {
+ coroutineScope {
+ launch { hydrator.activate() }
+ launch {
+ copyRequests.receiveAsFlow().collect { buildNumberInteractor.copyBuildNumber() }
+ }
+ awaitCancellation()
+ }
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): BuildNumberViewModel
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 1a5654144b65..2e1096fcae36 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.deviceentry.domain.interactor
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.policy.IKeyguardDismissCallback
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
@@ -43,7 +44,6 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Hosts application business logic related to device entry.
@@ -84,30 +84,53 @@ constructor(
)
/**
+ * Emits `true` when the current scene switches to [Scenes.Gone] for the first time after having
+ * been on [Scenes.Lockscreen].
+ *
+ * Different from [isDeviceEntered] such that the current scene must actually go through
+ * [Scenes.Gone] to produce a `true`. [isDeviceEntered] also takes into account the navigation
+ * back stack and will produce a `true` value even when the current scene is still not
+ * [Scenes.Gone] but the bottommost entry of the navigation back stack switched from
+ * [Scenes.Lockscreen] to [Scenes.Gone] while the user is staring at another scene.
+ */
+ val isDeviceEnteredDirectly: StateFlow<Boolean> =
+ sceneInteractor.currentScene
+ .filter { currentScene ->
+ currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
+ }
+ .mapLatestConflated { scene ->
+ if (scene == Scenes.Gone) {
+ // Make sure device unlock status is definitely unlocked before we
+ // consider the device "entered".
+ deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
+ true
+ } else {
+ false
+ }
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
+
+ /**
* Whether the device has been entered (i.e. the lockscreen has been dismissed, by any method).
* This can be `false` when the device is unlocked, e.g. when the user still needs to swipe away
* the non-secure lockscreen, even though they've already authenticated.
*
* Note: This does not imply that the lockscreen is visible or not.
+ *
+ * Different from [isDeviceEnteredDirectly] such that the current scene doesn't actually have to
+ * go through [Scenes.Gone] to produce a `true`. [isDeviceEnteredDirectly] doesn't take the
+ * navigation back stack into account and will only produce a `true` value even when the current
+ * scene is actually [Scenes.Gone].
*/
val isDeviceEntered: StateFlow<Boolean> =
combine(
// This flow emits true when the currentScene switches to Gone for the first time
// after having been on Lockscreen.
- sceneInteractor.currentScene
- .filter { currentScene ->
- currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
- }
- .mapLatestConflated { scene ->
- if (scene == Scenes.Gone) {
- // Make sure device unlock status is definitely unlocked before we
- // consider the device "entered".
- deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
- true
- } else {
- false
- }
- },
+ isDeviceEnteredDirectly,
// This flow emits true only if the bottom of the navigation back stack has been
// switched from Lockscreen to Gone. In other words, only if the device was unlocked
// while visiting at least one scene "above" the Lockscreen scene.
@@ -174,6 +197,14 @@ constructor(
}
/**
+ * Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically
+ * dismissed once the authentication challenge is completed. For example, completing a biometric
+ * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
+ * lockscreen.
+ */
+ val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled
+
+ /**
* Attempt to enter the device and dismiss the lockscreen. If authentication is required to
* unlock the device it will transition to bouncer.
*
@@ -238,11 +269,8 @@ constructor(
isLockscreenEnabled()
}
- /**
- * Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically
- * dismissed once the authentication challenge is completed. For example, completing a biometric
- * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
- * lockscreen.
- */
- val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled
+ /** Locks the device instantly. */
+ fun lockNow() {
+ deviceUnlockedInteractor.lockNow()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
index b74ca035a229..7d684cab39f7 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
@@ -35,6 +35,7 @@ import com.android.systemui.keyguard.domain.interactor.TrustInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
@@ -42,6 +43,7 @@ import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
@@ -56,6 +58,7 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
@OptIn(ExperimentalCoroutinesApi::class)
@@ -177,6 +180,8 @@ constructor(
val deviceUnlockStatus: StateFlow<DeviceUnlockStatus> =
repository.deviceUnlockStatus.asStateFlow()
+ private val lockNowRequests = Channel<Unit>()
+
override suspend fun onActivated(): Nothing {
authenticationInteractor.authenticationMethod.collectLatest { authMethod ->
if (!authMethod.isSecure) {
@@ -195,6 +200,11 @@ constructor(
awaitCancellation()
}
+ /** Locks the device instantly. */
+ fun lockNow() {
+ lockNowRequests.trySend(Unit)
+ }
+
private suspend fun handleLockAndUnlockEvents() {
try {
Log.d(TAG, "started watching for lock and unlock events")
@@ -224,10 +234,12 @@ constructor(
.map { (isAsleep, lastSleepReason) ->
if (isAsleep) {
if (
- lastSleepReason == WakeSleepReason.POWER_BUTTON &&
+ (lastSleepReason == WakeSleepReason.POWER_BUTTON) &&
authenticationInteractor.getPowerButtonInstantlyLocks()
) {
LockImmediately("locked instantly from power button")
+ } else if (lastSleepReason == WakeSleepReason.SLEEP_BUTTON) {
+ LockImmediately("locked instantly from sleep button")
} else {
LockWithDelay("entering sleep")
}
@@ -255,6 +267,7 @@ constructor(
emptyFlow()
}
},
+ lockNowRequests.receiveAsFlow().map { LockImmediately("lockNow") },
)
.collectLatest(::onLockEvent)
}
@@ -363,6 +376,9 @@ constructor(
private val interactor: DeviceUnlockedInteractor,
) : CoreStartable {
override fun start() {
+ if (!SceneContainerFlag.isEnabled)
+ return
+
applicationScope.launch { interactor.activate() }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index 589dbf92de38..e862525623fe 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -30,6 +30,8 @@ import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractorImpl
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import dagger.Binds
import dagger.Lazy
@@ -46,6 +48,11 @@ interface DisplayModule {
provider: ConnectedDisplayInteractorImpl
): ConnectedDisplayInteractor
+ @Binds
+ fun bindRearDisplayStateInteractor(
+ provider: RearDisplayStateInteractorImpl
+ ): RearDisplayStateInteractor
+
@Binds fun bindsDisplayRepository(displayRepository: DisplayRepositoryImpl): DisplayRepository
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
index 1da5351ac2a3..29044d017d2d 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.hardware.devicestate.DeviceState as PlatformDeviceState
import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT
import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY
+import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN
@@ -49,6 +50,15 @@ interface DeviceStateRepository {
UNFOLDED,
/** Device state that corresponds to the device being in rear display mode */
REAR_DISPLAY,
+ /**
+ * Device state that corresponds to the device being in rear display mode with the inner
+ * display showing a system-provided affordance to cancel the mode.
+ *
+ * TODO(b/371095273): This state will be removed after the RDM_V2 flag lifecycle is complete
+ * at which point the REAR_DISPLAY state will be the will be the new and only rear display
+ * mode.
+ */
+ REAR_DISPLAY_OUTER_DEFAULT,
/** Device state in that corresponds to the device being in concurrent display mode */
CONCURRENT_DISPLAY,
/** Device state in none of the other arrays. */
@@ -62,7 +72,7 @@ constructor(
val context: Context,
val deviceStateManager: DeviceStateManager,
@Background bgScope: CoroutineScope,
- @Background executor: Executor
+ @Background executor: Executor,
) : DeviceStateRepository {
override val state: StateFlow<DeviceState> =
@@ -105,6 +115,12 @@ constructor(
*/
private fun PlatformDeviceState.toDeviceStateEnum(): DeviceState {
return when {
+ hasProperties(
+ PROPERTY_FEATURE_REAR_DISPLAY,
+ PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT,
+ ) -> {
+ DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+ }
hasProperty(PROPERTY_FEATURE_REAR_DISPLAY) -> DeviceState.REAR_DISPLAY
hasProperty(PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT) -> {
DeviceState.CONCURRENT_DISPLAY
@@ -112,7 +128,7 @@ constructor(
hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) -> DeviceState.FOLDED
hasProperties(
PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
- PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN
+ PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN,
) -> DeviceState.HALF_FOLDED
hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) -> {
DeviceState.UNFOLDED
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
index 80eb9eea6c9b..f310b30c1a81 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
@@ -27,6 +27,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.shared.model.DisplayWindowProperties
import com.android.systemui.res.R
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.google.common.collect.HashBasedTable
import com.google.common.collect.Table
@@ -60,7 +61,10 @@ constructor(
) : DisplayWindowPropertiesRepository, CoreStartable {
init {
- StatusBarConnectedDisplays.assertInNewMode()
+ check(StatusBarConnectedDisplays.isEnabled || ShadeWindowGoesAround.isEnabled) {
+ "This should be instantiated only when wither StatusBarConnectedDisplays or " +
+ "ShadeWindowGoesAround are enabled."
+ }
}
private val properties: Table<Int, Int, DisplayWindowProperties> = HashBasedTable.create()
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
index ecddef6ee843..711534f9dbf0 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
@@ -17,13 +17,12 @@
package com.android.systemui.display.data.repository
import android.view.Display
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.qualifiers.Background
import java.io.PrintWriter
import java.util.concurrent.ConcurrentHashMap
-import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
/** Provides per display instances of [T]. */
interface PerDisplayStore<T> {
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt
new file mode 100644
index 000000000000..b743377881bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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.display.domain.interactor
+
+import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DeviceStateRepository
+import com.android.systemui.display.data.repository.DisplayRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combineTransform
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+
+/** Provides information about the status of Rear Display Mode. */
+interface RearDisplayStateInteractor {
+
+ /** A flow notifying the subscriber of Rear Display state changes */
+ val state: Flow<State>
+
+ sealed class State {
+ /** Indicates that the rear display is disabled */
+ data object Disabled : State()
+
+ /**
+ * Indicates that the device is in Rear Display Mode, and that the inner display is ready to
+ * show a system-provided affordance allowing the user to cancel out of the Rear Display
+ * Mode.
+ */
+ data class Enabled(val innerDisplay: Display) : State()
+ }
+}
+
+@SysUISingleton
+class RearDisplayStateInteractorImpl
+@Inject
+constructor(
+ displayRepository: DisplayRepository,
+ deviceStateRepository: DeviceStateRepository,
+ @Background backgroundCoroutineDispatcher: CoroutineDispatcher,
+) : RearDisplayStateInteractor {
+
+ override val state: Flow<RearDisplayStateInteractor.State> =
+ deviceStateRepository.state
+ .combineTransform(displayRepository.displays) { state, displays ->
+ val innerDisplay = displays.find { it.flags and Display.FLAG_REAR != 0 }
+
+ if (state != DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT) {
+ emit(RearDisplayStateInteractor.State.Disabled)
+ } else if (innerDisplay != null) {
+ emit(RearDisplayStateInteractor.State.Enabled(innerDisplay))
+ }
+ }
+ .distinctUntilChanged()
+ .flowOn(backgroundCoroutineDispatcher)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 89fce4a70c6c..abc810afca98 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -469,9 +469,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
|| posture >= mLightSensorOptional.length) {
return;
}
-
- final Sensor oldSensor = mLightSensorOptional[mDevicePosture].get();
- final Sensor newSensor = mLightSensorOptional[posture].get();
+ Sensor oldSensor = mLightSensorOptional[mDevicePosture].orElse(null);
+ Sensor newSensor = mLightSensorOptional[posture].orElse(null);
if (Objects.equals(oldSensor, newSensor)) {
mDevicePosture = posture;
// uses the same sensor for the new posture
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
deleted file mode 100644
index 80e68cfbff21..000000000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
+++ /dev/null
@@ -1,129 +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;
-
-import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.os.PatternMatcher;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
-import android.util.Log;
-
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dagger.qualifiers.SystemUser;
-import com.android.systemui.shared.condition.Monitor;
-import com.android.systemui.util.condition.ConditionalCoreStartable;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-/**
- * {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be
- * the designated dream overlay component.
- */
-public class DreamOverlayRegistrant extends ConditionalCoreStartable {
- private static final String TAG = "DreamOverlayRegistrant";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final IDreamManager mDreamManager;
- private final ComponentName mOverlayServiceComponent;
- private final Context mContext;
- private final Resources mResources;
- private boolean mCurrentRegisteredState = false;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "package changed receiver - onReceive");
- }
-
- registerOverlayService();
- }
- };
-
- private void registerOverlayService() {
- // Check to see if the service has been disabled by the user. In this case, we should not
- // proceed modifying the enabled setting.
- final PackageManager packageManager = mContext.getPackageManager();
- final int enabledState =
- packageManager.getComponentEnabledSetting(mOverlayServiceComponent);
-
- // The overlay service is only registered when its component setting is enabled.
- boolean register = false;
-
- try {
- register = packageManager.getServiceInfo(mOverlayServiceComponent,
- PackageManager.GET_META_DATA).enabled;
- } catch (NameNotFoundException e) {
- Log.e(TAG, "could not find dream overlay service");
- }
-
- if (mCurrentRegisteredState == register) {
- return;
- }
-
- mCurrentRegisteredState = register;
-
- try {
- if (DEBUG) {
- Log.d(TAG, mCurrentRegisteredState
- ? "registering dream overlay service:" + mOverlayServiceComponent
- : "clearing dream overlay service");
- }
-
- mDreamManager.registerDreamOverlayService(
- mCurrentRegisteredState ? mOverlayServiceComponent : null);
- } catch (RemoteException e) {
- Log.e(TAG, "could not register dream overlay service:" + e);
- }
- }
-
- @Inject
- public DreamOverlayRegistrant(Context context, @Main Resources resources,
- @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent,
- @SystemUser Monitor monitor) {
- super(monitor);
- mContext = context;
- mResources = resources;
- mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.getService(DreamService.DREAM_SERVICE));
- mOverlayServiceComponent = dreamOverlayServiceComponent;
- }
-
- @Override
- protected void onStart() {
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- filter.addDataSchemeSpecificPart(mOverlayServiceComponent.getPackageName(),
- PatternMatcher.PATTERN_LITERAL);
- // Note that we directly register the receiver here as data schemes are not supported by
- // BroadcastDispatcher.
- mContext.registerReceiver(mReceiver, filter);
-
- registerOverlayService();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt
new file mode 100644
index 000000000000..e76fd47c74de
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2024 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 android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.os.PatternMatcher
+import android.os.RemoteException
+import android.service.dreams.IDreamManager
+import android.util.Log
+import com.android.systemui.Flags
+import com.android.systemui.dagger.qualifiers.SystemUser
+import com.android.systemui.dreams.dagger.DreamModule
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.dagger.DreamLog
+import com.android.systemui.shared.condition.Monitor
+import com.android.systemui.util.condition.ConditionalCoreStartable
+import javax.inject.Inject
+import javax.inject.Named
+
+/**
+ * [DreamOverlayRegistrant] is responsible for telling system server that SystemUI should be the
+ * designated dream overlay component.
+ */
+class DreamOverlayRegistrant
+@Inject
+constructor(
+ private val context: Context,
+ @param:Named(DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT)
+ private val overlayServiceComponent: ComponentName,
+ @SystemUser monitor: Monitor,
+ private val packageManager: PackageManager,
+ private val dreamManager: IDreamManager,
+ @DreamLog private val logBuffer: LogBuffer,
+) : ConditionalCoreStartable(monitor) {
+ private var currentRegisteredState = false
+ private val logger: DreamLogger = DreamLogger(logBuffer, TAG)
+
+ private val receiver: BroadcastReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (DEBUG) {
+ Log.d(TAG, "package changed receiver - onReceive")
+ }
+
+ registerOverlayService()
+ }
+ }
+
+ internal val enabledInManifest: Boolean
+ get() {
+ return packageManager
+ .getServiceInfo(
+ overlayServiceComponent,
+ PackageManager.GET_META_DATA or PackageManager.MATCH_DISABLED_COMPONENTS,
+ )
+ .enabled
+ }
+
+ internal val enabled: Boolean
+ get() {
+ // Always disabled via setting
+ if (
+ packageManager.getComponentEnabledSetting(overlayServiceComponent) ==
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ ) {
+ return false
+ }
+
+ // If the overlay is available in the manifest, then it is already available
+ if (enabledInManifest) {
+ return true
+ }
+
+ if (
+ Flags.communalHubOnMobile() &&
+ packageManager.getComponentEnabledSetting(overlayServiceComponent) ==
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ ) {
+ return true
+ }
+
+ return false
+ }
+
+ /**
+ * This method enables the dream overlay at runtime. This method allows expanding the eligible
+ * device pool during development before enabling the component in said devices' manifest.
+ */
+ internal fun enableIfAvailable() {
+ // If the overlay is available in the manifest, then it is already available
+ if (enabledInManifest) {
+ return
+ }
+
+ // Enable for hub on mobile
+ if (Flags.communalHubOnMobile()) {
+ // Not available on TV or auto
+ if (
+ packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) ||
+ packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) ||
+ packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)
+ ) {
+ if (DEBUG) {
+ Log.d(TAG, "unsupported platform")
+ }
+ return
+ }
+
+ // If the component is not in the default enabled state, then don't update
+ if (
+ packageManager.getComponentEnabledSetting(overlayServiceComponent) !=
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ ) {
+ return
+ }
+
+ packageManager.setComponentEnabledSetting(
+ overlayServiceComponent,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP,
+ )
+ }
+ }
+
+ private fun registerOverlayService() {
+ // The overlay service is only registered when its component setting is enabled.
+ var register = false
+
+ try {
+ Log.d(TAG, "trying to find component:" + overlayServiceComponent)
+ // Check to see if the service has been disabled by the user. In this case, we should
+ // not proceed modifying the enabled setting.
+ register = enabled
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(TAG, "could not find dream overlay service")
+ }
+
+ if (currentRegisteredState == register) {
+ return
+ }
+
+ currentRegisteredState = register
+
+ try {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ if (currentRegisteredState)
+ "registering dream overlay service:$overlayServiceComponent"
+ else "clearing dream overlay service",
+ )
+ }
+
+ dreamManager.registerDreamOverlayService(
+ if (currentRegisteredState) overlayServiceComponent else null
+ )
+ logger.logDreamOverlayEnabled(currentRegisteredState)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "could not register dream overlay service:$e")
+ }
+ }
+
+ override fun onStart() {
+ val filter = IntentFilter(Intent.ACTION_PACKAGE_CHANGED)
+ filter.addDataScheme("package")
+ filter.addDataSchemeSpecificPart(
+ overlayServiceComponent.packageName,
+ PatternMatcher.PATTERN_LITERAL,
+ )
+ // Note that we directly register the receiver here as data schemes are not supported by
+ // BroadcastDispatcher.
+ context.registerReceiver(receiver, filter)
+
+ registerOverlayService()
+
+ enableIfAvailable()
+ }
+
+ companion object {
+ private const val TAG = "DreamOverlayRegistrant"
+ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 1ffbbd2a9f32..43b7cedcd767 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -18,6 +18,7 @@ package com.android.systemui.dreams;
import static android.service.dreams.Flags.dreamWakeRedirect;
+import static com.android.systemui.Flags.communalHubOnMobile;
import static com.android.systemui.Flags.glanceableHubAllowKeyguardWhenDreaming;
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_WINDOW_TITLE;
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_TOUCH_INSET_MANAGER;
@@ -47,24 +48,30 @@ import androidx.lifecycle.ServiceLifecycleDispatcher;
import androidx.lifecycle.ViewModelStore;
import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
+import com.android.compose.animation.scene.SceneKey;
import com.android.dream.lowlight.dagger.LowLightDreamModule;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.ambient.touch.TouchHandler;
import com.android.systemui.ambient.touch.TouchMonitor;
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent;
import com.android.systemui.ambient.touch.scrim.ScrimManager;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.communal.shared.log.CommunalUiEvent;
import com.android.systemui.communal.shared.model.CommunalScenes;
+import com.android.systemui.communal.shared.model.CommunalTransitionKeys;
import com.android.systemui.complication.dagger.ComplicationComponent;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.navigationbar.gestural.domain.GestureInteractor;
import com.android.systemui.navigationbar.gestural.domain.TaskMatcher;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.scene.shared.model.Scenes;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -72,8 +79,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor;
import kotlinx.coroutines.Job;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.function.Consumer;
@@ -162,6 +169,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
private TouchMonitor mTouchMonitor;
+ private final SceneInteractor mSceneInteractor;
private final CommunalInteractor mCommunalInteractor;
private boolean mCommunalAvailable;
@@ -208,16 +216,14 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
private final Consumer<Boolean> mBouncerShowingConsumer = new Consumer<>() {
@Override
public void accept(Boolean bouncerShowing) {
- mExecutor.execute(() -> {
- if (mBouncerShowing == bouncerShowing) {
- return;
- }
-
- mBouncerShowing = bouncerShowing;
+ mExecutor.execute(() -> updateBouncerShowingLocked(bouncerShowing));
+ }
+ };
- updateLifecycleStateLocked();
- updateGestureBlockingLocked();
- });
+ private final Consumer<SceneKey> mCurrentSceneConsumer = new Consumer<>() {
+ @Override
+ public void accept(SceneKey currentScene) {
+ mExecutor.execute(() -> updateBouncerShowingLocked(currentScene == Scenes.Bouncer));
}
};
@@ -378,6 +384,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
KeyguardUpdateMonitor keyguardUpdateMonitor,
ScrimManager scrimManager,
CommunalInteractor communalInteractor,
+ SceneInteractor sceneInteractor,
SystemDialogsCloser systemDialogsCloser,
UiEventLogger uiEventLogger,
@Named(DREAM_TOUCH_INSET_MANAGER) TouchInsetManager touchInsetManager,
@@ -405,6 +412,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mDreamOverlayCallbackController = dreamOverlayCallbackController;
mWindowTitle = windowTitle;
mCommunalInteractor = communalInteractor;
+ mSceneInteractor = sceneInteractor;
mSystemDialogsCloser = systemDialogsCloser;
mGestureInteractor = gestureInteractor;
mDreamOverlayComponentFactory = dreamOverlayComponentFactory;
@@ -419,8 +427,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mIsCommunalAvailableCallback));
mFlows.add(collectFlow(getLifecycle(), communalInteractor.isCommunalVisible(),
mCommunalVisibleConsumer));
- mFlows.add(collectFlow(getLifecycle(), keyguardInteractor.primaryBouncerShowing,
- mBouncerShowingConsumer));
+ if (SceneContainerFlag.isEnabled()) {
+ mFlows.add(collectFlow(getLifecycle(), sceneInteractor.getCurrentScene(),
+ mCurrentSceneConsumer));
+ } else {
+ mFlows.add(collectFlow(getLifecycle(), keyguardInteractor.primaryBouncerShowing,
+ mBouncerShowingConsumer));
+ }
}
@NonNull
@@ -473,11 +486,16 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
final DreamOverlayComponent dreamOverlayComponent = mDreamOverlayComponentFactory.create(
mLifecycleOwner, complicationComponent.getComplicationHostViewController(),
mTouchInsetManager);
+
+ final ArrayList<TouchHandler> touchHandlers = new ArrayList<>(
+ List.of(dreamComplicationComponent.getHideComplicationTouchHandler()));
+ if (!communalHubOnMobile()) {
+ // Do not add the communal touch handler for glanceable hub v2 since there is no dream
+ // to hub swipe gesture.
+ touchHandlers.add(dreamOverlayComponent.getCommunalTouchHandler());
+ }
final AmbientTouchComponent ambientTouchComponent = mAmbientTouchComponentFactory.create(
- mLifecycleOwner,
- new HashSet<>(Arrays.asList(
- dreamComplicationComponent.getHideComplicationTouchHandler(),
- dreamOverlayComponent.getCommunalTouchHandler())), TAG);
+ mLifecycleOwner, new HashSet<>(touchHandlers), TAG);
setLifecycleStateLocked(Lifecycle.State.STARTED);
@@ -551,9 +569,15 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
@Override
public void onWakeRequested() {
mUiEventLogger.log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START);
- mCommunalInteractor.changeScene(CommunalScenes.Communal,
- "dream wake requested",
- null);
+ if (SceneContainerFlag.isEnabled()) {
+ // Scene interactor can only be modified on main thread.
+ mExecutor.execute(() -> mSceneInteractor.changeScene(Scenes.Communal,
+ "dream wake redirect to communal"));
+ } else {
+ mCommunalInteractor.changeScene(CommunalScenes.Communal,
+ "dream wake requested",
+ communalHubOnMobile() ? CommunalTransitionKeys.INSTANCE.getSimpleFade() : null);
+ }
}
private void updateGestureBlockingLocked() {
@@ -617,7 +641,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mSystemDialogsCloser.closeSystemDialogs();
// Hide glanceable hub (this is a nop if glanceable hub is not open).
- mCommunalInteractor.changeScene(CommunalScenes.Blank, "dream come to front", null);
+ if (SceneContainerFlag.isEnabled()) {
+ // Scene interactor can only be modified on main thread.
+ mExecutor.execute(
+ () -> mSceneInteractor.changeScene(Scenes.Dream, "closing hub to go to dream"));
+ } else {
+ mCommunalInteractor.changeScene(CommunalScenes.Blank, "dream come to front", null);
+ }
}
/**
@@ -689,4 +719,15 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
Log.w(TAG, "Removing dream overlay container view parent!");
parentView.removeView(containerView);
}
+
+ private void updateBouncerShowingLocked(boolean bouncerShowing) {
+ if (mBouncerShowing == bouncerShowing) {
+ return;
+ }
+
+ mBouncerShowing = bouncerShowing;
+
+ updateLifecycleStateLocked();
+ updateGestureBlockingLocked();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index 7015cc992dad..bd1fda7ad03a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -16,8 +16,6 @@
package com.android.systemui.dreams;
-import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_ENABLED;
-
import android.service.dreams.DreamService;
import androidx.annotation.NonNull;
@@ -46,7 +44,6 @@ 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
@@ -103,7 +100,6 @@ public class DreamOverlayStateController implements
}
private final Executor mExecutor;
- private final boolean mOverlayEnabled;
private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
@Complication.ComplicationType
@@ -123,12 +119,10 @@ public class DreamOverlayStateController implements
@VisibleForTesting
@Inject
public DreamOverlayStateController(@Main Executor executor,
- @Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled,
FeatureFlags featureFlags,
@DreamLog LogBuffer logBuffer,
WeakReferenceFactory weakReferenceFactory) {
mExecutor = executor;
- mOverlayEnabled = overlayEnabled;
mLogger = new DreamLogger(logBuffer, TAG);
mFeatureFlags = featureFlags;
mWeakReferenceFactory = weakReferenceFactory;
@@ -138,18 +132,12 @@ public class DreamOverlayStateController implements
} else {
mSupportedTypes = Complication.COMPLICATION_TYPE_NONE;
}
- mLogger.logDreamOverlayEnabled(mOverlayEnabled);
}
/**
* Adds a complication to be included on the dream overlay.
*/
public void addComplication(Complication complication) {
- if (!mOverlayEnabled) {
- mLogger.logIgnoreAddComplication("overlay disabled", complication.toString());
- return;
- }
-
mExecutor.execute(() -> {
if (mComplications.add(complication)) {
mLogger.logAddComplication(complication.toString());
@@ -162,11 +150,6 @@ public class DreamOverlayStateController implements
* Removes a complication from inclusion on the dream overlay.
*/
public void removeComplication(Complication complication) {
- if (!mOverlayEnabled) {
- mLogger.logIgnoreRemoveComplication("overlay disabled", complication.toString());
- return;
- }
-
mExecutor.execute(() -> {
if (mComplications.remove(complication)) {
mLogger.logRemoveComplication(complication.toString());
@@ -264,7 +247,7 @@ public class DreamOverlayStateController implements
* @return {@code true} if overlay is active, {@code false} otherwise.
*/
public boolean isOverlayActive() {
- return mOverlayEnabled && containsState(STATE_DREAM_OVERLAY_ACTIVE);
+ return containsState(STATE_DREAM_OVERLAY_ACTIVE);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
index 8b6cc8cb4540..b37206a4fef7 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
@@ -16,17 +16,62 @@
package com.android.systemui.dreams.ui.viewmodel
+import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.shade.ui.viewmodel.dualShadeActions
+import com.android.systemui.shade.ui.viewmodel.singleShadeActions
+import com.android.systemui.shade.ui.viewmodel.splitShadeActions
+import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
/** Handles user input for the dream scene. */
-class DreamUserActionsViewModel @AssistedInject constructor() : UserActionsViewModel() {
+class DreamUserActionsViewModel
+@AssistedInject
+constructor(
+ private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
+ private val shadeInteractor: ShadeInteractor,
+) : UserActionsViewModel() {
override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
- setActions(emptyMap())
+ shadeInteractor.isShadeTouchable
+ .flatMapLatestConflated { isShadeTouchable ->
+ if (!isShadeTouchable) {
+ flowOf(emptyMap())
+ } else {
+ combine(
+ deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked },
+ shadeInteractor.shadeMode,
+ ) { isDeviceUnlocked, shadeMode ->
+ buildList {
+ add(Swipe.Start to Scenes.Communal)
+
+ val bouncerOrGone =
+ if (isDeviceUnlocked) Scenes.Gone else Scenes.Bouncer
+ add(Swipe.Up to bouncerOrGone)
+
+ addAll(
+ when (shadeMode) {
+ ShadeMode.Single -> singleShadeActions()
+ ShadeMode.Split -> splitShadeActions()
+ ShadeMode.Dual -> dualShadeActions()
+ }
+ )
+ }
+ .associate { it }
+ }
+ }
+ }
+ .collect { setActions(it) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
index ca43871415e6..25f99207ad28 100644
--- a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
@@ -27,7 +27,6 @@ import android.content.res.Resources
import android.content.res.Resources.NotFoundException
import android.graphics.Bitmap
import android.graphics.ImageDecoder
-import android.graphics.ImageDecoder.DecodeException
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
@@ -39,7 +38,6 @@ import com.android.app.tracing.traceSection
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import java.io.IOException
import javax.inject.Inject
import kotlin.math.min
import kotlinx.coroutines.CoroutineDispatcher
@@ -54,7 +52,7 @@ class ImageLoader
@Inject
constructor(
@Application private val defaultContext: Context,
- @Background private val backgroundDispatcher: CoroutineDispatcher
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
) {
/** Source of the image data. */
@@ -103,7 +101,7 @@ constructor(
source: Source,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Bitmap? =
withContext(backgroundDispatcher) { loadBitmapSync(source, maxWidth, maxHeight, allocator) }
@@ -127,14 +125,14 @@ constructor(
source: Source,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Bitmap? {
return try {
loadBitmapSync(
toImageDecoderSource(source, defaultContext),
maxWidth,
maxHeight,
- allocator
+ allocator,
)
} catch (e: NotFoundException) {
Log.w(TAG, "Couldn't load resource $source", e)
@@ -162,7 +160,7 @@ constructor(
source: ImageDecoder.Source,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Bitmap? =
traceSection("ImageLoader#loadBitmap") {
return try {
@@ -170,12 +168,11 @@ constructor(
configureDecoderForMaximumSize(decoder, info.size, maxWidth, maxHeight)
decoder.allocator = allocator
}
- } catch (e: IOException) {
+ } catch (e: Exception) {
+ // If we're loading an Uri, we can receive any exception from the other side.
+ // So we have to catch them all.
Log.w(TAG, "Failed to load source $source", e)
return null
- } catch (e: DecodeException) {
- Log.w(TAG, "Failed to decode source $source", e)
- return null
}
}
@@ -199,7 +196,7 @@ constructor(
source: Source,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Drawable? =
withContext(backgroundDispatcher) {
loadDrawableSync(source, maxWidth, maxHeight, allocator)
@@ -227,7 +224,7 @@ constructor(
context: Context = defaultContext,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Drawable? =
withContext(backgroundDispatcher) {
loadDrawableSync(icon, context, maxWidth, maxHeight, allocator)
@@ -254,7 +251,7 @@ constructor(
source: Source,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Drawable? =
traceSection("ImageLoader#loadDrawable") {
return try {
@@ -262,7 +259,7 @@ constructor(
toImageDecoderSource(source, defaultContext),
maxWidth,
maxHeight,
- allocator
+ allocator,
)
?:
// If we have a resource, retry fallback using the "normal" Resource loading
@@ -301,7 +298,7 @@ constructor(
source: ImageDecoder.Source,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Drawable? =
traceSection("ImageLoader#loadDrawable") {
return try {
@@ -309,12 +306,11 @@ constructor(
configureDecoderForMaximumSize(decoder, info.size, maxWidth, maxHeight)
decoder.allocator = allocator
}
- } catch (e: IOException) {
+ } catch (e: Exception) {
+ // If we're loading from an Uri, any exception can happen on the
+ // other side. We have to catch them all.
Log.w(TAG, "Failed to load source $source", e)
return null
- } catch (e: DecodeException) {
- Log.w(TAG, "Failed to decode source $source", e)
- return null
}
}
@@ -325,7 +321,7 @@ constructor(
context: Context = defaultContext,
@Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
@Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
- allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+ allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
): Drawable? =
traceSection("ImageLoader#loadDrawable") {
return when (icon.type) {
@@ -341,7 +337,7 @@ constructor(
ImageDecoder.createSource(it, icon.resId),
maxWidth,
maxHeight,
- allocator
+ allocator,
)
}
// Fallback to non-ImageDecoder load if the attempt failed (e.g. the
@@ -360,7 +356,7 @@ constructor(
ImageDecoder.createSource(icon.dataBytes, icon.dataOffset, icon.dataLength),
maxWidth,
maxHeight,
- allocator
+ allocator,
)
}
else -> {
@@ -421,12 +417,10 @@ constructor(
fun loadSizeSync(source: ImageDecoder.Source): Size? {
return try {
ImageDecoder.decodeHeader(source).size
- } catch (e: IOException) {
+ } catch (e: Exception) {
+ // Any exception can happen when loading Uris, so we have to catch them all.
Log.w(TAG, "Failed to load source $source", e)
return null
- } catch (e: DecodeException) {
- Log.w(TAG, "Failed to decode source $source", e)
- return null
}
}
@@ -472,7 +466,7 @@ constructor(
decoder: ImageDecoder,
imgSize: Size,
@Px maxWidth: Int,
- @Px maxHeight: Int
+ @Px maxHeight: Int,
) {
if (maxWidth == DO_NOT_RESIZE && maxHeight == DO_NOT_RESIZE) {
return
@@ -547,7 +541,7 @@ constructor(
pm.getApplicationInfo(
resPackage,
PackageManager.MATCH_UNINSTALLED_PACKAGES or
- PackageManager.GET_SHARED_LIBRARY_FILES
+ PackageManager.GET_SHARED_LIBRARY_FILES,
)
if (ai != null) {
return pm.getResourcesForApplication(ai)
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt
index ed7d1823648a..316964a47753 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt
@@ -83,9 +83,6 @@ constructor(
interactionState == TileInteractionState.LONG_CLICKED &&
animationState == TileAnimationState.ACTIVITY_LAUNCH ->
TileHapticsState.LONG_PRESS
- interactionState == TileInteractionState.LONG_CLICKED &&
- !tileViewModel.currentState.handlesLongClick ->
- TileHapticsState.FAILED_LONGPRESS
else -> TileHapticsState.NO_HAPTICS
}
}
@@ -102,7 +99,6 @@ constructor(
TileHapticsState.TOGGLE_ON -> MSDLToken.SWITCH_ON
TileHapticsState.TOGGLE_OFF -> MSDLToken.SWITCH_OFF
TileHapticsState.LONG_PRESS -> MSDLToken.LONG_PRESS
- TileHapticsState.FAILED_LONGPRESS -> MSDLToken.FAILURE
TileHapticsState.NO_HAPTICS -> null
}
tokenToPlay?.let {
@@ -154,7 +150,6 @@ constructor(
TOGGLE_ON,
TOGGLE_OFF,
LONG_PRESS,
- FAILED_LONGPRESS,
NO_HAPTICS,
}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
index 2e792497906e..b82aa817afd8 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
@@ -215,6 +215,21 @@ constructor(
return true
}
+ fun onTileLongClick(): Boolean {
+ if (state == State.IDLE) {
+ // This case represents a long-click detected outside of the QSLongPressEffect. This can
+ // be due to accessibility services
+ qsTile?.longClick(expandable)
+ logEvent(
+ qsTile?.tileSpec,
+ state,
+ "long click action triggered from OnLongClickListener",
+ )
+ return true
+ }
+ return false
+ }
+
/**
* Get the appropriate state for a click action.
*
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt
index 092a25aa1cad..7bd09b915d1a 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.os.Build
import android.os.UserHandle
import com.android.systemui.CoreStartable
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -52,13 +53,13 @@ constructor(
receiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
- applicationContext.startActivityAsUser(
- Intent(
- applicationContext,
- KeyboardTouchpadTutorialActivity::class.java
- ),
- UserHandle.SYSTEM
- )
+ val activityIntent =
+ Intent(applicationContext, KeyboardTouchpadTutorialActivity::class.java)
+ if (Build.IS_DEBUGGABLE) {
+ // helpful for testing different cases but pointless for public builds
+ intent.extras?.let { activityIntent.putExtras(it) }
+ }
+ applicationContext.startActivityAsUser(activityIntent, UserHandle.SYSTEM)
}
},
filter = IntentFilter("com.android.systemui.action.KEYBOARD_TOUCHPAD_TUTORIAL"),
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt
index 144c5ead1bb8..ae6cbbc4315e 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt
@@ -18,8 +18,8 @@ package com.android.systemui.inputdevice.tutorial
import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU
import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
import com.android.systemui.shared.system.SysUiStatsLog
import javax.inject.Inject
@@ -37,9 +37,9 @@ class KeyboardTouchpadTutorialMetricsLogger @Inject constructor() {
val tutorialType =
when (tutorialTypeExtra) {
- INTENT_TUTORIAL_TYPE_KEYBOARD ->
+ INTENT_TUTORIAL_SCOPE_KEYBOARD ->
SysUiStatsLog.PERIPHERAL_TUTORIAL_LAUNCHED__TUTORIAL_TYPE__KEYBOARD
- INTENT_TUTORIAL_TYPE_TOUCHPAD ->
+ INTENT_TUTORIAL_SCOPE_TOUCHPAD ->
SysUiStatsLog.PERIPHERAL_TUTORIAL_LAUNCHED__TUTORIAL_TYPE__TOUCHPAD
else -> SysUiStatsLog.PERIPHERAL_TUTORIAL_LAUNCHED__TUTORIAL_TYPE__BOTH
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
index 4a369e7e849e..7758dcc0fc88 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
@@ -17,12 +17,14 @@
package com.android.systemui.inputdevice.tutorial.domain.interactor
import android.os.SystemProperties
+import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType
import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType.KEYBOARD
import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType.TOUCHPAD
import com.android.systemui.inputdevice.tutorial.data.repository.TutorialSchedulerRepository
+import com.android.systemui.inputdevice.tutorial.domain.interactor.TutorialSchedulerInteractor.Companion.LAUNCH_DELAY
import com.android.systemui.keyboard.data.repository.KeyboardRepository
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
@@ -35,6 +37,7 @@ import kotlin.time.Duration.Companion.hours
import kotlin.time.toKotlinDuration
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
@@ -96,6 +99,9 @@ constructor(
private suspend fun waitForDeviceConnection(deviceType: DeviceType) =
isAnyDeviceConnected[deviceType]!!.filter { it }.first()
+ // Only for testing notifications. This should behave independently from scheduling
+ @VisibleForTesting val commandTutorials = MutableStateFlow(TutorialType.NONE)
+
// Merging two flows ensures that tutorial is launched consecutively to avoid race condition
val tutorials: Flow<TutorialType> =
merge(touchpadScheduleFlow, keyboardScheduleFlow).map {
@@ -146,6 +152,15 @@ constructor(
pw.println("Touchpad connect time = ${repo.firstConnectionTime(TOUCHPAD)}")
pw.println(" launch time = ${repo.launchTime(TOUCHPAD)}")
}
+ "notify" -> {
+ if (args.size != 2) help(pw)
+ when (args[1]) {
+ "keyboard" -> commandTutorials.value = TutorialType.KEYBOARD
+ "touchpad" -> commandTutorials.value = TutorialType.TOUCHPAD
+ "both" -> commandTutorials.value = TutorialType.BOTH
+ else -> help(pw)
+ }
+ }
else -> help(pw)
}
}
@@ -155,6 +170,7 @@ constructor(
pw.println("Available commands:")
pw.println(" clear")
pw.println(" info")
+ pw.println(" notify [keyboard|touchpad|both]")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt
index 3b26f2ff9deb..3cba70e39e66 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt
@@ -24,6 +24,7 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.core.app.NotificationCompat
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -33,15 +34,15 @@ import com.android.systemui.inputdevice.tutorial.domain.interactor.TutorialSched
import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity
import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_KEY
import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_BOTH
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_ALL
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
+import kotlinx.coroutines.flow.merge
/** When the scheduler is due, show a notification to launch tutorial */
@SysUISingleton
@@ -56,7 +57,11 @@ constructor(
) {
fun start() {
backgroundScope.launch {
- tutorialSchedulerInteractor.tutorials.collect { showNotification(it) }
+ merge(
+ tutorialSchedulerInteractor.tutorials,
+ tutorialSchedulerInteractor.commandTutorials,
+ )
+ .collect { showNotification(it) }
}
}
@@ -103,7 +108,7 @@ constructor(
private fun createPendingIntent(tutorialType: String): PendingIntent {
val intent =
Intent(context, KeyboardTouchpadTutorialActivity::class.java).apply {
- putExtra(INTENT_TUTORIAL_TYPE_KEY, tutorialType)
+ putExtra(INTENT_TUTORIAL_SCOPE_KEY, tutorialType)
putExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY, INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
@@ -123,13 +128,13 @@ constructor(
NotificationInfo(
context.getString(R.string.launch_keyboard_tutorial_notification_title),
context.getString(R.string.launch_keyboard_tutorial_notification_content),
- INTENT_TUTORIAL_TYPE_KEYBOARD,
+ INTENT_TUTORIAL_SCOPE_KEYBOARD,
)
TutorialType.TOUCHPAD ->
NotificationInfo(
context.getString(R.string.launch_touchpad_tutorial_notification_title),
context.getString(R.string.launch_touchpad_tutorial_notification_content),
- INTENT_TUTORIAL_TYPE_TOUCHPAD,
+ INTENT_TUTORIAL_SCOPE_TOUCHPAD,
)
TutorialType.BOTH ->
NotificationInfo(
@@ -139,7 +144,7 @@ constructor(
context.getString(
R.string.launch_keyboard_touchpad_tutorial_notification_content
),
- INTENT_TUTORIAL_TYPE_BOTH,
+ INTENT_TUTORIAL_SCOPE_ALL,
)
TutorialType.NONE -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
index fa494150cbbf..67b307fb7a36 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
@@ -27,6 +27,7 @@ import androidx.compose.runtime.getValue
import androidx.lifecycle.Lifecycle.State.STARTED
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.theme.PlatformTheme
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger.TutorialContext
@@ -40,7 +41,6 @@ import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTUR
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
import java.util.Optional
import javax.inject.Inject
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Activity for out of the box experience for keyboard and touchpad. Note that it's possible that
@@ -56,10 +56,13 @@ constructor(
) : ComponentActivity() {
companion object {
- const val INTENT_TUTORIAL_TYPE_KEY = "tutorial_type"
- const val INTENT_TUTORIAL_TYPE_TOUCHPAD = "touchpad"
- const val INTENT_TUTORIAL_TYPE_KEYBOARD = "keyboard"
- const val INTENT_TUTORIAL_TYPE_BOTH = "both"
+ const val INTENT_TUTORIAL_SCOPE_KEY = "tutorial_scope"
+ const val INTENT_TUTORIAL_SCOPE_TOUCHPAD = "touchpad"
+ const val INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK = "touchpad_back"
+ const val INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME = "touchpad_home"
+ const val INTENT_TUTORIAL_SCOPE_KEYBOARD = "keyboard"
+ const val INTENT_TUTORIAL_SCOPE_ALL = "all"
+
const val INTENT_TUTORIAL_ENTRY_POINT_KEY = "entry_point"
const val INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER = "scheduler"
const val INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU = "contextual_edu"
@@ -90,10 +93,11 @@ constructor(
setContent {
PlatformTheme { KeyboardTouchpadTutorialContainer(vm, touchpadTutorialScreensProvider) }
}
+ // TODO(b/376692701): Update launchTime when the activity is launched by Companion App
if (savedInstanceState == null) {
metricsLogger.logPeripheralTutorialLaunched(
intent.getStringExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY),
- intent.getStringExtra(INTENT_TUTORIAL_TYPE_KEY),
+ intent.getStringExtra(INTENT_TUTORIAL_SCOPE_KEY),
)
logger.logOpenTutorial(TutorialContext.KEYBOARD_TOUCHPAD_TUTORIAL)
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
index 896bdc068154..eeb4b697a5fc 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
@@ -22,15 +22,21 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.domain.interactor.ConnectionState
import com.android.systemui.inputdevice.tutorial.domain.interactor.KeyboardTouchpadConnectionInteractor
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_ALL
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.RequiredHardware.KEYBOARD
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.RequiredHardware.TOUCHPAD
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -42,27 +48,23 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.runningFold
-import com.android.app.tracing.coroutines.launchTraced as launch
class KeyboardTouchpadTutorialViewModel(
private val gesturesInteractor: Optional<TouchpadGesturesInteractor>,
private val keyboardTouchpadConnectionInteractor: KeyboardTouchpadConnectionInteractor,
private val hasTouchpadTutorialScreens: Boolean,
private val logger: InputDeviceTutorialLogger,
- handle: SavedStateHandle
+ handle: SavedStateHandle,
) : ViewModel(), DefaultLifecycleObserver {
- private fun startingScreen(handle: SavedStateHandle): Screen {
- val tutorialType: String? = handle[INTENT_TUTORIAL_TYPE_KEY]
- return if (tutorialType == INTENT_TUTORIAL_TYPE_KEYBOARD) ACTION_KEY else BACK_GESTURE
- }
-
private val _screen = MutableStateFlow(startingScreen(handle))
val screen: Flow<Screen> = _screen.filter { it.canBeShown() }
private val _closeActivity: MutableStateFlow<Boolean> = MutableStateFlow(false)
val closeActivity: StateFlow<Boolean> = _closeActivity
+ private val screenSequence: ScreenSequence = chooseScreenSequence(handle)
+
private val screensBackStack = ArrayDeque(listOf(_screen.value))
private var connectionState: ConnectionState =
@@ -105,6 +107,33 @@ class KeyboardTouchpadTutorialViewModel(
}
}
+ private fun startingScreen(handle: SavedStateHandle): Screen {
+ val scope: String? = handle[INTENT_TUTORIAL_SCOPE_KEY]
+ return when (scope) {
+ INTENT_TUTORIAL_SCOPE_KEYBOARD -> ACTION_KEY
+ INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME -> HOME_GESTURE
+ INTENT_TUTORIAL_SCOPE_TOUCHPAD,
+ INTENT_TUTORIAL_SCOPE_ALL,
+ INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK -> BACK_GESTURE
+ else -> {
+ logger.w("Intent didn't specify tutorial scope, starting with default")
+ BACK_GESTURE
+ }
+ }
+ }
+
+ private fun chooseScreenSequence(handle: SavedStateHandle): ScreenSequence {
+ val scope: String? = handle[INTENT_TUTORIAL_SCOPE_KEY]
+ return if (
+ scope == INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME ||
+ scope == INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
+ ) {
+ SingleScreenOnly
+ } else {
+ AllSupportedScreens
+ }
+ }
+
override fun onCleared() {
// this shouldn't be needed as onTutorialInvisible should already clear device state but
// it'd be really bad if we'd block gestures/shortcuts after leaving tutorial so just to be
@@ -121,13 +150,13 @@ class KeyboardTouchpadTutorialViewModel(
}
fun onDoneButtonClicked() {
- var nextScreen = _screen.value.next()
+ var nextScreen = screenSequence.nextScreen(_screen.value)
while (nextScreen != null) {
if (requiredHardwarePresent(nextScreen)) {
break
}
logger.logNextScreenMissingHardware(nextScreen)
- nextScreen = nextScreen.next()
+ nextScreen = screenSequence.nextScreen(nextScreen)
}
if (nextScreen == null) {
logger.d("Final screen reached, closing tutorial")
@@ -192,33 +221,44 @@ class KeyboardTouchpadTutorialViewModel(
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
- handle: SavedStateHandle
+ handle: SavedStateHandle,
): T =
KeyboardTouchpadTutorialViewModel(
gesturesInteractor,
keyboardTouchpadConnected,
hasTouchpadTutorialScreens,
logger,
- handle
+ handle,
)
as T
}
+
+ private interface ScreenSequence {
+ fun nextScreen(current: Screen): Screen?
+ }
+
+ private object AllSupportedScreens : ScreenSequence {
+ override fun nextScreen(current: Screen): Screen? {
+ return when (current) {
+ BACK_GESTURE -> HOME_GESTURE
+ HOME_GESTURE -> ACTION_KEY
+ ACTION_KEY -> null
+ }
+ }
+ }
+
+ private object SingleScreenOnly : ScreenSequence {
+ override fun nextScreen(current: Screen): Screen? = null
+ }
}
enum class RequiredHardware {
TOUCHPAD,
- KEYBOARD
+ KEYBOARD,
}
enum class Screen(val requiredHardware: RequiredHardware) {
BACK_GESTURE(requiredHardware = TOUCHPAD),
HOME_GESTURE(requiredHardware = TOUCHPAD),
- ACTION_KEY(requiredHardware = KEYBOARD);
-
- fun next(): Screen? =
- when (this) {
- BACK_GESTURE -> HOME_GESTURE
- HOME_GESTURE -> ACTION_KEY
- ACTION_KEY -> null
- }
+ ACTION_KEY(requiredHardware = KEYBOARD),
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/ShortcutCustomizationRequestResult.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/ShortcutCustomizationRequestResult.kt
new file mode 100644
index 000000000000..bb563b1f6561
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/ShortcutCustomizationRequestResult.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.keyboard.shared.model
+
+enum class ShortcutCustomizationRequestResult {
+ SUCCESS,
+ ERROR_RESERVED_COMBINATION,
+ ERROR_OTHER,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
index 7b3380a6a608..1af7340ad7b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
@@ -18,6 +18,9 @@ package com.android.systemui.keyboard.shortcut
import com.android.systemui.CoreStartable
import com.android.systemui.Flags.keyboardShortcutHelperRewrite
+import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
import com.android.systemui.keyboard.shortcut.data.source.AppCategoriesShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.CurrentAppShortcutsSource
@@ -27,6 +30,8 @@ import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsS
import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource
import com.android.systemui.keyboard.shortcut.qualifiers.AppCategoriesShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.CurrentAppShortcuts
+import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories
+import com.android.systemui.keyboard.shortcut.qualifiers.DefaultShortcutCategories
import com.android.systemui.keyboard.shortcut.qualifiers.InputShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.MultitaskingShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.SystemShortcuts
@@ -63,6 +68,18 @@ interface ShortcutHelperModule {
impl: AppCategoriesShortcutsSource
): KeyboardShortcutGroupsSource
+ @Binds
+ @DefaultShortcutCategories
+ fun defaultShortcutCategoriesRepository(
+ impl: DefaultShortcutCategoriesRepository
+ ): ShortcutCategoriesRepository
+
+ @Binds
+ @CustomShortcutCategories
+ fun customShortcutCategoriesRepository(
+ impl: CustomShortcutCategoriesRepository
+ ): ShortcutCategoriesRepository
+
companion object {
@Provides
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
index 7f8fbb5065aa..99cafd3daacb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
@@ -19,26 +19,41 @@ package com.android.systemui.keyboard.shortcut.data.repository
import android.content.Context
import android.content.Context.INPUT_SERVICE
import android.hardware.input.InputGestureData
+import android.hardware.input.InputGestureData.Builder
import android.hardware.input.InputGestureData.KeyTrigger
+import android.hardware.input.InputGestureData.createKeyTrigger
import android.hardware.input.InputManager
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS
import android.hardware.input.InputSettings
import android.hardware.input.KeyGestureEvent
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.compose.runtime.mutableStateOf
+import com.android.systemui.Flags.shortcutHelperKeyGlyph
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup
import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.settings.UserTracker
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
@SysUISingleton
class CustomShortcutCategoriesRepository
@@ -47,8 +62,10 @@ constructor(
stateRepository: ShortcutHelperStateRepository,
private val userTracker: UserTracker,
@Background private val backgroundScope: CoroutineScope,
- @Background private val backgroundDispatcher: CoroutineDispatcher,
+ @Background private val bgCoroutineContext: CoroutineContext,
private val shortcutCategoriesUtils: ShortcutCategoriesUtils,
+ private val context: Context,
+ private val inputGestureMaps: InputGestureMaps
) : ShortcutCategoriesRepository {
private val userContext: Context
@@ -59,15 +76,53 @@ constructor(
private val inputManager: InputManager
get() = userContext.getSystemService(INPUT_SERVICE) as InputManager
+ private val _selectedKeyCombination = MutableStateFlow<KeyCombination?>(null)
+ private val _shortcutBeingCustomized = mutableStateOf<ShortcutCustomizationRequestInfo?>(null)
+
private val activeInputDevice =
stateRepository.state.map {
if (it is Active) {
- withContext(backgroundDispatcher) { inputManager.getInputDevice(it.deviceId) }
+ withContext(bgCoroutineContext) { inputManager.getInputDevice(it.deviceId) }
} else {
null
}
}
+ val pressedKeys =
+ _selectedKeyCombination
+ .combine(activeInputDevice) { keyCombination, inputDevice ->
+ if (inputDevice == null || keyCombination == null) {
+ return@combine emptyList()
+ } else {
+ val keyGlyphMap =
+ if (shortcutHelperKeyGlyph()) {
+ inputManager.getKeyGlyphMap(inputDevice.id)
+ } else null
+ val modifiers =
+ shortcutCategoriesUtils.toShortcutModifierKeys(
+ keyCombination.modifiers,
+ keyGlyphMap,
+ )
+ val triggerKey =
+ keyCombination.keyCode?.let {
+ shortcutCategoriesUtils.toShortcutKey(
+ keyGlyphMap,
+ inputDevice.keyCharacterMap,
+ keyCode = it,
+ )
+ }
+ val keys = mutableListOf<ShortcutKey>()
+ modifiers?.let { keys += it }
+ triggerKey?.let { keys += it }
+ return@combine keys
+ }
+ }
+ .stateIn(
+ scope = backgroundScope,
+ started = SharingStarted.Lazily,
+ initialValue = emptyList(),
+ )
+
override val categories: Flow<List<ShortcutCategory>> =
activeInputDevice
.map { inputDevice ->
@@ -103,6 +158,96 @@ constructor(
started = SharingStarted.Lazily,
)
+ fun updateUserKeyCombination(keyCombination: KeyCombination?) {
+ _selectedKeyCombination.value = keyCombination
+ }
+
+ fun onCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo?) {
+ _shortcutBeingCustomized.value = requestInfo
+ }
+
+ @VisibleForTesting
+ fun buildInputGestureDataForShortcutBeingCustomized(): InputGestureData? {
+ try {
+ return Builder()
+ .addKeyGestureTypeFromShortcutLabel()
+ .addTriggerFromSelectedKeyCombination()
+ .build()
+ // TODO(b/379648200) add app launch data for application categories shortcut after
+ // dynamic
+ // label/icon mapping implementation
+ } catch (e: IllegalArgumentException) {
+ Log.w(TAG, "could not add custom shortcut: $e")
+ return null
+ }
+ }
+
+ suspend fun confirmAndSetShortcutCurrentlyBeingCustomized(): ShortcutCustomizationRequestResult {
+ return withContext(bgCoroutineContext) {
+ val inputGestureData =
+ buildInputGestureDataForShortcutBeingCustomized()
+ ?: return@withContext ShortcutCustomizationRequestResult.ERROR_OTHER
+
+ return@withContext when (inputManager.addCustomInputGesture(inputGestureData)) {
+ CUSTOM_INPUT_GESTURE_RESULT_SUCCESS -> ShortcutCustomizationRequestResult.SUCCESS
+ CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS ->
+ ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION
+
+ CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE ->
+ ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION
+
+ else -> ShortcutCustomizationRequestResult.ERROR_OTHER
+ }
+ }
+ }
+
+ private fun Builder.addKeyGestureTypeFromShortcutLabel(): Builder {
+ val shortcutBeingCustomized =
+ getShortcutBeingCustomized() as? ShortcutCustomizationRequestInfo.Add
+
+ if (shortcutBeingCustomized == null) {
+ Log.w(TAG, "User requested to set shortcut but shortcut being customized is null")
+ return this
+ }
+
+ val keyGestureType =
+ inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label]
+
+ if (keyGestureType == null) {
+ Log.w(TAG, "Could not find KeyGestureType for shortcut $shortcutBeingCustomized")
+ return this
+ }
+
+ return setKeyGestureType(keyGestureType)
+ }
+
+ private fun Builder.addTriggerFromSelectedKeyCombination(): Builder {
+ val selectedKeyCombination = _selectedKeyCombination.value
+ if (selectedKeyCombination?.keyCode == null) {
+ Log.w(
+ TAG,
+ "User requested to set shortcut but selected key combination is " +
+ "$selectedKeyCombination",
+ )
+ return this
+ }
+
+ return setTrigger(
+ createKeyTrigger(
+ /* keycode = */ selectedKeyCombination.keyCode,
+ /* modifierState = */
+ shortcutCategoriesUtils.removeUnsupportedModifiers(
+ selectedKeyCombination.modifiers
+ ),
+ )
+ )
+ }
+
+ @VisibleForTesting
+ fun getShortcutBeingCustomized(): ShortcutCustomizationRequestInfo? {
+ return _shortcutBeingCustomized.value
+ }
+
private fun toInternalGroupSources(
inputGestures: List<InputGestureData>
): List<InternalGroupsSource> {
@@ -111,8 +256,10 @@ constructor(
val keyTrigger = gestureData.trigger as KeyTrigger
val keyGestureType = gestureData.action.keyGestureType()
fetchGroupLabelByGestureType(keyGestureType)?.let { groupLabel ->
- toInternalKeyboardShortcutInfo(keyGestureType, keyTrigger)?.let {
- internalKeyboardShortcutInfo ->
+ toInternalKeyboardShortcutInfo(
+ keyGestureType,
+ keyTrigger
+ )?.let { internalKeyboardShortcutInfo ->
val group =
InternalKeyboardShortcutGroup(
label = groupLabel,
@@ -147,29 +294,31 @@ constructor(
private fun fetchGroupLabelByGestureType(
@KeyGestureEvent.KeyGestureType keyGestureType: Int
): String? {
- return InputGestures.gestureToInternalKeyboardShortcutGroupLabelMap.getOrDefault(
- keyGestureType,
- null,
- )
+ inputGestureMaps.gestureToInternalKeyboardShortcutGroupLabelResIdMap[keyGestureType]?.let {
+ return context.getString(it)
+ } ?: return null
}
private fun fetchShortcutInfoLabelByGestureType(
@KeyGestureEvent.KeyGestureType keyGestureType: Int
): String? {
- return InputGestures.gestureToInternalKeyboardShortcutInfoLabelMap.getOrDefault(
- keyGestureType,
- null,
- )
+ inputGestureMaps.gestureToInternalKeyboardShortcutInfoLabelResIdMap[keyGestureType]?.let {
+ return context.getString(it)
+ } ?: return null
}
private fun fetchShortcutCategoryTypeByGestureType(
@KeyGestureEvent.KeyGestureType keyGestureType: Int
): ShortcutCategoryType? {
- return InputGestures.gestureToShortcutCategoryTypeMap.getOrDefault(keyGestureType, null)
+ return inputGestureMaps.gestureToShortcutCategoryTypeMap[keyGestureType]
}
private data class InternalGroupsSource(
val groups: List<InternalKeyboardShortcutGroup>,
val type: ShortcutCategoryType,
)
+
+ private companion object {
+ private const val TAG = "CustomShortcutCategoriesRepository"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
new file mode 100644
index 000000000000..d228a15e51b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2024 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.keyboard.shortcut.data.repository
+
+import android.content.Context
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_BACK
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+class InputGestureMaps
+@Inject
+constructor(private val context: Context) {
+ val gestureToShortcutCategoryTypeMap =
+ mapOf(
+ // System Category
+ KEY_GESTURE_TYPE_HOME to System,
+ KEY_GESTURE_TYPE_RECENT_APPS to System,
+ KEY_GESTURE_TYPE_BACK to System,
+ KEY_GESTURE_TYPE_TAKE_SCREENSHOT to System,
+ KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to System,
+ KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to System,
+ KEY_GESTURE_TYPE_LOCK_SCREEN to System,
+ KEY_GESTURE_TYPE_OPEN_NOTES to System,
+ KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to System,
+ KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to System,
+ KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to System,
+ KEY_GESTURE_TYPE_ALL_APPS to System,
+
+ // Multitasking Category
+ KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to MultiTasking,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to MultiTasking,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to MultiTasking,
+ KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to MultiTasking,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to MultiTasking,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to MultiTasking,
+
+ // App Category
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to AppCategories,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to AppCategories,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to AppCategories,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to AppCategories,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to AppCategories,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to AppCategories,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to AppCategories,
+ )
+
+ val gestureToInternalKeyboardShortcutGroupLabelResIdMap =
+ mapOf(
+ // System Category
+ KEY_GESTURE_TYPE_HOME to R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_RECENT_APPS to R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_BACK to R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_TAKE_SCREENSHOT to R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to
+ R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to
+ R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_ALL_APPS to R.string.shortcut_helper_category_system_controls,
+ KEY_GESTURE_TYPE_OPEN_NOTES to R.string.shortcut_helper_category_system_apps,
+ KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to
+ R.string.shortcut_helper_category_system_apps,
+ KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.shortcut_helper_category_system_apps,
+ KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to
+ R.string.shortcut_helper_category_system_apps,
+
+ // Multitasking Category
+ KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to R.string.shortcutHelper_category_recent_apps,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to
+ R.string.shortcutHelper_category_split_screen,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to
+ R.string.shortcutHelper_category_split_screen,
+ KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to
+ R.string.shortcutHelper_category_split_screen,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to
+ R.string.shortcutHelper_category_split_screen,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to
+ R.string.shortcutHelper_category_split_screen,
+
+ // App Category
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to
+ R.string.keyboard_shortcut_group_applications,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to
+ R.string.keyboard_shortcut_group_applications,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to
+ R.string.keyboard_shortcut_group_applications,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to
+ R.string.keyboard_shortcut_group_applications,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to R.string.keyboard_shortcut_group_applications,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to R.string.keyboard_shortcut_group_applications,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to
+ R.string.keyboard_shortcut_group_applications,
+ )
+
+ val gestureToInternalKeyboardShortcutInfoLabelResIdMap =
+ mapOf(
+ // System Category
+ KEY_GESTURE_TYPE_HOME to R.string.group_system_access_home_screen,
+ KEY_GESTURE_TYPE_RECENT_APPS to R.string.group_system_overview_open_apps,
+ KEY_GESTURE_TYPE_BACK to R.string.group_system_go_back,
+ KEY_GESTURE_TYPE_TAKE_SCREENSHOT to R.string.group_system_full_screenshot,
+ KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to
+ R.string.group_system_access_system_app_shortcuts,
+ KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to
+ R.string.group_system_access_notification_shade,
+ KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.group_system_lock_screen,
+ KEY_GESTURE_TYPE_ALL_APPS to R.string.group_system_access_all_apps_search,
+ KEY_GESTURE_TYPE_OPEN_NOTES to R.string.group_system_quick_memo,
+ KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to R.string.group_system_access_system_settings,
+ KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.group_system_access_google_assistant,
+ KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to
+ R.string.group_system_access_google_assistant,
+
+ // Multitasking Category
+ KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to R.string.group_system_cycle_forward,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to R.string.system_multitasking_lhs,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to R.string.system_multitasking_rhs,
+ KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to R.string.system_multitasking_full_screen,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to
+ R.string.system_multitasking_splitscreen_focus_lhs,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to
+ R.string.system_multitasking_splitscreen_focus_rhs,
+
+ // App Category
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to
+ R.string.keyboard_shortcut_group_applications_calculator,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to
+ R.string.keyboard_shortcut_group_applications_calendar,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to
+ R.string.keyboard_shortcut_group_applications_browser,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to
+ R.string.keyboard_shortcut_group_applications_contacts,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to
+ R.string.keyboard_shortcut_group_applications_email,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to
+ R.string.keyboard_shortcut_group_applications_maps,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to
+ R.string.keyboard_shortcut_group_applications_sms,
+ )
+
+ val shortcutLabelToKeyGestureTypeMap: Map<String, Int>
+ get() = gestureToInternalKeyboardShortcutInfoLabelResIdMap.entries.associateBy({
+ context.getString(it.value)
+ }) {
+ it.key
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt
deleted file mode 100644
index 28134db4d588..000000000000
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2024 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.keyboard.shortcut.data.repository
-
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_BACK
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_HOME
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
-
-object InputGestures {
- val gestureToShortcutCategoryTypeMap =
- mapOf(
- // System Category
- KEY_GESTURE_TYPE_HOME to System,
- KEY_GESTURE_TYPE_RECENT_APPS to System,
- KEY_GESTURE_TYPE_BACK to System,
- KEY_GESTURE_TYPE_TAKE_SCREENSHOT to System,
- KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to System,
- KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to System,
- KEY_GESTURE_TYPE_LOCK_SCREEN to System,
- KEY_GESTURE_TYPE_OPEN_NOTES to System,
- KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to System,
- KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to System,
- KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to System,
- KEY_GESTURE_TYPE_ALL_APPS to System,
-
- // Multitasking Category
- KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to MultiTasking,
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to MultiTasking,
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to MultiTasking,
- KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to MultiTasking,
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to MultiTasking,
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to MultiTasking,
-
- // App Category
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to AppCategories,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to AppCategories,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to AppCategories,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to AppCategories,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to AppCategories,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to AppCategories,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to AppCategories,
- )
-
- // TODO move all string to to resources use the same resources as the original shortcuts
- // - that way when the strings are translated there are no discrepancies
- val gestureToInternalKeyboardShortcutGroupLabelMap =
- mapOf(
- // System Category
- KEY_GESTURE_TYPE_HOME to "System controls",
- KEY_GESTURE_TYPE_RECENT_APPS to "System controls",
- KEY_GESTURE_TYPE_BACK to "System controls",
- KEY_GESTURE_TYPE_TAKE_SCREENSHOT to "System controls",
- KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to "System controls",
- KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to "System controls",
- KEY_GESTURE_TYPE_LOCK_SCREEN to "System controls",
- KEY_GESTURE_TYPE_ALL_APPS to "System controls",
- KEY_GESTURE_TYPE_OPEN_NOTES to "System apps",
- KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to "System apps",
- KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to "System apps",
- KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to "System apps",
-
- // Multitasking Category
- KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to "Recent apps",
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to "Split screen",
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to "Split screen",
- KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to "Split screen",
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to "Split screen",
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to "Split screen",
-
- // App Category
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to "Applications",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to "Applications",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to "Applications",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to "Applications",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to "Applications",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to "Applications",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to "Applications",
- )
-
- val gestureToInternalKeyboardShortcutInfoLabelMap =
- mapOf(
- // System Category
- KEY_GESTURE_TYPE_HOME to "Go to home screen",
- KEY_GESTURE_TYPE_RECENT_APPS to "View recent apps",
- KEY_GESTURE_TYPE_BACK to "Go back",
- KEY_GESTURE_TYPE_TAKE_SCREENSHOT to "Take screenshot",
- KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to "Show shortcuts",
- KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to "View notifications",
- KEY_GESTURE_TYPE_LOCK_SCREEN to "Lock screen",
- KEY_GESTURE_TYPE_ALL_APPS to "Open apps list",
- KEY_GESTURE_TYPE_OPEN_NOTES to "Take a note",
- KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to "Open settings",
- KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to "Open assistant",
- KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to "Open assistant",
-
- // Multitasking Category
- KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to "Cycle forward through recent apps",
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to
- "Use split screen with current app on the left",
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to
- "Use split screen with current app on the right",
- KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to "Switch from split screen to full screen",
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to
- "Switch to app on left or above while using split screen",
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to
- "Switch to app on right or below while using split screen",
-
- // App Category
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to "Calculator",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to "Calendar",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to "Chrome",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to "Contacts",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to "Gmail",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to "Maps",
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to "Messages",
- )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
index 899fd15d6115..95bc9f66618c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
@@ -24,6 +24,7 @@ import android.util.Log
import android.view.InputDevice
import android.view.KeyCharacterMap
import android.view.KeyEvent
+import android.view.KeyEvent.META_META_ON
import com.android.systemui.Flags.shortcutHelperKeyGlyph
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup
@@ -35,9 +36,9 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutIcon
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
+import kotlinx.coroutines.withContext
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
-import kotlinx.coroutines.withContext
class ShortcutCategoriesUtils
@Inject
@@ -46,6 +47,11 @@ constructor(
@Background private val backgroundCoroutineContext: CoroutineContext,
private val inputManager: InputManager,
) {
+
+ fun removeUnsupportedModifiers(modifierMask: Int): Int {
+ return SUPPORTED_MODIFIERS.reduce { acc, modifier -> acc or modifier } and modifierMask
+ }
+
fun fetchShortcutCategory(
type: ShortcutCategoryType?,
groups: List<InternalKeyboardShortcutGroup>,
@@ -92,7 +98,7 @@ constructor(
}
.filter { it.shortcuts.isNotEmpty() }
return if (subCategories.isEmpty()) {
- Log.wtf(TAG, "Empty sub categories after converting $shortcutGroups")
+ Log.w(TAG, "Empty sub categories after converting $shortcutGroups")
null
} else {
ShortcutCategory(type, subCategories)
@@ -161,7 +167,7 @@ constructor(
}
if (remainingModifiers != 0) {
// There is a remaining modifier we don't support
- Log.wtf(TAG, "Unsupported modifiers remaining: $remainingModifiers")
+ Log.w(TAG, "Unsupported modifiers remaining: $remainingModifiers")
return null
}
if (info.keycode != 0 || info.baseCharacter > Char.MIN_VALUE) {
@@ -170,21 +176,32 @@ constructor(
?: return null
}
if (keys.isEmpty()) {
- Log.wtf(TAG, "No keys for $info")
+ Log.w(TAG, "No keys for $info")
return null
}
return ShortcutCommand(keys = keys, isCustom = info.isCustomShortcut)
}
+ fun toShortcutModifierKeys(modifiers: Int, keyGlyphMap: KeyGlyphMap?): List<ShortcutKey>? {
+ val keys: MutableList<ShortcutKey> = mutableListOf()
+ var remainingModifiers = modifiers
+ SUPPORTED_MODIFIERS.forEach { supportedModifier ->
+ if ((supportedModifier and remainingModifiers) != 0) {
+ keys += toShortcutModifierKey(keyGlyphMap, supportedModifier) ?: return null
+ remainingModifiers = remainingModifiers and supportedModifier.inv()
+ }
+ }
+ return keys
+ }
+
private fun toShortcutModifierKey(keyGlyphMap: KeyGlyphMap?, modifierMask: Int): ShortcutKey? {
val modifierDrawable = keyGlyphMap?.getDrawableForModifierState(context, modifierMask)
if (modifierDrawable != null) {
return ShortcutKey.Icon.DrawableIcon(drawable = modifierDrawable)
}
- val iconResId = ShortcutHelperKeys.keyIcons[modifierMask]
- if (iconResId != null) {
- return ShortcutKey.Icon.ResIdIcon(iconResId)
+ if (modifierMask == META_META_ON) {
+ return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.metaModifierIconResId)
}
val modifierLabel = ShortcutHelperKeys.modifierLabels[modifierMask]
@@ -195,7 +212,7 @@ constructor(
return null
}
- private fun toShortcutKey(
+ fun toShortcutKey(
keyGlyphMap: KeyGlyphMap?,
keyCharacterMap: KeyCharacterMap,
keyCode: Int,
@@ -222,7 +239,7 @@ constructor(
if (displayLabelCharacter.code != 0) {
return ShortcutKey.Text(displayLabelCharacter.toString())
}
- Log.wtf(TAG, "Couldn't find label or icon for key: $keyCode")
+ Log.w(TAG, "Couldn't find label or icon for key: $keyCode")
return null
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
index 288efa275219..e47b33f8c37c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
@@ -116,9 +116,10 @@ import com.android.systemui.res.R
object ShortcutHelperKeys {
+ val metaModifierIconResId = R.drawable.ic_ksh_key_meta
+
val keyIcons =
mapOf(
- META_META_ON to R.drawable.ic_ksh_key_meta,
KEYCODE_BACK to R.drawable.ic_arrow_back_2,
KEYCODE_HOME to R.drawable.ic_radio_button_unchecked,
KEYCODE_RECENT_APPS to R.drawable.ic_check_box_outline_blank,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
index 85d22144f201..f4e2f05379bb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
@@ -16,13 +16,32 @@
package com.android.systemui.keyboard.shortcut.domain.interactor
-import android.view.KeyEvent.META_META_ON
+import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
+import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import javax.inject.Inject
-class ShortcutCustomizationInteractor @Inject constructor() {
+class ShortcutCustomizationInteractor
+@Inject
+constructor(private val customShortcutRepository: CustomShortcutCategoriesRepository) {
+ val pressedKeys = customShortcutRepository.pressedKeys
+
+ fun updateUserSelectedKeyCombination(keyCombination: KeyCombination?) {
+ customShortcutRepository.updateUserKeyCombination(keyCombination)
+ }
+
fun getDefaultCustomShortcutModifierKey(): ShortcutKey.Icon.ResIdIcon {
- return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.keyIcons[META_META_ON]!!)
+ return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.metaModifierIconResId)
+ }
+
+ fun onCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo?) {
+ customShortcutRepository.onCustomizationRequested(requestInfo)
+ }
+
+ suspend fun confirmAndSetShortcutCurrentlyBeingCustomized(): ShortcutCustomizationRequestResult {
+ return customShortcutRepository.confirmAndSetShortcutCurrentlyBeingCustomized()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
index 39fc27d35082..0381eaec5026 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
@@ -16,37 +16,66 @@
package com.android.systemui.keyboard.shortcut.domain.interactor
+import com.android.systemui.Flags.keyboardShortcutHelperShortcutCustomizer
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories
+import com.android.systemui.keyboard.shortcut.qualifiers.DefaultShortcutCategories
import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
@SysUISingleton
class ShortcutHelperCategoriesInteractor
@Inject
-constructor(categoriesRepository: DefaultShortcutCategoriesRepository) {
-
+constructor(
+ @DefaultShortcutCategories defaultCategoriesRepository: ShortcutCategoriesRepository,
+ @CustomShortcutCategories customCategoriesRepositoryLazy: Lazy<ShortcutCategoriesRepository>,
+) {
val shortcutCategories: Flow<List<ShortcutCategory>> =
- categoriesRepository.categories.map { categories ->
- categories.map { category -> groupSubCategoriesInCategory(category) }
+ defaultCategoriesRepository.categories.combine(
+ if (keyboardShortcutHelperShortcutCustomizer()) {
+ customCategoriesRepositoryLazy.get().categories
+ } else {
+ flowOf(emptyList())
+ }
+ ) { defaultShortcutCategories, customShortcutCategories ->
+ groupCategories(defaultShortcutCategories + customShortcutCategories)
}
- private fun groupSubCategoriesInCategory(shortcutCategory: ShortcutCategory): ShortcutCategory {
- val subCategoriesWithGroupedShortcuts =
- shortcutCategory.subCategories.map {
+ private fun groupCategories(
+ shortcutCategories: List<ShortcutCategory>
+ ): List<ShortcutCategory> {
+ return shortcutCategories
+ .groupBy { it.type }
+ .entries
+ .map { (categoryType, groupedCategories) ->
+ ShortcutCategory(
+ type = categoryType,
+ subCategories =
+ groupSubCategories(groupedCategories.flatMap { it.subCategories }),
+ )
+ }
+ }
+
+ private fun groupSubCategories(
+ subCategories: List<ShortcutSubCategory>
+ ): List<ShortcutSubCategory> {
+ return subCategories
+ .groupBy { it.label }
+ .entries
+ .map { (label, groupedSubcategories) ->
ShortcutSubCategory(
- label = it.label,
- shortcuts = groupShortcutsInSubcategory(it.shortcuts),
+ label = label,
+ shortcuts =
+ groupShortcutsInSubcategory(groupedSubcategories.flatMap { it.shortcuts }),
)
}
- return ShortcutCategory(
- type = shortcutCategory.type,
- subCategories = subCategoriesWithGroupedShortcuts,
- )
}
private fun groupShortcutsInSubcategory(shortcuts: List<Shortcut>) =
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CustomShortcutCategories.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CustomShortcutCategories.kt
new file mode 100644
index 000000000000..8acb9eebbd4d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CustomShortcutCategories.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 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.keyboard.shortcut.qualifiers
+
+import javax.inject.Qualifier
+
+@Qualifier annotation class CustomShortcutCategories
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/DefaultShortcutCategories.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/DefaultShortcutCategories.kt
new file mode 100644
index 000000000000..f94e10d17964
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/DefaultShortcutCategories.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 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.keyboard.shortcut.qualifiers
+
+import javax.inject.Qualifier
+
+@Qualifier annotation class DefaultShortcutCategories
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/KeyCombination.kt
index e4ccc2c553fa..5e4031b29502 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/KeyCombination.kt
@@ -16,8 +16,4 @@
package com.android.systemui.keyboard.shortcut.shared.model
-data class ShortcutInfo(
- val label: String,
- val categoryType: ShortcutCategoryType,
- val subCategoryLabel: String,
-)
+data class KeyCombination(val modifiers: Int, val keyCode: Int?)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
index 5f8570cba7a6..bf7df7ef8561 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
@@ -20,7 +20,9 @@ data class Shortcut(
val label: String,
val commands: List<ShortcutCommand>,
val icon: ShortcutIcon? = null,
-)
+) {
+ val containsCustomShortcutCommands: Boolean = commands.any { it.isCustom }
+}
class ShortcutBuilder(private val label: String) {
val commands = mutableListOf<ShortcutCommand>()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
new file mode 100644
index 000000000000..2d3e7f6f6448
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.keyboard.shortcut.shared.model
+
+sealed interface ShortcutCustomizationRequestInfo {
+ data class Add(
+ val label: String = "",
+ val categoryType: ShortcutCategoryType = ShortcutCategoryType.System,
+ val subCategoryLabel: String = "",
+ ) : ShortcutCustomizationRequestInfo
+
+ data class Delete(
+ val label: String = "",
+ val categoryType: ShortcutCategoryType = ShortcutCategoryType.System,
+ val subCategoryLabel: String = "",
+ ) : ShortcutCustomizationRequestInfo
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index 02e206e09bc7..67caadba0d45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -17,22 +17,28 @@
package com.android.systemui.keyboard.shortcut.ui
import android.app.Dialog
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo
-import com.android.systemui.keyboard.shortcut.ui.composable.AssignNewShortcutDialog
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
+import com.android.systemui.keyboard.shortcut.ui.composable.ShortcutCustomizationDialog
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.AddShortcutDialog
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.DeleteShortcutDialog
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import com.android.systemui.statusbar.phone.create
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.launch
class ShortcutCustomizationDialogStarter
@AssistedInject
@@ -46,34 +52,49 @@ constructor(
override suspend fun onActivated(): Nothing {
viewModel.shortcutCustomizationUiState.collect { uiState ->
- if (
- uiState is ShortcutCustomizationUiState.AddShortcutDialog &&
- !uiState.isDialogShowing
- ) {
- dialog = createAddShortcutDialog().also { it.show() }
- viewModel.onAddShortcutDialogShown()
+ val shouldShowAddDialog = uiState is AddShortcutDialog && !uiState.isDialogShowing
+ val shouldShowDeleteDialog = uiState is DeleteShortcutDialog && !uiState.isDialogShowing
+ if (shouldShowDeleteDialog || shouldShowAddDialog) {
+ dialog = createDialog().also { it.show() }
+ viewModel.onDialogShown()
} else if (uiState is ShortcutCustomizationUiState.Inactive) {
dialog?.dismiss()
dialog = null
}
}
+ awaitCancellation()
}
- fun onAddShortcutDialogRequested(shortcutBeingCustomized: ShortcutInfo) {
- viewModel.onAddShortcutDialogRequested(shortcutBeingCustomized)
+ fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) {
+ viewModel.onShortcutCustomizationRequested(requestInfo)
}
- private fun createAddShortcutDialog(): Dialog {
+ private fun createDialog(): Dialog {
return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog
->
- val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle()
- AssignNewShortcutDialog(
+ val uiState by
+ viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle(
+ initialValue = ShortcutCustomizationUiState.Inactive
+ )
+ val coroutineScope = rememberCoroutineScope()
+ ShortcutCustomizationDialog(
uiState = uiState,
- modifier = Modifier.width(364.dp).wrapContentHeight().padding(vertical = 24.dp),
+ modifier = Modifier
+ .width(364.dp)
+ .wrapContentHeight()
+ .padding(vertical = 24.dp),
onKeyPress = { viewModel.onKeyPressed(it) },
onCancel = { dialog.dismiss() },
+ onConfirmSetShortcut = {
+ coroutineScope.launch { viewModel.onSetShortcut() }
+ },
+ onConfirmDeleteShortcut = { viewModel.onDeleteShortcut() },
)
- dialog.setOnDismissListener { viewModel.onAddShortcutDialogDismissed() }
+ dialog.setOnDismissListener { viewModel.onDialogDismissed() }
+
+ // By default, apps cannot intercept action key. The system always handles it. This
+ // flag is needed to enable customisation dialog window to intercept action key
+ dialog.window?.addPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
index 10a201e976c1..fa03883e2a35 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
@@ -84,7 +84,7 @@ constructor(
onKeyboardSettingsClicked = { onKeyboardSettingsClicked(dialog) },
onSearchQueryChanged = { shortcutHelperViewModel.onSearchQueryChanged(it) },
onCustomizationRequested = {
- shortcutCustomizationDialogStarter.onAddShortcutDialogRequested(it)
+ shortcutCustomizationDialogStarter.onShortcutCustomizationRequested(it)
},
)
dialog.setOnDismissListener { shortcutHelperViewModel.onViewClosed() }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
index 43f0f200ab23..20040c673994 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -39,57 +40,106 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.KeyEvent
-import androidx.compose.ui.input.key.onPreviewKeyEvent
+import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
+import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
import com.android.systemui.res.R
@Composable
-fun AssignNewShortcutDialog(
+fun ShortcutCustomizationDialog(
uiState: ShortcutCustomizationUiState,
modifier: Modifier = Modifier,
onKeyPress: (KeyEvent) -> Boolean,
onCancel: () -> Unit,
+ onConfirmSetShortcut: () -> Unit,
+ onConfirmDeleteShortcut: () -> Unit,
) {
- if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) {
- Column(modifier = modifier) {
- Title(
- uiState.shortcutLabel,
- modifier = Modifier.padding(horizontal = 24.dp).width(316.dp),
- )
- Description(
- modifier = Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp).width(316.dp)
- )
- PromptShortcutModifier(
- modifier =
- Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp)
- .width(131.dp)
- .height(48.dp),
- defaultModifierKey = uiState.defaultCustomShortcutModifierKey,
- )
- SelectedKeyCombinationContainer(
- shouldShowErrorMessage = uiState.shouldShowErrorMessage,
- onKeyPress = onKeyPress,
- )
- KeyCombinationAlreadyInUseErrorMessage(uiState.shouldShowErrorMessage)
- DialogButtons(onCancel, isValidKeyCombination = uiState.isValidKeyCombination)
+ when (uiState) {
+ is ShortcutCustomizationUiState.AddShortcutDialog -> {
+ Column(modifier = modifier) {
+ Title(uiState.shortcutLabel)
+ Description(
+ text =
+ stringResource(
+ id = R.string.shortcut_customize_mode_add_shortcut_description
+ )
+ )
+ PromptShortcutModifier(
+ modifier =
+ Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp)
+ .width(131.dp)
+ .height(48.dp),
+ defaultModifierKey = uiState.defaultCustomShortcutModifierKey,
+ )
+ SelectedKeyCombinationContainer(
+ shouldShowError = uiState.errorMessage.isNotEmpty(),
+ onKeyPress = onKeyPress,
+ pressedKeys = uiState.pressedKeys,
+ )
+ ErrorMessageContainer(uiState.errorMessage)
+ DialogButtons(
+ onCancel,
+ isConfirmButtonEnabled = uiState.pressedKeys.isNotEmpty(),
+ onConfirm = onConfirmSetShortcut,
+ confirmButtonText =
+ stringResource(
+ R.string.shortcut_helper_customize_dialog_set_shortcut_button_label
+ ),
+ )
+ }
+ }
+ is ShortcutCustomizationUiState.DeleteShortcutDialog -> {
+ Column(modifier) {
+ Title(
+ title =
+ stringResource(
+ id = R.string.shortcut_customize_mode_remove_shortcut_dialog_title
+ )
+ )
+ Description(
+ text =
+ stringResource(
+ id = R.string.shortcut_customize_mode_remove_shortcut_description
+ )
+ )
+ DialogButtons(
+ onCancel = onCancel,
+ onConfirm = onConfirmDeleteShortcut,
+ confirmButtonText =
+ stringResource(
+ R.string.shortcut_helper_customize_dialog_remove_button_label
+ ),
+ )
+ }
+ }
+ else -> {
+ /* No-Op */
}
}
}
@Composable
-fun DialogButtons(onCancel: () -> Unit, isValidKeyCombination: Boolean) {
+fun DialogButtons(
+ onCancel: () -> Unit,
+ isConfirmButtonEnabled: Boolean = true,
+ onConfirm: () -> Unit,
+ confirmButtonText: String,
+) {
Row(
modifier =
Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp)
@@ -107,23 +157,22 @@ fun DialogButtons(onCancel: () -> Unit, isValidKeyCombination: Boolean) {
)
Spacer(modifier = Modifier.width(8.dp))
ShortcutHelperButton(
- onClick = {},
+ onClick = onConfirm,
color = MaterialTheme.colorScheme.primary,
width = 116.dp,
contentColor = MaterialTheme.colorScheme.onPrimary,
- text =
- stringResource(R.string.shortcut_helper_customize_dialog_set_shortcut_button_label),
- enabled = isValidKeyCombination,
+ text = confirmButtonText,
+ enabled = isConfirmButtonEnabled,
)
}
}
@Composable
-fun KeyCombinationAlreadyInUseErrorMessage(shouldShowErrorMessage: Boolean) {
- if (shouldShowErrorMessage) {
+fun ErrorMessageContainer(errorMessage: String) {
+ if (errorMessage.isNotEmpty()) {
Box(modifier = Modifier.padding(horizontal = 16.dp).width(332.dp).height(40.dp)) {
Text(
- text = stringResource(R.string.shortcut_helper_customize_dialog_error_message),
+ text = errorMessage,
style = MaterialTheme.typography.bodyMedium,
fontSize = 14.sp,
lineHeight = 20.sp,
@@ -137,17 +186,19 @@ fun KeyCombinationAlreadyInUseErrorMessage(shouldShowErrorMessage: Boolean) {
@Composable
fun SelectedKeyCombinationContainer(
- keyCombination: String =
- stringResource(R.string.shortcut_helper_add_shortcut_dialog_placeholder),
- shouldShowErrorMessage: Boolean,
+ shouldShowError: Boolean,
onKeyPress: (KeyEvent) -> Boolean,
+ pressedKeys: List<ShortcutKey>,
) {
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
val outlineColor =
if (!isFocused) MaterialTheme.colorScheme.outline
- else if (shouldShowErrorMessage) MaterialTheme.colorScheme.error
+ else if (shouldShowError) MaterialTheme.colorScheme.error
else MaterialTheme.colorScheme.primary
+ val focusRequester = remember { FocusRequester() }
+
+ LaunchedEffect(Unit) { focusRequester.requestFocus() }
ClickableShortcutSurface(
onClick = {},
@@ -157,24 +208,21 @@ fun SelectedKeyCombinationContainer(
Modifier.padding(all = 16.dp)
.sizeIn(minWidth = 332.dp, minHeight = 56.dp)
.border(width = 2.dp, color = outlineColor, shape = RoundedCornerShape(50.dp))
- .onPreviewKeyEvent { onKeyPress(it) },
+ .onKeyEvent { onKeyPress(it) }
+ .focusRequester(focusRequester),
interactionSource = interactionSource,
) {
Row(
modifier = Modifier.padding(start = 24.dp, top = 16.dp, end = 16.dp, bottom = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
- Text(
- text = keyCombination,
- style = MaterialTheme.typography.headlineSmall,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- fontWeight = FontWeight.W500,
- color = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.width(252.dp),
- )
+ if (pressedKeys.isEmpty()) {
+ PressKeyPrompt()
+ } else {
+ PressedKeysTextContainer(pressedKeys)
+ }
Spacer(modifier = Modifier.weight(1f))
- if (shouldShowErrorMessage) {
+ if (shouldShowError) {
Icon(
imageVector = Icons.Default.ErrorOutline,
contentDescription = null,
@@ -187,25 +235,89 @@ fun SelectedKeyCombinationContainer(
}
@Composable
-private fun Title(title: String, modifier: Modifier = Modifier) {
+private fun RowScope.PressedKeysTextContainer(pressedKeys: List<ShortcutKey>) {
+ pressedKeys.forEachIndexed { keyIndex, key ->
+ if (keyIndex > 0) {
+ ShortcutKeySeparator()
+ }
+ if (key is ShortcutKey.Text) {
+ ShortcutTextKey(key)
+ } else if (key is ShortcutKey.Icon) {
+ ShortcutIconKey(key)
+ }
+ }
+}
+
+@Composable
+private fun ShortcutKeySeparator() {
+ Text(
+ text = stringResource(id = R.string.shortcut_helper_plus_symbol),
+ style = MaterialTheme.typography.titleSmall,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+}
+
+@Composable
+private fun RowScope.ShortcutIconKey(key: ShortcutKey.Icon) {
+ Icon(
+ painter =
+ when (key) {
+ is ShortcutKey.Icon.ResIdIcon -> painterResource(key.drawableResId)
+ is ShortcutKey.Icon.DrawableIcon -> rememberDrawablePainter(drawable = key.drawable)
+ },
+ contentDescription = null,
+ modifier = Modifier.align(Alignment.CenterVertically).height(24.dp),
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+}
+
+@Composable
+private fun PressKeyPrompt() {
+ Text(
+ text = stringResource(id = R.string.shortcut_helper_add_shortcut_dialog_placeholder),
+ style = MaterialTheme.typography.titleSmall,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+}
+
+@Composable
+private fun ShortcutTextKey(key: ShortcutKey.Text) {
+ Text(
+ text = key.value,
+ style = MaterialTheme.typography.titleSmall,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+}
+
+@Composable
+private fun Title(title: String) {
Text(
text = title,
style = MaterialTheme.typography.headlineSmall,
fontSize = 24.sp,
- modifier = modifier.wrapContentSize(Alignment.Center),
+ modifier =
+ Modifier.padding(horizontal = 24.dp).width(316.dp).wrapContentSize(Alignment.Center),
color = MaterialTheme.colorScheme.onSurface,
lineHeight = 32.sp,
+ fontWeight = FontWeight.W400,
)
}
@Composable
-private fun Description(modifier: Modifier = Modifier) {
+private fun Description(text: String) {
Text(
- text = stringResource(id = R.string.shortcut_helper_customize_mode_sub_title),
+ text = text,
style = MaterialTheme.typography.bodyMedium,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- modifier = modifier.wrapContentSize(Alignment.Center),
+ modifier =
+ Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp)
+ .width(316.dp)
+ .wrapContentSize(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 13934ea38233..f41ff7c69684 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -43,6 +43,7 @@ import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
@@ -53,6 +54,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.OpenInNew
import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.DeleteOutline
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Tune
@@ -70,8 +72,8 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -89,15 +91,18 @@ import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -106,17 +111,18 @@ import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import com.android.compose.modifiers.thenIf
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutIcon
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import com.android.systemui.keyboard.shortcut.ui.model.IconSource
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import com.android.systemui.res.R
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
+import kotlinx.coroutines.delay
@Composable
fun ShortcutHelper(
@@ -125,7 +131,7 @@ fun ShortcutHelper(
modifier: Modifier = Modifier,
shortcutsUiState: ShortcutsUiState,
useSinglePane: @Composable () -> Boolean = { shouldUseSinglePane() },
- onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+ onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
when (shortcutsUiState) {
is ShortcutsUiState.Active -> {
@@ -138,6 +144,7 @@ fun ShortcutHelper(
onCustomizationRequested,
)
}
+
else -> {
// No-op for now.
}
@@ -151,7 +158,7 @@ private fun ActiveShortcutHelper(
onSearchQueryChanged: (String) -> Unit,
modifier: Modifier,
onKeyboardSettingsClicked: () -> Unit,
- onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+ onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
var selectedCategoryType by
remember(shortcutsUiState.defaultSelectedCategory) {
@@ -367,26 +374,26 @@ private fun ShortcutHelperTwoPane(
onCategorySelected: (ShortcutCategoryType?) -> Unit,
onKeyboardSettingsClicked: () -> Unit,
isShortcutCustomizerFlagEnabled: Boolean,
- onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+ onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType }
- var isCustomizeModeEntered by remember { mutableStateOf(false) }
- val isCustomizing by
- remember(isCustomizeModeEntered, isShortcutCustomizerFlagEnabled) {
- derivedStateOf { isCustomizeModeEntered && isCustomizeModeEntered }
- }
+ var isCustomizing by remember { mutableStateOf(false) }
Column(modifier = modifier.fillMaxSize().padding(horizontal = 24.dp)) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
- Box(modifier = Modifier.padding(start = 202.dp).width(412.dp)) {
- TitleBar(isCustomizing)
- }
- Spacer(modifier = Modifier.weight(1f))
- if (isShortcutCustomizerFlagEnabled) {
- if (isCustomizeModeEntered) {
- DoneButton(onClick = { isCustomizeModeEntered = false })
+ // Keep title centered whether customize button is visible or not.
+ Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) {
+ Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
+ TitleBar(isCustomizing)
+ }
+ if (isShortcutCustomizerFlagEnabled) {
+ if (isCustomizing) {
+ DoneButton(onClick = { isCustomizing = false })
+ } else {
+ CustomizeButton(onClick = { isCustomizing = true })
+ }
} else {
- CustomizeButton(onClick = { isCustomizeModeEntered = true })
+ Spacer(modifier = Modifier.width(if (isCustomizing) 69.dp else 133.dp))
}
}
}
@@ -394,7 +401,7 @@ private fun ShortcutHelperTwoPane(
Row(Modifier.fillMaxWidth()) {
StartSidePanel(
onSearchQueryChanged = onSearchQueryChanged,
- modifier = Modifier.width(240.dp),
+ modifier = Modifier.width(240.dp).semantics { isTraversalGroup = true },
categories = categories,
onKeyboardSettingsClicked = onKeyboardSettingsClicked,
selectedCategory = selectedCategoryType,
@@ -403,7 +410,7 @@ private fun ShortcutHelperTwoPane(
Spacer(modifier = Modifier.width(24.dp))
EndSidePanel(
searchQuery,
- Modifier.fillMaxSize().padding(top = 8.dp),
+ Modifier.fillMaxSize().padding(top = 8.dp).semantics { isTraversalGroup = true },
selectedCategory,
isCustomizing = isCustomizing,
onCustomizationRequested = onCustomizationRequested,
@@ -441,7 +448,7 @@ private fun EndSidePanel(
modifier: Modifier,
category: ShortcutCategoryUi?,
isCustomizing: Boolean,
- onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+ onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
val listState = rememberLazyListState()
LaunchedEffect(key1 = category) { if (category != null) listState.animateScrollToItem(0) }
@@ -455,14 +462,18 @@ private fun EndSidePanel(
searchQuery = searchQuery,
subCategory = subcategory,
isCustomizing = isCustomizing,
- onCustomizationRequested = { label, subCategoryLabel ->
- onCustomizationRequested(
- ShortcutInfo(
- label = label,
- subCategoryLabel = subCategoryLabel,
- categoryType = category.type,
- )
- )
+ onCustomizationRequested = { requestInfo ->
+ when (requestInfo) {
+ is ShortcutCustomizationRequestInfo.Add ->
+ onCustomizationRequested(
+ requestInfo.copy(categoryType = category.type)
+ )
+
+ is ShortcutCustomizationRequestInfo.Delete ->
+ onCustomizationRequested(
+ requestInfo.copy(categoryType = category.type)
+ )
+ }
},
)
Spacer(modifier = Modifier.height(8.dp))
@@ -493,7 +504,7 @@ private fun SubCategoryContainerDualPane(
searchQuery: String,
subCategory: ShortcutSubCategory,
isCustomizing: Boolean,
- onCustomizationRequested: (String, String) -> Unit = { _: String, _: String -> },
+ onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit,
) {
Surface(
modifier = Modifier.fillMaxWidth(),
@@ -515,7 +526,19 @@ private fun SubCategoryContainerDualPane(
searchQuery = searchQuery,
shortcut = shortcut,
isCustomizing = isCustomizing,
- onCustomizationRequested = { onCustomizationRequested(it, subCategory.label) },
+ onCustomizationRequested = { requestInfo ->
+ when (requestInfo) {
+ is ShortcutCustomizationRequestInfo.Add ->
+ onCustomizationRequested(
+ requestInfo.copy(subCategoryLabel = subCategory.label)
+ )
+
+ is ShortcutCustomizationRequestInfo.Delete ->
+ onCustomizationRequested(
+ requestInfo.copy(subCategoryLabel = subCategory.label)
+ )
+ }
+ },
)
}
}
@@ -537,7 +560,7 @@ private fun Shortcut(
searchQuery: String,
shortcut: ShortcutModel,
isCustomizing: Boolean = false,
- onCustomizationRequested: (String) -> Unit = {},
+ onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
@@ -551,7 +574,7 @@ private fun Shortcut(
.padding(8.dp)
) {
Row(
- modifier = Modifier.width(128.dp).align(Alignment.CenterVertically),
+ modifier = Modifier.width(128.dp).align(Alignment.CenterVertically).weight(0.333f),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
@@ -562,10 +585,19 @@ private fun Shortcut(
}
Spacer(modifier = Modifier.width(24.dp))
ShortcutKeyCombinations(
- modifier = Modifier.weight(1f),
+ modifier = Modifier.weight(.666f),
shortcut = shortcut,
isCustomizing = isCustomizing,
- onAddShortcutClicked = { onCustomizationRequested(shortcut.label) },
+ onAddShortcutRequested = {
+ onCustomizationRequested(
+ ShortcutCustomizationRequestInfo.Add(label = shortcut.label)
+ )
+ },
+ onDeleteShortcutRequested = {
+ onCustomizationRequested(
+ ShortcutCustomizationRequestInfo.Delete(label = shortcut.label)
+ )
+ },
)
}
}
@@ -594,42 +626,92 @@ private fun ShortcutKeyCombinations(
modifier: Modifier = Modifier,
shortcut: ShortcutModel,
isCustomizing: Boolean = false,
- onAddShortcutClicked: () -> Unit = {},
+ onAddShortcutRequested: () -> Unit = {},
+ onDeleteShortcutRequested: () -> Unit = {},
) {
FlowRow(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp),
+ itemVerticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End,
) {
shortcut.commands.forEachIndexed { index, command ->
if (index > 0) {
ShortcutOrSeparator(spacing = 16.dp)
}
- ShortcutCommand(command)
+ ShortcutCommandContainer(showBackground = command.isCustom) { ShortcutCommand(command) }
}
if (isCustomizing) {
Spacer(modifier = Modifier.width(16.dp))
- ShortcutHelperButton(
- modifier =
- Modifier.border(
- width = 1.dp,
- color = MaterialTheme.colorScheme.outline,
- shape = CircleShape,
- ),
- onClick = { onAddShortcutClicked() },
- color = Color.Transparent,
- width = 32.dp,
- height = 32.dp,
- iconSource = IconSource(imageVector = Icons.Default.Add),
- contentColor = MaterialTheme.colorScheme.primary,
- contentPaddingVertical = 0.dp,
- contentPaddingHorizontal = 0.dp,
- )
+ if (shortcut.containsCustomShortcutCommands) {
+ DeleteShortcutButton(onDeleteShortcutRequested)
+ } else {
+ AddShortcutButton(onAddShortcutRequested)
+ }
}
}
}
@Composable
+private fun AddShortcutButton(onClick: () -> Unit) {
+ ShortcutHelperButton(
+ modifier =
+ Modifier.border(
+ width = 1.dp,
+ color = MaterialTheme.colorScheme.outline,
+ shape = CircleShape,
+ ),
+ onClick = onClick,
+ color = Color.Transparent,
+ width = 32.dp,
+ height = 32.dp,
+ iconSource = IconSource(imageVector = Icons.Default.Add),
+ contentColor = MaterialTheme.colorScheme.primary,
+ contentPaddingVertical = 0.dp,
+ contentPaddingHorizontal = 0.dp,
+ )
+}
+
+@Composable
+private fun DeleteShortcutButton(onClick: () -> Unit) {
+ ShortcutHelperButton(
+ modifier =
+ Modifier.border(
+ width = 1.dp,
+ color = MaterialTheme.colorScheme.outline,
+ shape = CircleShape,
+ ),
+ onClick = onClick,
+ color = Color.Transparent,
+ width = 32.dp,
+ height = 32.dp,
+ iconSource = IconSource(imageVector = Icons.Default.DeleteOutline),
+ contentColor = MaterialTheme.colorScheme.primary,
+ contentPaddingVertical = 0.dp,
+ contentPaddingHorizontal = 0.dp,
+ )
+}
+
+@Composable
+private fun ShortcutCommandContainer(showBackground: Boolean, content: @Composable () -> Unit) {
+ if (showBackground) {
+ Box(
+ modifier =
+ Modifier.wrapContentSize()
+ .background(
+ color = MaterialTheme.colorScheme.outlineVariant,
+ shape = RoundedCornerShape(16.dp),
+ )
+ .padding(4.dp)
+ ) {
+ content()
+ }
+ } else {
+ content()
+ }
+}
+
+@Composable
private fun ShortcutCommand(command: ShortcutCommand) {
Row {
command.keys.forEachIndexed { keyIndex, key ->
@@ -704,7 +786,7 @@ private fun ShortcutDescriptionText(
Text(
modifier = modifier,
text = textWithHighlightedSearchQuery(shortcut.label, searchQuery),
- style = MaterialTheme.typography.bodyMedium,
+ style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSurface,
)
}
@@ -742,16 +824,25 @@ private fun StartSidePanel(
selectedCategory: ShortcutCategoryType?,
onCategoryClicked: (ShortcutCategoryUi) -> Unit,
) {
- Column(modifier) {
- ShortcutsSearchBar(onSearchQueryChanged)
- Spacer(modifier = Modifier.heightIn(8.dp))
- CategoriesPanelTwoPane(categories, selectedCategory, onCategoryClicked)
- Spacer(modifier = Modifier.weight(1f))
- KeyboardSettings(
- horizontalPadding = 24.dp,
- verticalPadding = 24.dp,
- onKeyboardSettingsClicked,
- )
+ CompositionLocalProvider(
+ // Restrict system font scale increases up to a max so categories display correctly.
+ LocalDensity provides
+ Density(
+ density = LocalDensity.current.density,
+ fontScale = LocalDensity.current.fontScale.coerceIn(1f, 1.5f),
+ )
+ ) {
+ Column(modifier) {
+ ShortcutsSearchBar(onSearchQueryChanged)
+ Spacer(modifier = Modifier.heightIn(8.dp))
+ CategoriesPanelTwoPane(categories, selectedCategory, onCategoryClicked)
+ Spacer(modifier = Modifier.weight(1f))
+ KeyboardSettings(
+ horizontalPadding = 24.dp,
+ verticalPadding = 24.dp,
+ onKeyboardSettingsClicked,
+ )
+ }
}
}
@@ -813,7 +904,7 @@ private fun CategoryItemTwoPane(
Text(
fontSize = 18.sp,
color = colors.textColor(selected).value,
- style = MaterialTheme.typography.headlineSmall,
+ style = MaterialTheme.typography.titleSmall,
text = label,
)
}
@@ -853,7 +944,12 @@ private fun ShortcutsSearchBar(onQueryChange: (String) -> Unit) {
var queryInternal by remember { mutableStateOf("") }
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current
- LaunchedEffect(Unit) { focusRequester.requestFocus() }
+ LaunchedEffect(Unit) {
+ // TODO(b/272065229): Added minor delay so TalkBack can take focus of search box by default,
+ // remove when default a11y focus is fixed.
+ delay(50)
+ focusRequester.requestFocus()
+ }
SearchBar(
modifier =
Modifier.fillMaxWidth().focusRequester(focusRequester).onKeyEvent {
@@ -904,9 +1000,11 @@ private fun KeyboardSettings(horizontalPadding: Dp, verticalPadding: Dp, onClick
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
- stringResource(id = R.string.shortcut_helper_keyboard_settings_buttons_label),
+ text =
+ stringResource(id = R.string.shortcut_helper_keyboard_settings_buttons_label),
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 16.sp,
+ style = MaterialTheme.typography.titleSmall,
)
Spacer(modifier = Modifier.weight(1f))
Icon(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
index e295564a740f..f9904f6f62bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
@@ -49,5 +49,5 @@ fun getWidth(): Dp {
object ShortcutHelperBottomSheet {
val DefaultWidth = 412.dp
val LargeScreenWidthPortrait = 704.dp
- val LargeScreenWidthLandscape = 864.dp
+ val LargeScreenWidthLandscape = 960.dp
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
index e761c7313ff3..58ce194694df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
@@ -18,6 +18,7 @@ package com.android.systemui.keyboard.shortcut.ui.composable
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.IndicationNodeFactory
+import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
@@ -126,8 +127,7 @@ fun SelectableShortcutSurface(
.selectable(
selected = selected,
interactionSource = interactionSource,
- indication =
- ShortcutHelperIndication(interactionSource, interactionsConfig),
+ indication = ShortcutHelperIndication(interactionsConfig),
enabled = enabled,
onClick = onClick,
)
@@ -181,8 +181,7 @@ fun ClickableShortcutSurface(
)
.clickable(
interactionSource = interactionSource,
- indication =
- ShortcutHelperIndication(interactionSource, interactionsConfig),
+ indication = ShortcutHelperIndication(interactionsConfig),
enabled = enabled,
onClick = onClick,
),
@@ -507,10 +506,8 @@ private class ShortcutHelperInteractionsNode(
}
}
-data class ShortcutHelperIndication(
- private val interactionSource: InteractionSource,
- private val interactionsConfig: InteractionsConfig,
-) : IndicationNodeFactory {
+data class ShortcutHelperIndication(private val interactionsConfig: InteractionsConfig) :
+ IndicationNodeFactory {
override fun create(interactionSource: InteractionSource): DelegatableNode {
return ShortcutHelperInteractionsNode(interactionSource, interactionsConfig)
}
@@ -529,3 +526,15 @@ data class InteractionsConfig(
val hoverPadding: Dp = 0.dp,
val pressedPadding: Dp = hoverPadding,
)
+
+@Composable
+fun ProvideShortcutHelperIndication(
+ interactionsConfig: InteractionsConfig,
+ content: @Composable () -> Unit,
+) {
+ CompositionLocalProvider(
+ LocalIndication provides ShortcutHelperIndication(interactionsConfig)
+ ) {
+ content()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
index e9f2a3b8e5b3..990257d642ff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
@@ -21,11 +21,13 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
sealed interface ShortcutCustomizationUiState {
data class AddShortcutDialog(
val shortcutLabel: String,
- val shouldShowErrorMessage: Boolean,
- val isValidKeyCombination: Boolean,
+ val errorMessage: String = "",
val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon,
val isDialogShowing: Boolean,
+ val pressedKeys: List<ShortcutKey> = emptyList(),
) : ShortcutCustomizationUiState
+ data class DeleteShortcutDialog(val isDialogShowing: Boolean) : ShortcutCustomizationUiState
+
data object Inactive : ShortcutCustomizationUiState
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
index b9253878ba0d..869682742043 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
@@ -16,61 +16,165 @@
package com.android.systemui.keyboard.shortcut.ui.viewmodel
-import androidx.compose.runtime.mutableStateOf
+import android.content.Context
+import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.KeyEventType
+import androidx.compose.ui.input.key.isMetaPressed
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.nativeKeyCode
+import androidx.compose.ui.input.key.type
+import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.AddShortcutDialog
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.DeleteShortcutDialog
+import com.android.systemui.res.R
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
class ShortcutCustomizationViewModel
@AssistedInject
-constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationInteractor) {
- private val _shortcutBeingCustomized = mutableStateOf<ShortcutInfo?>(null)
-
+constructor(
+ private val context: Context,
+ private val shortcutCustomizationInteractor: ShortcutCustomizationInteractor,
+) {
private val _shortcutCustomizationUiState =
MutableStateFlow<ShortcutCustomizationUiState>(ShortcutCustomizationUiState.Inactive)
- val shortcutCustomizationUiState = _shortcutCustomizationUiState.asStateFlow()
-
- fun onAddShortcutDialogRequested(shortcutBeingCustomized: ShortcutInfo) {
- _shortcutCustomizationUiState.value =
- ShortcutCustomizationUiState.AddShortcutDialog(
- shortcutLabel = shortcutBeingCustomized.label,
- shouldShowErrorMessage = false,
- isValidKeyCombination = false,
- defaultCustomShortcutModifierKey =
- shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
- isDialogShowing = false,
- )
+ val shortcutCustomizationUiState =
+ shortcutCustomizationInteractor.pressedKeys
+ .map { keys ->
+ // Note that Action Key is excluded as it's already displayed on the UI
+ keys.filter {
+ it != shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey()
+ }
+ }
+ .combine(_shortcutCustomizationUiState) { keys, uiState ->
+ if (uiState is AddShortcutDialog) {
+ uiState.copy(pressedKeys = keys)
+ } else {
+ uiState
+ }
+ }
+
+ fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) {
+ when (requestInfo) {
+ is ShortcutCustomizationRequestInfo.Add -> {
+ _shortcutCustomizationUiState.value =
+ AddShortcutDialog(
+ shortcutLabel = requestInfo.label,
+ defaultCustomShortcutModifierKey =
+ shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
+ isDialogShowing = false,
+ pressedKeys = emptyList(),
+ )
+ shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
+ }
- _shortcutBeingCustomized.value = shortcutBeingCustomized
+ is ShortcutCustomizationRequestInfo.Delete -> {
+ _shortcutCustomizationUiState.value =
+ DeleteShortcutDialog(isDialogShowing = false)
+ shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
+ }
+ }
}
- fun onAddShortcutDialogShown() {
+ fun onDialogShown() {
_shortcutCustomizationUiState.update { uiState ->
- (uiState as? ShortcutCustomizationUiState.AddShortcutDialog)
- ?.let { it.copy(isDialogShowing = true) }
+ (uiState as? AddShortcutDialog)?.copy(isDialogShowing = true)
+ ?: (uiState as? DeleteShortcutDialog)?.copy(isDialogShowing = true)
?: uiState
}
}
- fun onAddShortcutDialogDismissed() {
- _shortcutBeingCustomized.value = null
+ fun onDialogDismissed() {
_shortcutCustomizationUiState.value = ShortcutCustomizationUiState.Inactive
+ shortcutCustomizationInteractor.onCustomizationRequested(null)
+ shortcutCustomizationInteractor.updateUserSelectedKeyCombination(null)
}
fun onKeyPressed(keyEvent: KeyEvent): Boolean {
- // TODO Not yet implemented b/373638584
+ if ((keyEvent.isMetaPressed && keyEvent.type == KeyEventType.KeyDown)) {
+ updatePressedKeys(keyEvent)
+ return true
+ }
return false
}
+ suspend fun onSetShortcut() {
+ val result = shortcutCustomizationInteractor.confirmAndSetShortcutCurrentlyBeingCustomized()
+
+ _shortcutCustomizationUiState.update { uiState ->
+ when (result) {
+ ShortcutCustomizationRequestResult.SUCCESS -> ShortcutCustomizationUiState.Inactive
+ ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION -> {
+ getUiStateWithErrorMessage(
+ uiState = uiState,
+ errorMessage =
+ context.getString(
+ R.string.shortcut_customizer_key_combination_in_use_error_message
+ ),
+ )
+ }
+
+ ShortcutCustomizationRequestResult.ERROR_OTHER ->
+ getUiStateWithErrorMessage(
+ uiState = uiState,
+ errorMessage =
+ context.getString(R.string.shortcut_customizer_generic_error_message),
+ )
+ }
+ }
+ }
+
+ fun onDeleteShortcut() {
+ // TODO(b/373631984) not yet implemented
+ }
+
+ private fun getUiStateWithErrorMessage(
+ uiState: ShortcutCustomizationUiState,
+ errorMessage: String,
+ ): ShortcutCustomizationUiState {
+ return (uiState as? AddShortcutDialog)?.copy(
+ errorMessage = errorMessage
+ ) ?: uiState
+ }
+
+ private fun updatePressedKeys(keyEvent: KeyEvent) {
+ val isModifier = SUPPORTED_MODIFIERS.contains(keyEvent.key)
+ val keyCombination =
+ KeyCombination(
+ modifiers = keyEvent.nativeKeyEvent.modifiers,
+ keyCode = if (!isModifier) keyEvent.key.nativeKeyCode else null,
+ )
+ shortcutCustomizationInteractor.updateUserSelectedKeyCombination(keyCombination)
+ }
+
@AssistedFactory
interface Factory {
fun create(): ShortcutCustomizationViewModel
}
+
+ companion object {
+ private val SUPPORTED_MODIFIERS =
+ listOf(
+ Key.MetaLeft,
+ Key.MetaRight,
+ Key.CtrlRight,
+ Key.CtrlLeft,
+ Key.AltLeft,
+ Key.AltRight,
+ Key.ShiftLeft,
+ Key.ShiftRight,
+ Key.Function,
+ Key.Symbol,
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
index 912bfe99cea8..08fd0af81006 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
@@ -123,7 +123,7 @@ constructor(
userContext.packageManager.getApplicationIcon(type.packageName)
IconSource(painter = DrawablePainter(drawable = iconDrawable))
} catch (e: NameNotFoundException) {
- Log.wtf(
+ Log.w(
"ShortcutHelperViewModel",
"Package not found when retrieving icon for ${type.packageName}",
)
@@ -153,7 +153,7 @@ constructor(
packageManagerForUser.getApplicationInfo(type.packageName, /* flags= */ 0)
return packageManagerForUser.getApplicationLabel(currentAppInfo).toString()
} catch (e: NameNotFoundException) {
- Log.wtf(
+ Log.w(
"ShortcutHelperViewModel",
"Package Not found when retrieving Label for ${type.packageName}",
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 32c2bc7c8620..7097c1d2fc4e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -662,7 +662,9 @@ public class KeyguardService extends Service {
trace("doKeyguardTimeout");
checkPermission();
- if (KeyguardWmStateRefactor.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
+ mDeviceEntryInteractorLazy.get().lockNow();
+ } else if (KeyguardWmStateRefactor.isEnabled()) {
mKeyguardLockWhileAwakeInteractor.onKeyguardServiceDoKeyguardTimeout(options);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 2d056001b669..5ec6d37207b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -95,7 +95,7 @@ constructor(
private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
@ShadeDisplayAware private val configuration: ConfigurationState,
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val keyguardIndicationController: KeyguardIndicationController,
private val shadeInteractor: ShadeInteractor,
private val interactionJankMonitor: InteractionJankMonitor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2ee9ddb0e453..01ec4d026646 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2875,7 +2875,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
- mKeyguardTransitions.startKeyguardTransition(showing, aodShowing);
+ startKeyguardTransition(showing, aodShowing);
} else {
try {
@@ -3019,7 +3019,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
final int keyguardFlag = flags;
mUiBgExecutor.execute(() -> {
if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
- mKeyguardTransitions.startKeyguardTransition(
+ startKeyguardTransition(
false /* keyguardShowing */, false /* aodShowing */);
return;
}
@@ -3035,6 +3035,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
};
+ private void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {
+ mKeyguardTransitions.startKeyguardTransition(keyguardShowing, aodShowing);
+ }
+
private final Runnable mHideAnimationFinishedRunnable = () -> {
Log.e(TAG, "mHideAnimationFinishedRunnable#run");
mHideAnimationRunning = false;
@@ -3490,8 +3494,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mSurfaceBehindRemoteAnimationRequested = true;
if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
- mKeyguardTransitions.startKeyguardTransition(
- false /* keyguardShowing */, false /* aodShowing */);
+ startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
index 39144b56adc7..c0ffda6640b2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
@@ -34,6 +34,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
@@ -91,7 +92,7 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe
@Inject
public WakefulnessLifecycle(
- Context context,
+ @ShadeDisplayAware Context context,
@Nullable IWallpaperManager wallpaperManagerService,
SystemClock systemClock,
DumpManager dumpManager) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index 2914cb9fdfdc..a137d6cf91ec 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -122,10 +122,7 @@ constructor(
if (visible) {
if (enableNewKeyguardShellTransitions) {
- keyguardTransitions.startKeyguardTransition(
- false /* keyguardShowing */,
- false, /* aodShowing */
- )
+ startKeyguardTransition(false, /* keyguardShowing */ false /* aodShowing */)
isKeyguardGoingAway = true
return
}
@@ -233,7 +230,7 @@ constructor(
"aodVisible=$aodVisible).",
)
if (enableNewKeyguardShellTransitions) {
- keyguardTransitions.startKeyguardTransition(lockscreenShowing, aodVisible)
+ startKeyguardTransition(lockscreenShowing, aodVisible)
} else {
activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible)
}
@@ -241,6 +238,10 @@ constructor(
this.isAodVisible = aodVisible
}
+ private fun startKeyguardTransition(keyguardShowing: Boolean, aodShowing: Boolean) {
+ keyguardTransitions.startKeyguardTransition(keyguardShowing, aodShowing)
+ }
+
private fun endKeyguardGoingAwayAnimation() {
if (!isKeyguardGoingAway) {
Log.d(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
index 585bd6adf11f..4bac8f7a1b47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
@@ -46,6 +46,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -83,7 +84,7 @@ constructor(
val activityTransitionAnimator: ActivityTransitionAnimator,
val keyguardViewController: dagger.Lazy<KeyguardViewController>,
val powerInteractor: PowerInteractor,
- val context: Context,
+ @ShadeDisplayAware val context: Context,
val interactionJankMonitor: InteractionJankMonitor,
@Main executor: Executor,
val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 7638079d7475..0101e099084e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -68,6 +68,7 @@ import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -126,7 +127,7 @@ public interface KeyguardModule {
@Provides
@SysUISingleton
static KeyguardViewMediator newKeyguardViewMediator(
- Context context,
+ @ShadeDisplayAware Context context,
UiEventLogger uiEventLogger,
SessionTracker sessionTracker,
UserTracker userTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
index 80675d373b8e..a45204d41718 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
@@ -28,6 +28,7 @@ object BuiltInKeyguardQuickAffordanceKeys {
const val CREATE_NOTE = "create_note"
const val DO_NOT_DISTURB = "do_not_disturb"
const val FLASHLIGHT = "flashlight"
+ const val GLANCEABLE_HUB = "glanceable_hub"
const val HOME_CONTROLS = "home"
const val MUTE = "mute"
const val QR_CODE_SCANNER = "qr_code_scanner"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index 77e8179195a1..74ee052f12b9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -27,9 +27,9 @@ import com.android.systemui.camera.CameraGestureHelper
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -41,7 +41,7 @@ import kotlinx.coroutines.withContext
class CameraQuickAffordanceConfig
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val packageManager: PackageManager,
private val cameraGestureHelper: Lazy<CameraGestureHelper>,
private val userTracker: UserTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
index be873344b719..d1f9fa259c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
@@ -40,6 +40,7 @@ import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.modes.shared.ModesUi
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.policy.ZenModeController
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
import com.android.systemui.util.settings.SecureSettings
@@ -75,7 +76,7 @@ constructor(
@Inject
constructor(
- context: Context,
+ @ShadeDisplayAware context: Context,
controller: ZenModeController,
interactor: ZenModeInteractor,
secureSettings: SecureSettings,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
index a7999c192643..480ef5e19d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
@@ -27,6 +27,7 @@ import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.policy.FlashlightController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -36,7 +37,7 @@ import kotlinx.coroutines.flow.Flow
class FlashlightQuickAffordanceConfig
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val flashlightController: FlashlightController,
) : KeyguardQuickAffordanceConfig {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
new file mode 100644
index 000000000000..8906156252a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2024 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.quickaffordance
+
+import android.content.Context
+import android.util.Log
+import com.android.systemui.Flags.glanceableHubShortcutButton
+import com.android.systemui.animation.Expandable
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.communal.data.repository.CommunalSceneRepository
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.CommunalTransitionKeys
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+
+/** Lockscreen affordance that opens the glanceable hub. */
+@SysUISingleton
+class GlanceableHubQuickAffordanceConfig
+@Inject
+constructor(
+ @Application private val context: Context,
+ private val communalSceneRepository: CommunalSceneRepository,
+ private val communalInteractor: CommunalInteractor,
+ private val sceneInteractor: SceneInteractor,
+) : KeyguardQuickAffordanceConfig {
+
+ private val pickerNameResourceId = R.string.glanceable_hub_lockscreen_affordance_label
+
+ override val key: String = BuiltInKeyguardQuickAffordanceKeys.GLANCEABLE_HUB
+
+ override fun pickerName(): String = context.getString(pickerNameResourceId)
+
+ override val pickerIconResourceId: Int
+ get() = R.drawable.ic_widgets
+
+ override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState>
+ get() = flow {
+ emit(
+ // TODO(b/378113263): Gate on getV2FlagEnabled() when ready.
+ if (!glanceableHubShortcutButton()) {
+ Log.i(TAG, "Button hidden on lockscreen: flag not enabled.")
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
+ } else if (!communalInteractor.isCommunalEnabled.value) {
+ Log.i(TAG, "Button hidden on lockscreen: hub not enabled in settings.")
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
+ } else {
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+ icon =
+ Icon.Resource(
+ pickerIconResourceId,
+ ContentDescription.Resource(pickerNameResourceId),
+ )
+ )
+ }
+ )
+ }
+
+ override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
+ // TODO(b/378113263): Gate on getV2FlagEnabled() when ready.
+ return if (!glanceableHubShortcutButton()) {
+ Log.i(TAG, "Button unavailable in picker: flag not enabled.")
+ KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
+ } else if (!communalInteractor.isCommunalEnabled.value) {
+ Log.i(TAG, "Button disabled in picker: hub not enabled in settings.")
+ KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
+ context.getString(R.string.glanceable_hub_lockscreen_affordance_disabled_text)
+ )
+ } else {
+ KeyguardQuickAffordanceConfig.PickerScreenState.Default()
+ }
+ }
+
+ override fun onTriggered(
+ expandable: Expandable?
+ ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.changeScene(Scenes.Communal, "lockscreen to communal from shortcut")
+ } else {
+ communalSceneRepository.changeScene(
+ CommunalScenes.Communal,
+ transitionKey = CommunalTransitionKeys.SimpleFade,
+ )
+ }
+ return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
+ }
+
+ companion object {
+ private const val TAG = "GlanceableHubQuickAffordanceConfig"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index cc36961ff973..3555f06ce96f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -36,6 +36,7 @@ import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.Companion.appStoreIntent
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.kotlin.getOrNull
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -48,7 +49,7 @@ import kotlinx.coroutines.flow.flowOf
class HomeControlsKeyguardQuickAffordanceConfig
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val component: ControlsComponent,
) : KeyguardQuickAffordanceConfig {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
index 45561959a7df..8c6fdb989daf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
@@ -26,7 +26,7 @@ import dagger.multibindings.ElementsIntoSet
interface KeyguardDataQuickAffordanceModule {
@Binds
fun providerClientFactory(
- impl: KeyguardQuickAffordanceProviderClientFactoryImpl,
+ impl: KeyguardQuickAffordanceProviderClientFactoryImpl
): KeyguardQuickAffordanceProviderClientFactory
companion object {
@@ -36,6 +36,7 @@ interface KeyguardDataQuickAffordanceModule {
camera: CameraQuickAffordanceConfig,
doNotDisturb: DoNotDisturbQuickAffordanceConfig,
flashlight: FlashlightQuickAffordanceConfig,
+ glanceableHub: GlanceableHubQuickAffordanceConfig,
home: HomeControlsKeyguardQuickAffordanceConfig,
mute: MuteQuickAffordanceConfig,
quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
@@ -46,6 +47,7 @@ interface KeyguardDataQuickAffordanceModule {
camera,
doNotDisturb,
flashlight,
+ glanceableHub,
home,
mute,
quickAccessWallet,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
index 796374aadc1a..f08576abc44f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
@@ -29,6 +29,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
@@ -47,7 +48,7 @@ import kotlinx.coroutines.flow.onStart
class KeyguardQuickAffordanceLocalUserSelectionManager
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val userFileManager: UserFileManager,
private val userTracker: UserTracker,
broadcastDispatcher: BroadcastDispatcher,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
index 6c1bdad98251..1358634a55f8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
@@ -33,6 +33,7 @@ import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.RingerModeTracker
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -51,7 +52,7 @@ import kotlinx.coroutines.withContext
class MuteQuickAffordanceConfig
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val userTracker: UserTracker,
private val userFileManager: UserFileManager,
private val ringerModeTracker: RingerModeTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index a503541dcf59..d12c42a754f0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -27,6 +27,7 @@ import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -36,7 +37,7 @@ import kotlinx.coroutines.flow.Flow
class QrCodeScannerKeyguardQuickAffordanceConfig
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val controller: QRCodeScannerController,
) : KeyguardQuickAffordanceConfig {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 56b520ed6206..eafa1cea59f3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -34,6 +34,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.wallet.controller.QuickAccessWalletController
import com.android.systemui.wallet.util.getPaymentCards
import javax.inject.Inject
@@ -51,7 +52,7 @@ import kotlinx.coroutines.withContext
class QuickAccessWalletKeyguardQuickAffordanceConfig
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val walletController: QuickAccessWalletController,
private val activityStarter: ActivityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
index 3e6e3b79a820..ceaeeca4ea2a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
@@ -32,6 +32,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
@@ -42,7 +43,7 @@ import kotlinx.coroutines.withContext
class VideoCameraQuickAffordanceConfig
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val cameraIntents: CameraIntentsWrapper,
private val activityIntentHelper: ActivityIntentHelper,
private val userTracker: UserTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
index dd3e6190ceaf..ab8cc7125d6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
@@ -40,6 +40,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.shared.model.AuthenticationFlags
import com.android.systemui.keyguard.shared.model.DevicePosture
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.user.data.repository.UserRepository
import java.io.PrintWriter
@@ -123,7 +124,7 @@ private const val TAG = "BiometricsRepositoryImpl"
class BiometricSettingsRepositoryImpl
@Inject
constructor(
- context: Context,
+ @ShadeDisplayAware context: Context,
lockPatternUtils: LockPatternUtils,
broadcastDispatcher: BroadcastDispatcher,
authController: AuthController,
@@ -354,7 +355,10 @@ constructor(
}
@OptIn(ExperimentalCoroutinesApi::class)
-private class StrongAuthTracker(private val userRepository: UserRepository, context: Context?) :
+private class StrongAuthTracker(
+ private val userRepository: UserRepository,
+ @ShadeDisplayAware context: Context?
+) :
LockPatternUtils.StrongAuthTracker(context) {
private val selectedUserId =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt
index be4ab4b2c486..c9be2072e506 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.data.repository
import android.annotation.IntDef
import android.content.res.Resources
import android.provider.Settings
-import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -27,13 +26,11 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.shared.model.DevicePosture
import com.android.systemui.keyguard.shared.model.DevicePosture.UNKNOWN
import com.android.systemui.res.R
-import com.android.systemui.tuner.TunerService
import com.android.systemui.util.kotlin.FlowDumperImpl
+import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
@@ -48,7 +45,7 @@ constructor(
biometricSettingsRepository: BiometricSettingsRepository,
devicePostureRepository: DevicePostureRepository,
dumpManager: DumpManager,
- private val tunerService: TunerService,
+ secureSettingsRepository: UserAwareSecureSettingsRepository,
@Background backgroundDispatcher: CoroutineDispatcher,
) : FlowDumperImpl(dumpManager) {
@@ -61,40 +58,26 @@ constructor(
DevicePosture.toPosture(resources.getInteger(R.integer.config_face_auth_supported_posture))
}
- private val dismissByDefault: Int by lazy {
- if (resources.getBoolean(com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) {
- 1
- } else {
- 0
- }
- }
-
private var bypassEnabledSetting: Flow<Boolean> =
- callbackFlow {
- val updateBypassSetting = { state: Boolean ->
- trySendWithFailureLogging(state, TAG, "Error sending bypassSetting $state")
- }
-
- val tunable =
- TunerService.Tunable { key, _ ->
- updateBypassSetting(tunerService.getValue(key, dismissByDefault) != 0)
- }
-
- updateBypassSetting(false)
- tunerService.addTunable(tunable, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
- awaitClose { tunerService.removeTunable(tunable) }
- }
+ secureSettingsRepository
+ .boolSetting(
+ name = Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
+ defaultValue =
+ resources.getBoolean(
+ com.android.internal.R.bool.config_faceAuthDismissesKeyguard
+ ),
+ )
.flowOn(backgroundDispatcher)
.dumpWhileCollecting("bypassEnabledSetting")
- val overrideFaceBypassSetting: Flow<Boolean> =
+ private val overrideFaceBypassSetting: Flow<Boolean> =
when (bypassOverride) {
FACE_UNLOCK_BYPASS_ALWAYS -> flowOf(true)
FACE_UNLOCK_BYPASS_NEVER -> flowOf(false)
else -> bypassEnabledSetting
}
- val isPostureAllowedForFaceAuth: Flow<Boolean> =
+ private val isPostureAllowedForFaceAuth: Flow<Boolean> =
when (configFaceAuthSupportedPosture) {
UNKNOWN -> flowOf(true)
else ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 95d1b5d7fcac..9718e7508df2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -31,6 +31,7 @@ import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
@@ -89,7 +90,7 @@ constructor(
override val clockEventController: ClockEventController,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@Application private val applicationScope: CoroutineScope,
- @Application private val applicationContext: Context,
+ @ShadeDisplayAware private val context: Context,
private val featureFlags: FeatureFlagsClassic,
) : KeyguardClockRepository {
@@ -143,7 +144,7 @@ constructor(
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = clockRegistry.createCurrentClock(),
+ initialValue = null,
)
override val previewClock: Flow<ClockController> =
@@ -166,7 +167,7 @@ constructor(
get() =
featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) &&
// True on small landscape screens
- applicationContext.resources.getBoolean(R.bool.force_small_clock_on_lockscreen)
+ context.resources.getBoolean(R.bool.force_small_clock_on_lockscreen)
private fun getClockSize(): ClockSizeSetting {
return ClockSizeSetting.fromSettingValue(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
index d0de21b45be0..c1ec88bb44f1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
@@ -36,6 +36,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerR
import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.kotlin.FlowDumperImpl
import java.io.PrintWriter
import javax.inject.Inject
@@ -57,7 +58,7 @@ import kotlinx.coroutines.flow.stateIn
class KeyguardQuickAffordanceRepository
@Inject
constructor(
- @Application private val appContext: Context,
+ @ShadeDisplayAware private val appContext: Context,
@Application private val scope: CoroutineScope,
private val localUserSelectionManager: KeyguardQuickAffordanceLocalUserSelectionManager,
private val remoteUserSelectionManager: KeyguardQuickAffordanceRemoteUserSelectionManager,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
index b67fd4bf0ea7..549a5081cc43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.data.repository
-import android.content.Context
import android.os.UserHandle
import android.provider.Settings
import android.view.View
@@ -46,7 +45,6 @@ interface KeyguardSmartspaceRepository {
class KeyguardSmartspaceRepositoryImpl
@Inject
constructor(
- context: Context,
private val secureSettings: SecureSettings,
private val userTracker: UserTracker,
@Application private val applicationScope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index eaf8fa9585f6..354fc3d82342 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -305,12 +305,12 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR
}
override suspend fun forceFinishCurrentTransition() {
- withContextMutex.lock()
-
if (lastAnimator?.isRunning != true) {
return
}
+ withContextMutex.lock()
+
return withContext("$TAG#forceFinishCurrentTransition", mainDispatcher) {
withContextMutex.unlock()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
index 4c9c282514cd..4f6319af24f1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
@@ -30,6 +30,7 @@ import com.android.systemui.power.data.repository.PowerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakeSleepReason.TAP
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LiftReveal
import com.android.systemui.statusbar.LightRevealEffect
@@ -77,7 +78,7 @@ class LightRevealScrimRepositoryImpl
@Inject
constructor(
keyguardRepository: KeyguardRepository,
- val context: Context,
+ @ShadeDisplayAware val context: Context,
powerRepository: PowerRepository,
private val scrimLogger: ScrimLogger,
) : LightRevealScrimRepository {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
index 73a4cc3ad9df..68ec4f3e86ce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
@@ -45,7 +45,7 @@ import kotlinx.coroutines.flow.stateIn
class BurnInInteractor
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val burnInHelperWrapper: BurnInHelperWrapper,
@Application private val scope: CoroutineScope,
@ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
index 03cf1a4b3e9a..6367b5c2df8e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -28,6 +28,7 @@ import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -47,7 +48,7 @@ import kotlinx.coroutines.flow.onEach
class DeviceEntrySideFpsOverlayInteractor
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
private val sceneInteractor: SceneInteractor,
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 1e672e23970b..deef2a6c3a4c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -21,11 +21,13 @@ import android.annotation.SuppressLint
import android.app.DreamManager
import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.Flags.communalHubOnMobile
import com.android.systemui.Flags.communalSceneKtfRefactor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -48,7 +50,6 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
-import com.android.app.tracing.coroutines.launchTraced as launch
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
@@ -176,6 +177,9 @@ constructor(
communalSceneInteractor.changeScene(
newScene = CommunalScenes.Communal,
loggingReason = "FromDreamingTransitionInteractor",
+ transitionKey =
+ if (communalHubOnMobile()) CommunalTransitionKeys.SimpleFade
+ else null,
)
} else {
startTransitionTo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index d4d7e75a8b41..2d81be6fb0dc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -28,6 +28,7 @@ import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.ShadeController
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import javax.inject.Inject
@@ -39,7 +40,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
class KeyguardKeyEventInteractor
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val statusBarStateController: StatusBarStateController,
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
private val shadeController: ShadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 8c9473f4284b..ae55825c9842 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -51,6 +51,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.KEYGUARD_QUICK_AFFORDANCE_ID_NONE
@@ -90,7 +91,7 @@ constructor(
private val dockManager: DockManager,
private val biometricSettingsRepository: BiometricSettingsRepository,
@Background private val backgroundDispatcher: CoroutineDispatcher,
- @Application private val appContext: Context,
+ @ShadeDisplayAware private val appContext: Context,
private val sceneInteractor: Lazy<SceneInteractor>,
) {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
index 377a03edf88d..b9784f14fa1c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
@@ -23,6 +23,7 @@ import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.kotlin.toPx
@@ -45,7 +46,7 @@ class KeyguardSurfaceBehindInteractor
@Inject
constructor(
private val repository: KeyguardSurfaceBehindRepository,
- context: Context,
+ @ShadeDisplayAware context: Context,
transitionInteractor: KeyguardTransitionInteractor,
inWindowLauncherUnlockAnimationInteractor: Lazy<InWindowLauncherUnlockAnimationInteractor>,
swipeToDismissInteractor: SwipeToDismissInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
index b2031d300a82..274a1ddbd392 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
@@ -34,6 +34,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.res.R
import com.android.systemui.shade.PulsingGestureListener
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -58,7 +59,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch
class KeyguardTouchHandlingInteractor
@Inject
constructor(
- @Application private val appContext: Context,
+ @ShadeDisplayAware private val context: Context,
@Application private val scope: CoroutineScope,
transitionInteractor: KeyguardTransitionInteractor,
repository: KeyguardRepository,
@@ -188,7 +189,7 @@ constructor(
private fun isFeatureEnabled(): Boolean {
return featureFlags.isEnabled(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED) &&
- appContext.resources.getBoolean(R.bool.long_press_keyguard_customize_lockscreen_enabled)
+ context.resources.getBoolean(R.bool.long_press_keyguard_customize_lockscreen_enabled)
}
/** Updates application state to ask to show the menu. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
index 9c98a96ea908..fbc7e2aecbdf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
@@ -38,6 +38,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.Companion.device
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.settings.SecureSettings
@@ -75,7 +76,7 @@ class KeyguardWakeDirectlyToGoneInteractor
@Inject
constructor(
@Application private val scope: CoroutineScope,
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val repository: KeyguardRepository,
private val systemClock: SystemClock,
private val alarmManager: AlarmManager,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt
index 508fb597ef65..7e7742354a9c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt
@@ -24,6 +24,7 @@ import android.provider.Settings
import android.provider.Settings.SettingNotFoundException
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
@SysUISingleton
@@ -31,7 +32,7 @@ class NaturalScrollingSettingObserver
@Inject
constructor(
@Main private val handler: Handler,
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
) {
var isNaturalScrollingEnabled = true
get() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
index 73e80ff1d02b..d6a110a8fd55 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
@@ -40,6 +40,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessModel
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -62,7 +63,7 @@ class StatusBarDisableFlagsInteractor
@Inject
constructor(
@Application private val scope: CoroutineScope,
- @Application private val applicationContext: Context,
+ @ShadeDisplayAware private val context: Context,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
private val statusBarService: IStatusBarService,
@@ -142,7 +143,7 @@ constructor(
scope.launch {
disableFlagsForUserId.collect { (selectedUserId, flags) ->
- if (applicationContext.getSystemService(Context.STATUS_BAR_SERVICE) == null) {
+ if (context.getSystemService(Context.STATUS_BAR_SERVICE) == null) {
return@collect
}
@@ -151,7 +152,7 @@ constructor(
statusBarService.disableForUser(
flags,
disableToken,
- applicationContext.packageName,
+ context.packageName,
selectedUserId,
)
} catch (e: RemoteException) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index f473a82138e6..9df293bf2c15 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -112,8 +112,10 @@ constructor(
}
.distinctUntilChanged()
- private val isDeviceEntered by lazy { deviceEntryInteractor.get().isDeviceEntered }
- private val isDeviceNotEntered by lazy { isDeviceEntered.map { !it } }
+ private val isDeviceEnteredDirectly by lazy {
+ deviceEntryInteractor.get().isDeviceEnteredDirectly
+ }
+ private val isDeviceNotEnteredDirectly by lazy { isDeviceEnteredDirectly.map { !it } }
/**
* Surface visibility, which is either determined by the default visibility when not
@@ -126,7 +128,7 @@ constructor(
sceneInteractor.get().transitionState.flatMapLatestConflated { state ->
when {
state.isTransitioning(from = Scenes.Lockscreen, to = Scenes.Gone) ->
- isDeviceEntered
+ isDeviceEnteredDirectly
state.isTransitioning(from = Scenes.Bouncer, to = Scenes.Gone) ->
(state as Transition).progress.map { progress ->
progress >
@@ -202,30 +204,6 @@ constructor(
.distinctUntilChanged()
}
- /**
- * Scenes that are part of the keyguard and are shown when the device is locked or when the
- * keyguard still needs to be dismissed.
- */
- private val keyguardScenes = setOf(Scenes.Lockscreen, Scenes.Bouncer, Scenes.Communal)
-
- /**
- * Scenes that don't belong in the keyguard family and cannot show when the device is locked or
- * when the keyguard still needs to be dismissed.
- */
- private val nonKeyguardScenes = setOf(Scenes.Gone)
-
- /**
- * Scenes that can show regardless of device lock or keyguard dismissal states. Other sources of
- * state need to be consulted to know whether the device has been entered or not.
- */
- private val keyguardAgnosticScenes =
- setOf(
- Scenes.Shade,
- Scenes.QuickSettings,
- Overlays.NotificationsShade,
- Overlays.QuickSettingsShade,
- )
-
private val lockscreenVisibilityWithScenes =
combine(
sceneInteractor.get().transitionState.flatMapLatestConflated {
@@ -234,7 +212,7 @@ constructor(
when (it.currentScene) {
in keyguardScenes -> flowOf(true)
in nonKeyguardScenes -> flowOf(false)
- in keyguardAgnosticScenes -> isDeviceNotEntered
+ in keyguardAgnosticScenes -> isDeviceNotEnteredDirectly
else ->
throw IllegalStateException("Unknown scene: ${it.currentScene}")
}
@@ -244,7 +222,7 @@ constructor(
it.isTransitioningSets(from = keyguardScenes) -> flowOf(true)
it.isTransitioningSets(from = nonKeyguardScenes) -> flowOf(false)
it.isTransitioningSets(from = keyguardAgnosticScenes) ->
- isDeviceNotEntered
+ isDeviceNotEnteredDirectly
else ->
throw IllegalStateException("Unknown scene: ${it.fromContent}")
}
@@ -355,4 +333,30 @@ constructor(
!BiometricUnlockMode.isWakeAndUnlock(biometricUnlockState.mode)
}
.distinctUntilChanged()
+
+ companion object {
+ /**
+ * Scenes that are part of the keyguard and are shown when the device is locked or when the
+ * keyguard still needs to be dismissed.
+ */
+ val keyguardScenes = setOf(Scenes.Lockscreen, Scenes.Bouncer, Scenes.Communal, Scenes.Dream)
+
+ /**
+ * Scenes that don't belong in the keyguard family and cannot show when the device is locked
+ * or when the keyguard still needs to be dismissed.
+ */
+ private val nonKeyguardScenes = setOf(Scenes.Gone)
+
+ /**
+ * Scenes that can show regardless of device lock or keyguard dismissal states. Other
+ * sources of state need to be consulted to know whether the device has been entered or not.
+ */
+ private val keyguardAgnosticScenes =
+ setOf(
+ Scenes.Shade,
+ Scenes.QuickSettings,
+ Overlays.NotificationsShade,
+ Overlays.QuickSettingsShade,
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
index 3540a0c6f016..b6aa209fad3f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.view.MotionEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.gesture.SwipeUpGestureHandler
import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
import javax.inject.Inject
@@ -29,7 +30,7 @@ import javax.inject.Inject
class SwipeUpAnywhereGestureHandler
@Inject
constructor(
- context: Context,
+ @ShadeDisplayAware context: Context,
displayTracker: DisplayTracker,
logger: SwipeUpGestureLogger,
) :
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index 7292ddaf43a7..b30e1e9b1103 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -26,6 +26,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
@@ -44,7 +45,6 @@ import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
object KeyguardClockViewBinder {
private val TAG = KeyguardClockViewBinder::class.simpleName!!
@@ -133,15 +133,26 @@ object KeyguardClockViewBinder {
launch {
if (!MigrateClocksToBlueprint.isEnabled) return@launch
aodBurnInViewModel.movement.collect { burnInModel ->
- viewModel.currentClock.value?.let {
- it.largeClock.layout.applyAodBurnIn(
+ viewModel.currentClock.value
+ ?.largeClock
+ ?.layout
+ ?.applyAodBurnIn(
AodClockBurnInModel(
translationX = burnInModel.translationX.toFloat(),
translationY = burnInModel.translationY.toFloat(),
scale = burnInModel.scale,
)
)
- }
+ }
+ }
+
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ viewModel.largeClockTextSize.collect { fontSizePx ->
+ viewModel.currentClock.value
+ ?.largeClock
+ ?.events
+ ?.onFontSettingChanged(fontSizePx = fontSizePx.toFloat())
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index 914fdd20e48e..ac302dd26365 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.ui.binder
-import android.content.Context
+import android.content.res.Resources
import android.view.View
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
@@ -34,8 +34,8 @@ import com.android.systemui.keyguard.ui.view.layout.sections.setVisibility
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
import com.android.systemui.shared.clocks.ClockRegistry
-import kotlin.reflect.KSuspendFunction1
/** Binder for the small clock view, large clock view. */
object KeyguardPreviewClockViewBinder {
@@ -66,11 +66,11 @@ object KeyguardPreviewClockViewBinder {
@JvmStatic
fun bind(
- context: Context,
rootView: ConstraintLayout,
viewModel: KeyguardPreviewClockViewModel,
clockRegistry: ClockRegistry,
- updateClockAppearance: KSuspendFunction1<ClockController, Unit>,
+ updateClockAppearance: suspend (ClockController, Resources) -> Unit,
+ clockPreviewConfig: ClockPreviewConfig,
) {
rootView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -82,7 +82,10 @@ object KeyguardPreviewClockViewBinder {
.forEach { rootView.removeView(it) }
}
lastClock = currentClock
- updateClockAppearance(currentClock)
+ updateClockAppearance(
+ currentClock,
+ clockPreviewConfig.previewContext.resources,
+ )
if (viewModel.shouldHighlightSelectedAffordance) {
(currentClock.largeClock.layout.views +
@@ -98,7 +101,12 @@ object KeyguardPreviewClockViewBinder {
(it.parent as? ViewGroup)?.removeView(it)
rootView.addView(it)
}
- applyPreviewConstraints(context, rootView, currentClock, viewModel)
+ applyPreviewConstraints(
+ clockPreviewConfig,
+ rootView,
+ currentClock,
+ viewModel,
+ )
}
}
.invokeOnCompletion {
@@ -121,14 +129,14 @@ object KeyguardPreviewClockViewBinder {
}
private fun applyPreviewConstraints(
- context: Context,
+ clockPreviewConfig: ClockPreviewConfig,
rootView: ConstraintLayout,
previewClock: ClockController,
viewModel: KeyguardPreviewClockViewModel,
) {
val cs = ConstraintSet().apply { clone(rootView) }
- previewClock.largeClock.layout.applyPreviewConstraints(context, cs)
- previewClock.smallClock.layout.applyPreviewConstraints(context, cs)
+ previewClock.largeClock.layout.applyPreviewConstraints(clockPreviewConfig, cs)
+ previewClock.smallClock.layout.applyPreviewConstraints(clockPreviewConfig, cs)
// When selectedClockSize is the initial value, make both clocks invisible to avoid
// flickering
@@ -151,7 +159,5 @@ object KeyguardPreviewClockViewBinder {
cs.applyTo(rootView)
}
- private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height"
- private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height"
private const val TAG = "KeyguardPreviewClockViewBinder"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
index baa681282a0b..e89be5d6ae4c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard.ui.binder
-import android.content.Context
import android.view.View
import androidx.core.view.isInvisible
import androidx.lifecycle.Lifecycle
@@ -26,16 +25,16 @@ import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
/** Binder for the small clock view, large clock view and smartspace. */
object KeyguardPreviewSmartspaceViewBinder {
@JvmStatic
fun bind(
- previewContext: Context,
smartspace: View,
- splitShadePreview: Boolean,
viewModel: KeyguardPreviewSmartspaceViewModel,
+ clockPreviewConfig: ClockPreviewConfig,
) {
smartspace.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -44,15 +43,9 @@ object KeyguardPreviewSmartspaceViewBinder {
val topPadding =
when (it) {
ClockSizeSetting.DYNAMIC ->
- viewModel.getLargeClockSmartspaceTopPadding(
- splitShadePreview,
- previewContext,
- )
+ viewModel.getLargeClockSmartspaceTopPadding(clockPreviewConfig)
ClockSizeSetting.SMALL ->
- viewModel.getSmallClockSmartspaceTopPadding(
- splitShadePreview,
- previewContext,
- )
+ viewModel.getSmallClockSmartspaceTopPadding(clockPreviewConfig)
}
smartspace.setTopPadding(topPadding)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index ab9cffc05667..9924a3bcdd6a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -22,6 +22,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.res.Resources
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.os.Bundle
@@ -47,6 +48,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.core.view.isInvisible
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.policy.SystemBarUtils
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
@@ -57,6 +59,7 @@ import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.communal.ui.binder.CommunalTutorialIndicatorViewBinder
import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel
import com.android.systemui.coroutines.newTracingContext
+import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -80,9 +83,11 @@ import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessage
import com.android.systemui.monet.ColorScheme
import com.android.systemui.monet.Style
import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
import com.android.systemui.plugins.clocks.ThemeConfig
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.clocks.DefaultClockController
@@ -105,7 +110,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.flowOf
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.json.JSONException
@@ -352,8 +356,11 @@ constructor(
val topPadding: Int =
smartspaceViewModel.getLargeClockSmartspaceTopPadding(
- previewInSplitShade(),
- previewContext,
+ ClockPreviewConfig(
+ previewContext,
+ getPreviewShadeLayoutWide(display!!),
+ SceneContainerFlag.isEnabled,
+ )
)
val startPadding: Int = smartspaceViewModel.getSmartspaceStartPadding(previewContext)
val endPadding: Int = smartspaceViewModel.getSmartspaceEndPadding(previewContext)
@@ -436,11 +443,15 @@ constructor(
setUpClock(previewContext, rootView)
if (MigrateClocksToBlueprint.isEnabled) {
KeyguardPreviewClockViewBinder.bind(
- previewContext,
keyguardRootView,
clockViewModel,
clockRegistry,
::updateClockAppearance,
+ ClockPreviewConfig(
+ previewContext,
+ getPreviewShadeLayoutWide(display!!),
+ SceneContainerFlag.isEnabled,
+ ),
)
} else {
KeyguardPreviewClockViewBinder.bind(
@@ -455,10 +466,14 @@ constructor(
smartSpaceView?.let {
KeyguardPreviewSmartspaceViewBinder.bind(
- previewContext,
it,
- previewInSplitShade(),
smartspaceViewModel,
+ clockPreviewConfig =
+ ClockPreviewConfig(
+ previewContext,
+ getPreviewShadeLayoutWide(display!!),
+ SceneContainerFlag.isEnabled,
+ ),
)
}
setupCommunalTutorialIndicator(keyguardRootView)
@@ -552,20 +567,14 @@ constructor(
val layoutParams =
FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_height
- ),
+ resources.getDimensionPixelSize(customR.dimen.small_clock_height),
)
layoutParams.topMargin =
SystemBarUtils.getStatusBarHeight(previewContext) +
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_padding_top
- )
+ resources.getDimensionPixelSize(customR.dimen.small_clock_padding_top)
smallClockHostView.layoutParams = layoutParams
smallClockHostView.setPaddingRelative(
- /* start = */ resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.clock_padding_start
- ),
+ /* start = */ resources.getDimensionPixelSize(customR.dimen.clock_padding_start),
/* top = */ 0,
/* end = */ 0,
/* bottom = */ 0,
@@ -637,7 +646,7 @@ constructor(
onClockChanged()
}
- private suspend fun updateClockAppearance(clock: ClockController) {
+ private suspend fun updateClockAppearance(clock: ClockController, resources: Resources) {
if (!MigrateClocksToBlueprint.isEnabled) {
clockController.clock = clock
}
@@ -667,6 +676,11 @@ constructor(
if (MigrateClocksToBlueprint.isEnabled) {
clockController.clock = clock
}
+ // When set clock to clockController,it will reset fontsize based on context.resources
+ // We need to override it with overlaid resources
+ clock.largeClock.events.onFontSettingChanged(
+ resources.getDimensionPixelSize(customR.dimen.large_clock_text_size).toFloat()
+ )
}
private fun onClockChanged() {
@@ -676,7 +690,7 @@ constructor(
coroutineScope.launch {
val clock = clockRegistry.createCurrentClock()
clockController.clock = clock
- updateClockAppearance(clock)
+ updateClockAppearance(clock, context.resources)
updateLargeClock(clock)
updateSmallClock(clock)
}
@@ -742,12 +756,14 @@ constructor(
smallClockHostView.addView(clock.smallClock.view)
}
- /*
- * When multi_crop_preview_ui_flag is on, we can preview portrait in split shadow direction
- * or vice versa. So we need to decide preview direction by width and height
- */
- private fun previewInSplitShade(): Boolean {
- return width > height
+ private fun getPreviewShadeLayoutWide(display: Display): Boolean {
+ return if (display.displayId == 0) {
+ shadeInteractor.isShadeLayoutWide.value
+ } else {
+ // For the unfolded preview in a folded screen; it's landscape by default
+ // For the folded preview in an unfolded screen; it's portrait by default
+ display.name == "Inner Display"
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt
index 717a89801ba4..587a8fe5a5c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt
@@ -26,6 +26,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.AccessibilityActionsViewBinder
import com.android.systemui.keyguard.ui.viewmodel.AccessibilityActionsViewModel
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.Utils
import javax.inject.Inject
import kotlinx.coroutines.DisposableHandle
@@ -37,7 +38,7 @@ import kotlinx.coroutines.DisposableHandle
class AccessibilityActionsSection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val communalSettingsInteractor: CommunalSettingsInteractor,
private val accessibilityActionsViewModel: AccessibilityActionsViewModel,
) : KeyguardSection() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
index d639978764f8..160380bb09bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.view.layout.sections
import android.content.Context
import android.view.View
+import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
@@ -28,13 +29,14 @@ import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
/** Adds a layer to group elements for translation for burn-in preventation */
class AodBurnInSection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val rootView: KeyguardRootView,
private val clockViewModel: KeyguardClockViewModel,
) : KeyguardSection() {
@@ -46,11 +48,15 @@ constructor(
visibility = View.GONE
}
}
+
override fun addViews(constraintLayout: ConstraintLayout) {
if (!MigrateClocksToBlueprint.isEnabled) {
return
}
-
+ if (emptyView.parent != null) {
+ // As emptyView is lazy, it might be already attached.
+ (emptyView.parent as? ViewGroup)?.removeView(emptyView)
+ }
constraintLayout.addView(emptyView)
burnInLayer =
AodBurnInLayer(context).apply {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index faa497833e7b..4c23adfe92e8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -29,6 +29,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.customization.R as customR
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
@@ -47,7 +48,7 @@ import kotlinx.coroutines.DisposableHandle
class AodNotificationIconsSection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
@ShadeDisplayAware private val configurationState: ConfigurationState,
private val iconBindingFailureTracker: StatusBarIconViewBindingFailureTracker,
private val nicAodViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
@@ -114,14 +115,14 @@ constructor(
START,
PARENT_ID,
START,
- context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
+ context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal),
)
connect(
nicId,
END,
PARENT_ID,
END,
- context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
+ context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal),
)
constrainHeight(
nicId,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index 6096cf74a772..70bf8bca55b9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -45,6 +45,7 @@ import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFaceLayout
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shared.R as sharedR
import com.android.systemui.util.ui.value
import dagger.Lazy
@@ -69,7 +70,7 @@ class ClockSection
constructor(
private val clockInteractor: KeyguardClockInteractor,
protected val keyguardClockViewModel: KeyguardClockViewModel,
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
val smartspaceViewModel: KeyguardSmartspaceViewModel,
val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
private val rootViewModel: KeyguardRootViewModel,
@@ -220,7 +221,9 @@ constructor(
PARENT_ID,
START,
context.resources.getDimensionPixelSize(customR.dimen.clock_padding_start) +
- context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
+ context.resources.getDimensionPixelSize(
+ customR.dimen.status_view_margin_horizontal
+ ),
)
val smallClockTopMargin = keyguardClockViewModel.getSmallClockTopMargin()
create(R.id.small_clock_guideline_top, ConstraintSet.HORIZONTAL_GUIDELINE)
@@ -232,9 +235,7 @@ constructor(
val smallClockBottom =
keyguardClockViewModel.getSmallClockTopMargin() +
- context.resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_height
- )
+ context.resources.getDimensionPixelSize(customR.dimen.small_clock_height)
val dateWeatherSmartspaceHeight = getDimen(context, DATE_WEATHER_VIEW_HEIGHT).toFloat()
val marginBetweenSmartspaceAndNotification =
context.resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 8d2bfb5bdf40..aa7eb2933992 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -28,6 +28,7 @@ import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -45,6 +46,7 @@ import com.android.systemui.log.dagger.LongPressTouchLog
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.VibratorHelper
import dagger.Lazy
import javax.inject.Inject
@@ -60,7 +62,7 @@ constructor(
@Application private val applicationScope: CoroutineScope,
private val authController: AuthController,
private val windowManager: WindowManager,
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val notificationPanelView: NotificationPanelView,
private val featureFlags: FeatureFlags,
private val deviceEntryIconViewModel: Lazy<DeviceEntryIconViewModel>,
@@ -114,7 +116,7 @@ constructor(
val scaleFactor: Float = authController.scaleFactor
val mBottomPaddingPx =
- context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
+ context.resources.getDimensionPixelSize(customR.dimen.lock_icon_margin_bottom)
val bounds = windowManager.currentWindowMetrics.bounds
var widthPixels = bounds.right.toFloat()
if (featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
index af0528a4c354..2d9dac41ba6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
@@ -27,6 +27,7 @@ import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea
import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.KeyguardIndicationController
import javax.inject.Inject
import kotlinx.coroutines.DisposableHandle
@@ -34,7 +35,7 @@ import kotlinx.coroutines.DisposableHandle
class DefaultIndicationAreaSection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel,
private val indicationController: KeyguardIndicationController,
) : KeyguardSection() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
index 6ac33af26605..3a791fd45528 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
@@ -28,6 +28,7 @@ import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
@@ -38,7 +39,7 @@ import javax.inject.Inject
class DefaultNotificationStackScrollLayoutSection
@Inject
constructor(
- context: Context,
+ @ShadeDisplayAware context: Context,
notificationPanelView: NotificationPanelView,
sharedNotificationContainer: SharedNotificationContainer,
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
index 9b5fae38059e..9d9be44f3153 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
@@ -31,6 +31,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.ShadeViewStateProvider
import com.android.systemui.statusbar.phone.KeyguardStatusBarView
import com.android.systemui.util.Utils
@@ -40,7 +41,7 @@ import javax.inject.Inject
class DefaultStatusBarSection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val notificationPanelView: NotificationPanelView,
private val keyguardStatusBarViewComponentFactory: KeyguardStatusBarViewComponent.Factory,
) : KeyguardSection() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index 45641dbfc517..57ea1ad5575d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -38,6 +38,7 @@ import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.policy.SplitShadeStateController
import com.android.systemui.util.Utils
import dagger.Lazy
@@ -47,7 +48,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
class DefaultStatusViewSection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val notificationPanelView: NotificationPanelView,
private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
private val keyguardViewConfigurator: Lazy<KeyguardViewConfigurator>,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt
index 2abb7ba37340..0ae1400b1906 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt
@@ -26,6 +26,7 @@ import com.android.systemui.deviceentry.ui.viewmodel.DeviceEntryUdfpsAccessibili
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -34,7 +35,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
class DefaultUdfpsAccessibilityOverlaySection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val viewModel: DeviceEntryUdfpsAccessibilityOverlayViewModel,
) : KeyguardSection() {
private val viewId = R.id.udfps_accessibility_overlay
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 6ddcae38ce92..d54d411b7de6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -33,6 +33,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardSmartspaceViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.res.R as R
import com.android.systemui.shared.R as sharedR
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
@@ -44,7 +45,7 @@ import kotlinx.coroutines.DisposableHandle
open class SmartspaceSection
@Inject
constructor(
- val context: Context,
+ @ShadeDisplayAware val context: Context,
val keyguardClockViewModel: KeyguardClockViewModel,
val keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel,
private val keyguardSmartspaceInteractor: KeyguardSmartspaceInteractor,
@@ -123,7 +124,7 @@ constructor(
ConstraintSet.START,
ConstraintSet.PARENT_ID,
ConstraintSet.START,
- horizontalPaddingStart
+ horizontalPaddingStart,
)
// migrate addSmartspaceView from KeyguardClockSwitchController
@@ -134,15 +135,15 @@ constructor(
ConstraintSet.START,
ConstraintSet.PARENT_ID,
ConstraintSet.START,
- horizontalPaddingStart
+ horizontalPaddingStart,
)
connect(
sharedR.id.bc_smartspace_view,
ConstraintSet.END,
- if (keyguardClockViewModel.clockShouldBeCentered.value) ConstraintSet.PARENT_ID
- else R.id.split_shade_guideline,
+ if (keyguardSmartspaceViewModel.isShadeLayoutWide.value) R.id.split_shade_guideline
+ else ConstraintSet.PARENT_ID,
ConstraintSet.END,
- horizontalPaddingEnd
+ horizontalPaddingEnd,
)
if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) {
@@ -151,7 +152,7 @@ constructor(
sharedR.id.date_smartspace_view,
ConstraintSet.BOTTOM,
sharedR.id.bc_smartspace_view,
- ConstraintSet.TOP
+ ConstraintSet.TOP,
)
} else {
clear(sharedR.id.date_smartspace_view, ConstraintSet.BOTTOM)
@@ -159,13 +160,13 @@ constructor(
sharedR.id.date_smartspace_view,
ConstraintSet.TOP,
customR.id.lockscreen_clock_view,
- ConstraintSet.BOTTOM
+ ConstraintSet.BOTTOM,
)
connect(
sharedR.id.bc_smartspace_view,
ConstraintSet.TOP,
sharedR.id.date_smartspace_view,
- ConstraintSet.BOTTOM
+ ConstraintSet.BOTTOM,
)
}
@@ -173,10 +174,7 @@ constructor(
R.id.smart_space_barrier_bottom,
Barrier.BOTTOM,
0,
- *intArrayOf(
- sharedR.id.bc_smartspace_view,
- sharedR.id.date_smartspace_view,
- )
+ *intArrayOf(sharedR.id.bc_smartspace_view, sharedR.id.date_smartspace_view),
)
}
updateVisibility(constraintSet)
@@ -211,7 +209,7 @@ constructor(
setVisibility(sharedR.id.weather_smartspace_view, weatherVisibility)
setAlpha(
sharedR.id.weather_smartspace_view,
- if (weatherVisibility == View.VISIBLE) 1f else 0f
+ if (weatherVisibility == View.VISIBLE) 1f else 0f,
)
val dateVisibility =
if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) ConstraintSet.GONE
@@ -219,7 +217,7 @@ constructor(
setVisibility(sharedR.id.date_smartspace_view, dateVisibility)
setAlpha(
sharedR.id.date_smartspace_view,
- if (dateVisibility == ConstraintSet.VISIBLE) 1f else 0f
+ if (dateVisibility == ConstraintSet.VISIBLE) 1f else 0f,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
index 5dbba75411a5..f0d21f22c5ee 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
@@ -28,20 +28,22 @@ import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.systemui.customization.R as customR
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
/** Aligns media on left side for split shade, below smartspace, date, and weather. */
class SplitShadeMediaSection
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val notificationPanelView: NotificationPanelView,
- private val keyguardMediaController: KeyguardMediaController
+ private val keyguardMediaController: KeyguardMediaController,
) : KeyguardSection() {
private val mediaContainerId = R.id.status_view_media_container
@@ -61,7 +63,7 @@ constructor(
val horizontalPadding =
padding +
context.resources.getDimensionPixelSize(
- R.dimen.status_view_margin_horizontal
+ customR.dimen.status_view_margin_horizontal
)
setPaddingRelative(horizontalPadding, padding, horizontalPadding, padding)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
index 1a7386678e14..729759a9ad00 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
@@ -26,6 +26,7 @@ import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
@@ -35,7 +36,7 @@ import javax.inject.Inject
class SplitShadeNotificationStackScrollLayoutSection
@Inject
constructor(
- context: Context,
+ @ShadeDisplayAware context: Context,
notificationPanelView: NotificationPanelView,
sharedNotificationContainer: SharedNotificationContainer,
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
index 56e3125f7078..3a5263f3df77 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
@@ -41,7 +41,7 @@ import kotlinx.coroutines.flow.onStart
class AlternateBouncerUdfpsIconViewModel
@Inject
constructor(
- val context: Context,
+ @ShadeDisplayAware val context: Context,
@ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
deviceEntryBackgroundViewModel: DeviceEntryBackgroundViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 12f9467c0f96..29ae4b94be6a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -40,7 +40,7 @@ import kotlinx.coroutines.flow.onStart
class DeviceEntryBackgroundViewModel
@Inject
constructor(
- val context: Context,
+ @ShadeDisplayAware val context: Context,
val deviceEntryIconViewModel: DeviceEntryIconViewModel,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
@ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index 749f19315409..19652525bee0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -31,8 +31,10 @@ import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
@@ -40,12 +42,13 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
/** Models the UI state for the device entry icon foreground view (displayed icon). */
+@OptIn(FlowPreview::class)
@ExperimentalCoroutinesApi
@SysUISingleton
class DeviceEntryForegroundViewModel
@Inject
constructor(
- val context: Context,
+ @ShadeDisplayAware val context: Context,
@ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
transitionInteractor: KeyguardTransitionInteractor,
@@ -97,7 +100,7 @@ constructor(
private val padding: Flow<Int> =
deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported ->
if (udfpsSupported) {
- udfpsOverlayInteractor.iconPadding
+ udfpsOverlayInteractor.iconPadding.debounce(udfpsPaddingDebounceDuration.toLong())
} else {
configurationInteractor.scaleForResolution.map { scale ->
(context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding) * scale)
@@ -120,6 +123,9 @@ constructor(
)
}
+ private val udfpsPaddingDebounceDuration: Int
+ get() = context.resources.getInteger(R.integer.udfps_padding_debounce_duration)
+
data class ForegroundIconViewModel(
val type: DeviceEntryIconView.IconType,
val useAodVariant: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 82adced1e1be..6e30e482bda0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.content.Context
import android.content.res.Resources
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.helper.widget.Layer
@@ -27,7 +28,8 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
-import com.android.systemui.res.R
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
+import com.android.systemui.plugins.clocks.DefaultClockFaceLayout.Companion.getSmallClockTopPadding
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -46,6 +48,7 @@ import kotlinx.coroutines.flow.stateIn
class KeyguardClockViewModel
@Inject
constructor(
+ val context: Context,
keyguardClockInteractor: KeyguardClockInteractor,
@Application private val applicationScope: CoroutineScope,
aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
@@ -158,16 +161,15 @@ constructor(
)
/** Calculates the top margin for the small clock. */
- fun getSmallClockTopMargin(): Int {
- val statusBarHeight = systemBarUtils.getStatusBarHeaderHeightKeyguard()
- return if (shadeInteractor.isShadeLayoutWide.value) {
- resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) -
- if (SceneContainerFlag.isEnabled) statusBarHeight else 0
- } else {
- resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
- if (!SceneContainerFlag.isEnabled) statusBarHeight else 0
- }
- }
+ fun getSmallClockTopMargin(): Int =
+ getSmallClockTopPadding(
+ ClockPreviewConfig(
+ context,
+ shadeInteractor.isShadeLayoutWide.value,
+ SceneContainerFlag.isEnabled,
+ ),
+ systemBarUtils.getStatusBarHeaderHeightKeyguard(),
+ )
val smallClockTopMargin =
combine(
@@ -187,6 +189,9 @@ constructor(
val largeClockTopMargin: Flow<Int> =
configurationInteractor.onAnyConfigurationChange.map { getLargeClockTopMargin() }
+ val largeClockTextSize: Flow<Int> =
+ configurationInteractor.dimensionPixelSize(customR.dimen.large_clock_text_size)
+
enum class ClockLayout {
LARGE_CLOCK,
SMALL_CLOCK,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt
index 65c0f57b76f5..1c4498212502 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt
@@ -17,11 +17,12 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.content.Context
-import com.android.internal.policy.SystemBarUtils
import com.android.systemui.customization.R as customR
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
-import com.android.systemui.res.R
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
+import com.android.systemui.plugins.clocks.DefaultClockFaceLayout.Companion.getSmallClockTopPadding
+import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -35,6 +36,7 @@ constructor(
interactor: KeyguardClockInteractor,
val smartspaceViewModel: KeyguardSmartspaceViewModel,
val clockViewModel: KeyguardClockViewModel,
+ private val systemBarUtils: SystemBarUtilsProxy,
) {
val selectedClockSize: StateFlow<ClockSizeSetting> = interactor.selectedClockSize
@@ -59,29 +61,18 @@ constructor(
return KeyguardSmartspaceViewModel.getSmartspaceEndMargin(context)
}
- fun getSmallClockSmartspaceTopPadding(splitShadePreview: Boolean, context: Context): Int {
- return getSmallClockTopPadding(splitShadePreview, context) +
- context.resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_height
- )
- }
-
- fun getLargeClockSmartspaceTopPadding(splitShadePreview: Boolean, context: Context): Int {
- return getSmallClockTopPadding(splitShadePreview, context)
- }
-
/*
* SmallClockTopPadding decides the top position of smartspace
*/
- private fun getSmallClockTopPadding(splitShadePreview: Boolean, context: Context): Int {
- return with(context.resources) {
- if (splitShadePreview) {
- getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
- } else {
- getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
- SystemBarUtils.getStatusBarHeight(context) +
- getDimensionPixelSize(customR.dimen.keyguard_smartspace_top_offset)
- }
- }
+ fun getSmallClockSmartspaceTopPadding(config: ClockPreviewConfig): Int {
+ return getSmallClockTopPadding(config, systemBarUtils.getStatusBarHeaderHeightKeyguard()) +
+ config.previewContext.resources.getDimensionPixelSize(customR.dimen.small_clock_height)
+ }
+
+ fun getLargeClockSmartspaceTopPadding(clockPreviewConfig: ClockPreviewConfig): Int {
+ return getSmallClockTopPadding(
+ clockPreviewConfig,
+ systemBarUtils.getStatusBarHeaderHeightKeyguard(),
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
index e30ddc69b19d..3266dc45427a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
@@ -17,10 +17,12 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.content.Context
+import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
import com.android.systemui.res.R
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -38,6 +40,7 @@ constructor(
smartspaceController: LockscreenSmartspaceController,
keyguardClockViewModel: KeyguardClockViewModel,
smartspaceInteractor: KeyguardSmartspaceInteractor,
+ shadeInteractor: ShadeInteractor,
) {
/** Whether the smartspace section is available in the build. */
val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled
@@ -59,10 +62,9 @@ constructor(
/** Whether the weather area should be visible. */
val isWeatherVisible: StateFlow<Boolean> =
- combine(
+ combine(isWeatherEnabled, keyguardClockViewModel.hasCustomWeatherDataDisplay) {
isWeatherEnabled,
- keyguardClockViewModel.hasCustomWeatherDataDisplay,
- ) { isWeatherEnabled, clockIncludesCustomWeatherDisplay ->
+ clockIncludesCustomWeatherDisplay ->
isWeatherVisible(
clockIncludesCustomWeatherDisplay = clockIncludesCustomWeatherDisplay,
isWeatherEnabled = isWeatherEnabled,
@@ -76,7 +78,7 @@ constructor(
clockIncludesCustomWeatherDisplay =
keyguardClockViewModel.hasCustomWeatherDataDisplay.value,
isWeatherEnabled = smartspaceInteractor.isWeatherEnabled.value,
- )
+ ),
)
private fun isWeatherVisible(
@@ -89,15 +91,17 @@ constructor(
/* trigger clock and smartspace constraints change when smartspace appears */
val bcSmartspaceVisibility: StateFlow<Int> = smartspaceInteractor.bcSmartspaceVisibility
+ val isShadeLayoutWide: StateFlow<Boolean> = shadeInteractor.isShadeLayoutWide
+
companion object {
fun getSmartspaceStartMargin(context: Context): Int {
return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start) +
- context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
+ context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal)
}
fun getSmartspaceEndMargin(context: Context): Int {
return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end) +
- context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
+ context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt
index 6adf3e9894bd..a249793798ed 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt
@@ -25,6 +25,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow.FlowBuilder
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.SysuiStatusBarStateController
import javax.inject.Inject
@@ -50,9 +51,7 @@ constructor(
duration = FromLockscreenTransitionInteractor.TO_GONE_DURATION,
edge = Edge.create(from = LOCKSCREEN, to = Scenes.Gone),
)
- .setupWithoutSceneContainer(
- edge = Edge.create(from = LOCKSCREEN, to = GONE),
- )
+ .setupWithoutSceneContainer(edge = Edge.create(from = LOCKSCREEN, to = GONE))
val shortcutsAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
@@ -65,6 +64,10 @@ constructor(
fun notificationAlpha(viewState: ViewStateAccessor): Flow<Float> {
var startAlpha = 1f
var leaveShadeOpen = false
+ val endAction: (() -> Float)? =
+ if (SceneContainerFlag.isEnabled) {
+ { 1f }
+ } else null
return transitionAnimation.sharedFlow(
duration = 80.milliseconds,
@@ -79,6 +82,8 @@ constructor(
MathUtils.lerp(startAlpha, 0f, it)
}
},
+ onFinish = endAction,
+ onCancel = endAction,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
index 6f29004d4f3f..618b04700afb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
@@ -23,6 +23,7 @@ import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -44,6 +45,7 @@ constructor(
private val deviceEntryInteractor: DeviceEntryInteractor,
private val communalInteractor: CommunalInteractor,
private val shadeInteractor: ShadeInteractor,
+ private val occlusionInteractor: SceneContainerOcclusionInteractor,
) : UserActionsViewModel() {
override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
@@ -57,7 +59,8 @@ constructor(
deviceEntryInteractor.isUnlocked,
communalInteractor.isCommunalAvailable,
shadeInteractor.shadeMode,
- ) { isDeviceUnlocked, isCommunalAvailable, shadeMode ->
+ occlusionInteractor.isOccludingActivityShown,
+ ) { isDeviceUnlocked, isCommunalAvailable, shadeMode, isOccluded ->
buildList {
if (isCommunalAvailable) {
add(Swipe.Start to Scenes.Communal)
@@ -67,7 +70,8 @@ constructor(
addAll(
when (shadeMode) {
- ShadeMode.Single -> singleShadeActions()
+ ShadeMode.Single ->
+ singleShadeActions(isDownFromTopEdgeEnabled = !isOccluded)
ShadeMode.Split -> splitShadeActions()
ShadeMode.Dual -> dualShadeActions()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
index da96f3fd1f9c..3de1f1e6258e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
@@ -40,6 +40,7 @@ import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatu
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.phone.DozeServiceHost
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -66,7 +67,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch
class SideFpsProgressBarViewModel
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
biometricStatusInteractor: BiometricStatusInteractor,
deviceEntryFingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
private val sfpsSensorInteractor: SideFpsSensorInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
index 881228d597b0..93ecae32ac17 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
@@ -21,11 +21,11 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshots.StateFactoryMarker
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.app.tracing.coroutines.traceCoroutine
+import com.android.systemui.log.table.TableLogBuffer
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Keeps snapshot/Compose [State]s up-to-date.
@@ -47,6 +47,12 @@ class Hydrator(
* concatenation or templating.
*/
private val traceName: String,
+ /**
+ * An optional [TableLogBuffer] to log emissions to the states. [traceName] will be used as the
+ * prefix for the columns logged by this [Hydrator], allowing to aggregate multiple hydrators in
+ * the same table.
+ */
+ private val tableLogBuffer: TableLogBuffer? = null,
) : ExclusiveActivatable() {
private val children = mutableListOf<NamedActivatable>()
@@ -62,15 +68,8 @@ class Hydrator(
* automatically set on the returned [State].
*/
@StateFactoryMarker
- fun <T> hydratedStateOf(
- traceName: String,
- source: StateFlow<T>,
- ): State<T> {
- return hydratedStateOf(
- traceName = traceName,
- initialValue = source.value,
- source = source,
- )
+ fun <T> hydratedStateOf(traceName: String, source: StateFlow<T>): State<T> {
+ return hydratedStateOf(traceName = traceName, initialValue = source.value, source = source)
}
/**
@@ -81,26 +80,44 @@ class Hydrator(
* performance findings with actual code. One recommendation: prefer whole string literals
* instead of some complex concatenation or templating scheme. Use `null` to disable
* performance tracing for this state.
+ *
+ * If a [TableLogBuffer] was provided, every emission to the flow will be logged using the
+ * [traceName] as the column name. For this to work correctly, all the states in the same
+ * hydrator should have different [traceName]. Use `null` to disable logging for this state.
+ *
* @param initialValue The first value to place on the [State]
* @param source The upstream [Flow] to collect from; values emitted to it will be automatically
* set on the returned [State].
*/
@StateFactoryMarker
- fun <T> hydratedStateOf(
- traceName: String?,
- initialValue: T,
- source: Flow<T>,
- ): State<T> {
+ fun <T> hydratedStateOf(traceName: String?, initialValue: T, source: Flow<T>): State<T> {
check(!isActive) { "Cannot call hydratedStateOf after Hydrator is already active." }
val mutableState = mutableStateOf(initialValue)
+ traceName?.let { name ->
+ tableLogBuffer?.logChange(
+ prefix = this.traceName,
+ columnName = name,
+ value = initialValue?.toString(),
+ isInitial = true,
+ )
+ }
children.add(
NamedActivatable(
traceName = traceName,
activatable =
object : ExclusiveActivatable() {
override suspend fun onActivated(): Nothing {
- source.collect { mutableState.value = it }
+ source.collect {
+ traceName?.let { name ->
+ tableLogBuffer?.logChange(
+ prefix = this@Hydrator.traceName,
+ columnName = name,
+ value = it?.toString(),
+ )
+ }
+ mutableState.value = it
+ }
awaitCancellation()
}
},
@@ -122,8 +139,5 @@ class Hydrator(
}
}
- private data class NamedActivatable(
- val traceName: String?,
- val activatable: Activatable,
- )
+ private data class NamedActivatable(val traceName: String?, val activatable: Activatable)
}
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 4c21da52db3a..8097d9585fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -32,8 +32,6 @@ import com.android.systemui.plugins.clocks.ClockMessageBuffers;
import com.android.systemui.qs.QSFragmentLegacy;
import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository;
import com.android.systemui.qs.pipeline.shared.TileSpec;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.util.Compile;
import com.android.systemui.util.wakelock.WakeLockLog;
import dagger.Lazy;
@@ -56,61 +54,6 @@ public class LogModule {
return factory.create("DozeLog", 150);
}
- /** Provides a logging buffer for all logs related to the data layer of notifications. */
- @Provides
- @SysUISingleton
- @NotificationLog
- public static LogBuffer provideNotificationsLogBuffer(
- LogBufferFactory factory,
- NotifPipelineFlags notifPipelineFlags) {
- int maxSize = 1000;
- if (Compile.IS_DEBUG && notifPipelineFlags.isDevLoggingEnabled()) {
- maxSize *= 10;
- }
- return factory.create("NotifLog", maxSize, Compile.IS_DEBUG /* systrace */);
- }
-
- /** Provides a logging buffer for all logs related to notifications on the lockscreen. */
- @Provides
- @SysUISingleton
- @NotificationLockscreenLog
- public static LogBuffer provideNotificationLockScreenLogBuffer(
- LogBufferFactory factory) {
- return factory.create("NotifLockscreenLog", 50, false /* systrace */);
- }
-
- /** Provides a logging buffer for logs related to heads up presentation of notifications. */
- @Provides
- @SysUISingleton
- @NotificationHeadsUpLog
- public static LogBuffer provideNotificationHeadsUpLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifHeadsUpLog", 1000);
- }
-
- /** Provides a logging buffer for logs related to inflation of notifications. */
- @Provides
- @SysUISingleton
- @NotifInflationLog
- public static LogBuffer provideNotifInflationLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifInflationLog", 250);
- }
-
- /** Provides a logging buffer for notification interruption calculations. */
- @Provides
- @SysUISingleton
- @NotificationInterruptLog
- public static LogBuffer provideNotificationInterruptLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifInterruptLog", 100);
- }
-
- /** Provides a logging buffer for notification rendering events. */
- @Provides
- @SysUISingleton
- @NotificationRenderLog
- public static LogBuffer provideNotificationRenderLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifRenderLog", 100);
- }
-
/** Provides a logging buffer for all logs for lockscreen to shade transition events. */
@Provides
@SysUISingleton
@@ -119,16 +62,6 @@ public class LogModule {
return factory.create("LSShadeTransitionLog", 50);
}
- /** */
- @Provides
- @SysUISingleton
- @SensitiveNotificationProtectionLog
- public static LogBuffer provideSensitiveNotificationProtectionLogBuffer(
- LogBufferFactory factory
- ) {
- return factory.create("SensitiveNotificationProtectionLog", 10);
- }
-
/** Provides a logging buffer for shade window messages. */
@Provides
@SysUISingleton
@@ -153,30 +86,6 @@ public class LogModule {
return factory.create("ShadeTouchLog", 500, false);
}
- /** Provides a logging buffer for all logs related to managing notification sections. */
- @Provides
- @SysUISingleton
- @NotificationSectionLog
- public static LogBuffer provideNotificationSectionLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifSectionLog", 1000 /* maxSize */, false /* systrace */);
- }
-
- /** Provides a logging buffer for all logs related to remote input controller. */
- @Provides
- @SysUISingleton
- @NotificationRemoteInputLog
- public static LogBuffer provideNotificationRemoteInputLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifRemoteInputLog", 50 /* maxSize */, false /* systrace */);
- }
-
- /** Provides a logging buffer for all logs related to notification visual stability. */
- @Provides
- @SysUISingleton
- @VisualStabilityLog
- public static LogBuffer provideVisualStabilityLogBuffer(LogBufferFactory factory) {
- return factory.create("VisualStabilityLog", 50 /* maxSize */, false /* systrace */);
- }
-
/** Provides a logging buffer for all logs related to keyguard media controller. */
@Provides
@SysUISingleton
@@ -185,22 +94,6 @@ public class LogModule {
return factory.create("KeyguardMediaControllerLog", 50 /* maxSize */, false /* systrace */);
}
- /** Provides a logging buffer for all logs related to unseen notifications. */
- @Provides
- @SysUISingleton
- @UnseenNotificationLog
- public static LogBuffer provideUnseenNotificationLogBuffer(LogBufferFactory factory) {
- return factory.create("UnseenNotifLog", 20 /* maxSize */, false /* systrace */);
- }
-
- /** Provides a logging buffer for all logs related to the data layer of notifications. */
- @Provides
- @SysUISingleton
- @NotifInteractionLog
- public static LogBuffer provideNotifInteractionLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifInteractionLog", 50);
- }
-
/** Provides a logging buffer for all logs related to Quick Settings. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
index 35efd751b8fe..7d3094827e17 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
@@ -20,6 +20,7 @@ import android.app.ActivityManager.RunningTaskInfo
import android.hardware.display.DisplayManager
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
+import android.media.projection.StopReason
import android.os.Handler
import android.view.ContentRecordingSession
import android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY
@@ -72,7 +73,7 @@ constructor(
}
}
- override suspend fun stopProjecting() {
+ override suspend fun stopProjecting(@StopReason stopReason: Int) {
withContext(backgroundDispatcher) {
logger.log(
TAG,
@@ -80,7 +81,7 @@ constructor(
{},
{ "Requesting MediaProjectionManager#stopActiveProjection" },
)
- mediaProjectionManager.stopActiveProjection()
+ mediaProjectionManager.stopActiveProjection(stopReason)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
index 50182d7a3b33..a01d8c2c98de 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.mediaprojection.data.repository
import android.app.ActivityManager.RunningTaskInfo
+import android.media.projection.StopReason
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import kotlinx.coroutines.flow.Flow
@@ -27,7 +28,7 @@ interface MediaProjectionRepository {
suspend fun switchProjectedTask(task: RunningTaskInfo)
/** Stops the currently active projection. */
- suspend fun stopProjecting()
+ suspend fun stopProjecting(@StopReason stopReason: Int)
/** Represents the current [MediaProjectionState]. */
val mediaProjectionState: Flow<MediaProjectionState>
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl b/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
index 3e947d9d2b16..7803f229dda7 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
+++ b/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
@@ -16,6 +16,7 @@
package com.android.systemui.notetask;
+import com.android.systemui.notetask.NoteTaskBubbleExpandBehavior;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
@@ -25,5 +26,6 @@ interface INoteTaskBubblesService {
boolean areBubblesAvailable();
- void showOrHideAppBubble(in Intent intent, in UserHandle userHandle, in Icon icon);
+ void showOrHideAppBubble(in Intent intent, in UserHandle userHandle, in Icon icon,
+ in NoteTaskBubbleExpandBehavior bubbleExpandBehavior);
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.aidl b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.aidl
new file mode 100644
index 000000000000..86a06a568a4b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.aidl
@@ -0,0 +1,3 @@
+package com.android.systemui.notetask;
+
+parcelable NoteTaskBubbleExpandBehavior; \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.kt
new file mode 100644
index 000000000000..63b38a1b73f9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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.notetask
+
+import android.os.Parcel
+import android.os.Parcelable
+
+enum class NoteTaskBubbleExpandBehavior : Parcelable {
+ /**
+ * The default bubble expand behavior for note task bubble: The bubble will collapse if there is
+ * already an expanded bubble, The bubble will expand if there is a collapsed bubble.
+ */
+ DEFAULT,
+ /**
+ * The special bubble expand behavior for note task bubble: The bubble will stay expanded, not
+ * collapse, if there is already an expanded bubble, The bubble will expand if there is a
+ * collapsed bubble.
+ */
+ KEEP_IF_EXPANDED;
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(dest: Parcel, flags: Int) {
+ dest.writeString(name)
+ }
+
+ companion object CREATOR : Parcelable.Creator<NoteTaskBubbleExpandBehavior> {
+ override fun createFromParcel(parcel: Parcel?): NoteTaskBubbleExpandBehavior {
+ return parcel?.readString()?.let { valueOf(it) } ?: DEFAULT
+ }
+
+ override fun newArray(size: Int) = arrayOfNulls<NoteTaskBubbleExpandBehavior>(size)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
index ec205f87d9fa..169285f6742e 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
@@ -27,6 +27,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.DebugLogger.debugLog
+import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.Bubbles
import java.util.Optional
import javax.inject.Inject
@@ -48,7 +49,7 @@ open class NoteTaskBubblesController
@Inject
constructor(
@Application private val context: Context,
- @Background private val bgDispatcher: CoroutineDispatcher
+ @Background private val bgDispatcher: CoroutineDispatcher,
) {
private val serviceConnector: ServiceConnector<INoteTaskBubblesService> =
@@ -57,7 +58,7 @@ constructor(
Intent(context, NoteTaskBubblesService::class.java),
Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
UserHandle.USER_SYSTEM,
- INoteTaskBubblesService.Stub::asInterface
+ INoteTaskBubblesService.Stub::asInterface,
)
/** Returns whether notes app bubble is supported. */
@@ -79,11 +80,12 @@ constructor(
open suspend fun showOrHideAppBubble(
intent: Intent,
userHandle: UserHandle,
- icon: Icon
+ icon: Icon,
+ bubbleExpandBehavior: NoteTaskBubbleExpandBehavior,
) {
withContext(bgDispatcher) {
serviceConnector
- .post { it.showOrHideAppBubble(intent, userHandle, icon) }
+ .post { it.showOrHideAppBubble(intent, userHandle, icon, bubbleExpandBehavior) }
.whenComplete { _, error ->
if (error != null) {
debugLog(error = error) {
@@ -120,16 +122,28 @@ constructor(
override fun showOrHideAppBubble(
intent: Intent,
userHandle: UserHandle,
- icon: Icon
+ icon: Icon,
+ bubbleExpandBehavior: NoteTaskBubbleExpandBehavior,
) {
mOptionalBubbles.ifPresentOrElse(
- { bubbles -> bubbles.showOrHideAppBubble(intent, userHandle, icon) },
+ { bubbles ->
+ if (
+ bubbleExpandBehavior ==
+ NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED &&
+ bubbles.isBubbleExpanded(
+ Bubble.getAppBubbleKeyForApp(intent.`package`, userHandle)
+ )
+ ) {
+ return@ifPresentOrElse
+ }
+ bubbles.showOrHideAppBubble(intent, userHandle, icon)
+ },
{
debugLog {
"Failed to show or hide bubble for intent $intent," +
"user $user, and icon $icon as bubble is empty."
}
- }
+ },
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 1fa5baaa21ae..ad1f37070c9d 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -43,6 +43,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
import com.android.systemui.log.DebugLogger.debugLog
+import com.android.systemui.notetask.NoteTaskEntryPoint.KEYBOARD_SHORTCUT
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser
@@ -84,7 +85,7 @@ constructor(
private val userTracker: UserTracker,
private val secureSettings: SecureSettings,
@Application private val applicationScope: CoroutineScope,
- @Background private val bgCoroutineContext: CoroutineContext
+ @Background private val bgCoroutineContext: CoroutineContext,
) {
@VisibleForTesting val infoReference = AtomicReference<NoteTaskInfo?>()
@@ -98,7 +99,7 @@ constructor(
if (key != Bubble.getAppBubbleKeyForApp(info.packageName, info.user)) return
// Safe guard mechanism, this callback should only be called for app bubbles.
- if (info.launchMode != NoteTaskLaunchMode.AppBubble) return
+ if (info.launchMode !is NoteTaskLaunchMode.AppBubble) return
if (isExpanding) {
debugLog { "onBubbleExpandChanged - expanding: $info" }
@@ -117,10 +118,7 @@ constructor(
} else {
getUserForHandlingNotesTaking(entryPoint)
}
- activityContext.startActivityAsUser(
- createNotesRoleHolderSettingsIntent(),
- user
- )
+ activityContext.startActivityAsUser(createNotesRoleHolderSettingsIntent(), user)
}
/**
@@ -140,8 +138,7 @@ constructor(
entryPoint == QUICK_AFFORDANCE -> {
userTracker.userProfiles
.firstOrNull { userManager.isManagedProfile(it.id) }
- ?.userHandle
- ?: userTracker.userHandle
+ ?.userHandle ?: userTracker.userHandle
}
// On work profile devices, SysUI always run in the main user.
else -> userTracker.userHandle
@@ -158,19 +155,14 @@ constructor(
*
* That will let users open other apps in full screen, and take contextual notes.
*/
- fun showNoteTask(
- entryPoint: NoteTaskEntryPoint,
- ) {
+ fun showNoteTask(entryPoint: NoteTaskEntryPoint) {
if (!isEnabled) return
showNoteTaskAsUser(entryPoint, getUserForHandlingNotesTaking(entryPoint))
}
/** A variant of [showNoteTask] which launches note task in the given [user]. */
- fun showNoteTaskAsUser(
- entryPoint: NoteTaskEntryPoint,
- user: UserHandle,
- ) {
+ fun showNoteTaskAsUser(entryPoint: NoteTaskEntryPoint, user: UserHandle) {
if (!isEnabled) return
applicationScope.launch("$TAG#showNoteTaskAsUser") {
@@ -178,10 +170,7 @@ constructor(
}
}
- private suspend fun awaitShowNoteTaskAsUser(
- entryPoint: NoteTaskEntryPoint,
- user: UserHandle,
- ) {
+ private suspend fun awaitShowNoteTaskAsUser(entryPoint: NoteTaskEntryPoint, user: UserHandle) {
if (!isEnabled) return
if (!noteTaskBubblesController.areBubblesAvailable()) {
@@ -217,12 +206,26 @@ constructor(
try {
// TODO(b/266686199): We should handle when app not available. For now, we log.
debugLog { "onShowNoteTask - start: $info on user#${user.identifier}" }
+ val useStylusMode =
+ when {
+ info.entryPoint == TAIL_BUTTON -> true
+ info.entryPoint == KEYBOARD_SHORTCUT -> false
+ else ->
+ context.resources.getInteger(R.integer.config_preferredNotesMode) ==
+ PREFERRED_NOTES_MODE_STYLUS
+ }
when (info.launchMode) {
is NoteTaskLaunchMode.AppBubble -> {
- val intent = createNoteTaskIntent(info)
+ val intent = createNoteTaskIntent(info, useStylusMode)
val icon =
Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
- noteTaskBubblesController.showOrHideAppBubble(intent, user, icon)
+ noteTaskBubblesController.showOrHideAppBubble(
+ intent,
+ user,
+ icon,
+ info.launchMode.bubbleExpandBehavior,
+ )
+
// App bubble logging happens on `onBubbleExpandChanged`.
debugLog { "onShowNoteTask - opened as app bubble: $info" }
}
@@ -234,7 +237,7 @@ constructor(
eventLogger.logNoteTaskClosed(info)
debugLog { "onShowNoteTask - closed as activity: $info" }
} else {
- val intent = createNoteTaskIntent(info)
+ val intent = createNoteTaskIntent(info, useStylusMode)
context.startActivityAsUser(intent, user)
eventLogger.logNoteTaskOpened(info)
debugLog { "onShowNoteTask - opened as activity: $info" }
@@ -398,20 +401,21 @@ constructor(
*/
const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE = "extra_shortcut_badge_override_package"
+ const val PREFERRED_NOTES_MODE_STYLUS = 1
+
/** Returns notes role holder settings intent. */
- fun createNotesRoleHolderSettingsIntent() = Intent(Intent.ACTION_MANAGE_DEFAULT_APP).
- putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NOTES)
+ fun createNotesRoleHolderSettingsIntent() =
+ Intent(Intent.ACTION_MANAGE_DEFAULT_APP).putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NOTES)
}
}
/** Creates an [Intent] for [ROLE_NOTES]. */
-private fun createNoteTaskIntent(info: NoteTaskInfo): Intent =
+private fun createNoteTaskIntent(info: NoteTaskInfo, useStylusMode: Boolean): Intent =
Intent(Intent.ACTION_CREATE_NOTE).apply {
setPackage(info.packageName)
// EXTRA_USE_STYLUS_MODE does not mean a stylus is in-use, but a stylus entrypoint
// was used to start the note task.
- val useStylusMode = info.entryPoint != NoteTaskEntryPoint.KEYBOARD_SHORTCUT
putExtra(Intent.EXTRA_USE_STYLUS_MODE, useStylusMode)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
index 269eb870686c..8319e07525d8 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
@@ -31,6 +31,10 @@ data class NoteTaskInfo(
if (isKeyguardLocked || entryPoint == WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE) {
NoteTaskLaunchMode.Activity
} else {
- NoteTaskLaunchMode.AppBubble
+ if (entryPoint == NoteTaskEntryPoint.QS_NOTES_TILE) {
+ NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED)
+ } else {
+ NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.DEFAULT)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt
index 836e103f4d69..6c85f20f2bce 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt
@@ -26,7 +26,8 @@ import com.android.wm.shell.bubbles.Bubbles
sealed class NoteTaskLaunchMode {
/** @see Bubbles.showOrHideAppBubble */
- object AppBubble : NoteTaskLaunchMode()
+ data class AppBubble(val bubbleExpandBehavior: NoteTaskBubbleExpandBehavior) :
+ NoteTaskLaunchMode()
/** @see Context.startActivity */
object Activity : NoteTaskLaunchMode()
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index a1c5c9c682c3..5d5465633f9f 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -41,6 +41,7 @@ import com.android.systemui.qs.tiles.impl.notes.domain.model.NotesTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel
import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
@@ -106,12 +107,14 @@ interface NoteTaskModule {
stateInteractor: NotesTileDataInteractor,
userActionInteractor: NotesTileUserActionInteractor,
): QSTileViewModel =
- factory.create(
- TileSpec.create(NOTES_TILE_SPEC),
- userActionInteractor,
- stateInteractor,
- mapper,
- )
+ if (com.android.systemui.Flags.qsNewTilesFuture())
+ factory.create(
+ TileSpec.create(NOTES_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
+ else StubQSTileViewModel
@Provides
@IntoMap
@@ -120,10 +123,10 @@ interface NoteTaskModule {
QSTileConfig(
tileSpec = TileSpec.create(NOTES_TILE_SPEC),
uiConfig =
- QSTileUIConfig.Resource(
- iconRes = R.drawable.ic_qs_notes,
- labelRes = R.string.quick_settings_notes_label,
- ),
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.ic_qs_notes,
+ labelRes = R.string.quick_settings_notes_label,
+ ),
instanceId = uiEventLogger.getNewInstanceId(),
category = TileCategory.UTILITIES,
)
diff --git a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt
index 776a8f47f056..c57b53bab442 100644
--- a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt
@@ -26,6 +26,9 @@ enum class WakeSleepReason(
/** The physical power button was pressed to wake up or sleep the device. */
POWER_BUTTON(isTouch = false, PowerManager.WAKE_REASON_POWER_BUTTON),
+ /** The sleep button was pressed to sleep the device. */
+ SLEEP_BUTTON(isTouch = false, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON),
+
/** The user has tapped or double tapped to wake the screen. */
TAP(isTouch = true, PowerManager.WAKE_REASON_TAP),
@@ -78,6 +81,7 @@ enum class WakeSleepReason(
fun fromPowerManagerSleepReason(reason: Int): WakeSleepReason {
return when (reason) {
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON -> POWER_BUTTON
+ PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON -> SLEEP_BUTTON
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT -> TIMEOUT
PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD -> FOLD
else -> OTHER
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index d715f42ed499..dc188c24e02b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,8 +16,11 @@
package com.android.systemui.qs;
+import static com.android.systemui.Flags.gsfQuickSettings;
+
import android.content.ClipData;
import android.content.ClipboardManager;
+import android.graphics.Typeface;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
@@ -64,6 +67,9 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
mRetailModeInteractor = retailModeInteractor;
mBuildText = mView.findViewById(R.id.build);
+ if (gsfQuickSettings()) {
+ mBuildText.setTypeface(Typeface.create("gsf-body-medium", Typeface.NORMAL));
+ }
mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
mEditButton = mView.findViewById(android.R.id.edit);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
index 8b0694219630..0d464f5a0936 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
@@ -28,6 +28,7 @@ import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Compa
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -48,7 +49,7 @@ class QSHostAdapter
@Inject
constructor(
private val interactor: CurrentTilesInteractor,
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val tileServiceRequestControllerBuilder: TileServiceRequestController.Builder,
@Application private val scope: CoroutineScope,
dumpManager: DumpManager,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 85bcc25e140c..afb852ae824c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -50,6 +50,7 @@ import com.android.systemui.util.kotlin.JavaAdapterKt;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
+import kotlinx.coroutines.DisposableHandle;
import kotlinx.coroutines.flow.StateFlow;
import java.io.PrintWriter;
@@ -107,6 +108,8 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
setLayoutForMediaInScene();
};
+ private DisposableHandle mJavaAdapterDisposableHandle;
+
private boolean mLastListening;
@VisibleForTesting
@@ -221,6 +224,9 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
mView.removeTile(record);
}
mRecords.clear();
+ if (mJavaAdapterDisposableHandle != null) {
+ mJavaAdapterDisposableHandle.dispose();
+ }
}
@Override
@@ -255,7 +261,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
}
private void registerForMediaInteractorChanges() {
- JavaAdapterKt.collectFlow(
+ mJavaAdapterDisposableHandle = JavaAdapterKt.collectFlow(
mView,
getMediaVisibleFlow(),
mMediaOrRecommendationVisibleConsumer
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index d38f8492c883..88f0318c2fbf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -87,6 +87,7 @@ import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig;
import com.android.systemui.res.R;
import com.android.systemui.security.data.model.SecurityModel;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
@@ -177,7 +178,7 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener {
@Inject
QSSecurityFooterUtils(
- @Application Context context, DevicePolicyManager devicePolicyManager,
+ @ShadeDisplayAware Context context, DevicePolicyManager devicePolicyManager,
UserTracker userTracker, @Main Handler mainHandler, ActivityStarter activityStarter,
SecurityController securityController, @Background Looper bgLooper,
DialogTransitionAnimator dialogTransitionAnimator) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 51ff598c580b..5167d173647e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -51,6 +51,7 @@ import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -70,6 +71,7 @@ import androidx.compose.ui.layout.approachLayout
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.layout.positionInRoot
+import androidx.compose.ui.layout.positionOnScreen
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
@@ -77,6 +79,7 @@ import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round
import androidx.compose.ui.util.fastRoundToInt
import androidx.compose.ui.viewinterop.AndroidView
@@ -101,6 +104,8 @@ import com.android.systemui.Dumpable
import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyboard.shortcut.ui.composable.InteractionsConfig
+import com.android.systemui.keyboard.shortcut.ui.composable.ProvideShortcutHelperIndication
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.setSnapshotBinding
import com.android.systemui.media.controls.ui.view.MediaHost
@@ -124,6 +129,7 @@ import com.android.systemui.qs.ui.composable.QuickSettingsShade
import com.android.systemui.qs.ui.composable.QuickSettingsTheme
import com.android.systemui.res.R
import com.android.systemui.util.LifecycleFragment
+import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.asIndenting
import com.android.systemui.util.printSection
import com.android.systemui.util.println
@@ -227,6 +233,7 @@ constructor(
// Only allow scrolling when we are fully expanded. That way, we don't intercept
// swipes in lockscreen (when somehow QS is receiving touches).
{ (scrollState.canScrollForward && viewModel.isQsFullyExpanded) || isCustomizing },
+ viewModel::emitMotionEventForFalsingSwipeNested,
)
frame.addView(
composeView,
@@ -238,51 +245,54 @@ constructor(
@Composable
private fun Content() {
- PlatformTheme {
- AnimatedVisibility(
- visible = viewModel.isQsVisible,
- modifier =
- Modifier.graphicsLayer { alpha = viewModel.viewAlpha }
- // Clipping before translation to match QSContainerImpl.onDraw
- .offset {
- IntOffset(x = 0, y = viewModel.viewTranslationY.fastRoundToInt())
- }
- .thenIf(notificationScrimClippingParams.isEnabled) {
- Modifier.notificationScrimClip {
- notificationScrimClippingParams.params
+ PlatformTheme(isDarkTheme = true) {
+ ProvideShortcutHelperIndication(interactionsConfig = interactionsConfig()) {
+ AnimatedVisibility(
+ visible = viewModel.isQsVisible,
+ modifier =
+ Modifier.graphicsLayer { alpha = viewModel.viewAlpha }
+ // Clipping before translation to match QSContainerImpl.onDraw
+ .offset {
+ IntOffset(x = 0, y = viewModel.viewTranslationY.fastRoundToInt())
+ }
+ .thenIf(notificationScrimClippingParams.isEnabled) {
+ Modifier.notificationScrimClip {
+ notificationScrimClippingParams.params
+ }
}
+ // Disable touches in the whole composable while the mirror is showing.
+ // While the mirror is showing, an ancestor of the ComposeView is made
+ // alpha 0, but touches are still being captured by the composables.
+ .gesturesDisabled(viewModel.showingMirror),
+ ) {
+ val isEditing by
+ viewModel.containerViewModel.editModeViewModel.isEditing
+ .collectAsStateWithLifecycle()
+ val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS)
+ AnimatedContent(
+ targetState = isEditing,
+ transitionSpec = {
+ fadeIn(animationSpecEditMode) togetherWith
+ fadeOut(animationSpecEditMode)
+ },
+ label = "EditModeAnimatedContent",
+ ) { editing ->
+ if (editing) {
+ val qqsPadding = viewModel.qqsHeaderHeight
+ EditMode(
+ viewModel = viewModel.containerViewModel.editModeViewModel,
+ modifier =
+ Modifier.fillMaxWidth()
+ .padding(top = { qqsPadding })
+ .padding(
+ horizontal = {
+ QuickSettingsShade.Dimensions.Padding.roundToPx()
+ }
+ ),
+ )
+ } else {
+ CollapsableQuickSettingsSTL()
}
- // Disable touches in the whole composable while the mirror is showing.
- // While the mirror is showing, an ancestor of the ComposeView is made
- // alpha 0, but touches are still being captured by the composables.
- .gesturesDisabled(viewModel.showingMirror),
- ) {
- val isEditing by
- viewModel.containerViewModel.editModeViewModel.isEditing
- .collectAsStateWithLifecycle()
- val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS)
- AnimatedContent(
- targetState = isEditing,
- transitionSpec = {
- fadeIn(animationSpecEditMode) togetherWith fadeOut(animationSpecEditMode)
- },
- label = "EditModeAnimatedContent",
- ) { editing ->
- if (editing) {
- val qqsPadding = viewModel.qqsHeaderHeight
- EditMode(
- viewModel = viewModel.containerViewModel.editModeViewModel,
- modifier =
- Modifier.fillMaxWidth()
- .padding(top = { qqsPadding })
- .padding(
- horizontal = {
- QuickSettingsShade.Dimensions.Padding.roundToPx()
- }
- ),
- )
- } else {
- CollapsableQuickSettingsSTL()
}
}
}
@@ -447,8 +457,7 @@ constructor(
}
override fun setShouldUpdateSquishinessOnMedia(shouldUpdate: Boolean) {
- super.setShouldUpdateSquishinessOnMedia(shouldUpdate)
- // TODO (b/353253280)
+ viewModel.shouldUpdateSquishinessOnMedia = shouldUpdate
}
override fun setInSplitShade(isInSplitShade: Boolean) {
@@ -660,7 +669,20 @@ constructor(
Column(
modifier =
- Modifier.offset {
+ Modifier.onPlaced { coordinates ->
+ val positionOnScreen = coordinates.positionOnScreen()
+ val left = positionOnScreen.x
+ val right = left + coordinates.size.width
+ val top = positionOnScreen.y
+ val bottom = top + coordinates.size.height
+ viewModel.applyNewQsScrollerBounds(
+ left = left,
+ top = top,
+ right = right,
+ bottom = bottom,
+ )
+ }
+ .offset {
IntOffset(
x = 0,
y = viewModel.qsScrollTranslationY.fastRoundToInt(),
@@ -697,14 +719,16 @@ constructor(
max =
QuickSettingsShade.Dimensions.GridMaxHeight
),
- containerViewModel.editModeViewModel::startEditing,
)
}
}
val Media =
@Composable {
if (viewModel.qsMediaVisible) {
- MediaObject(mediaHost = viewModel.qsMediaHost)
+ MediaObject(
+ mediaHost = viewModel.qsMediaHost,
+ update = { translationY = viewModel.qsMediaTranslationY },
+ )
}
}
Box(
@@ -927,6 +951,7 @@ private class FrameLayoutTouchPassthrough(
private val clippingEnabledProvider: () -> Boolean,
private val clippingTopProvider: () -> Int,
private val canScrollForwardQs: () -> Boolean,
+ private val emitMotionEventForFalsing: () -> Unit,
) : FrameLayout(context) {
override fun isTransformedTouchPointInView(
x: Float,
@@ -943,6 +968,32 @@ private class FrameLayoutTouchPassthrough(
val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
var downY = 0f
+ var preventingIntercept = false
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ val action = event.actionMasked
+ when (action) {
+ MotionEvent.ACTION_DOWN -> {
+ preventingIntercept = false
+ if (canScrollVertically(1)) {
+ // If we can scroll down, make sure we're not intercepted by the parent
+ preventingIntercept = true
+ parent?.requestDisallowInterceptTouchEvent(true)
+ } else if (!canScrollVertically(-1)) {
+ // Don't pass on the touch to the view, because scrolling will unconditionally
+ // disallow interception even if we can't scroll.
+ // if a user can't scroll at all, we should never listen to the touch.
+ return false
+ }
+ }
+ MotionEvent.ACTION_UP -> {
+ if (preventingIntercept) {
+ emitMotionEventForFalsing()
+ }
+ }
+ }
+ return super.onTouchEvent(event)
+ }
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
// If there's a touch on this view and we can scroll down, we don't want to be intercepted
@@ -950,8 +1001,10 @@ private class FrameLayoutTouchPassthrough(
when (action) {
MotionEvent.ACTION_DOWN -> {
+ preventingIntercept = false
// If we can scroll down, make sure none of our parents intercepts us.
if (canScrollForwardQs()) {
+ preventingIntercept = true
parent?.requestDisallowInterceptTouchEvent(true)
}
downY = ev.y
@@ -987,7 +1040,11 @@ private fun Modifier.gesturesDisabled(disabled: Boolean) =
}
@Composable
-private fun MediaObject(mediaHost: MediaHost, modifier: Modifier = Modifier) {
+private fun MediaObject(
+ mediaHost: MediaHost,
+ modifier: Modifier = Modifier,
+ update: UniqueObjectHostView.() -> Unit = {},
+) {
Box {
AndroidView(
modifier = modifier,
@@ -1000,6 +1057,7 @@ private fun MediaObject(mediaHost: MediaHost, modifier: Modifier = Modifier) {
)
}
},
+ update = { view -> view.update() },
onReset = {},
)
}
@@ -1068,3 +1126,14 @@ private object ResIdTags {
const val qsScroll = "expanded_qs_scroll_view"
const val qsFooterActions = "qs_footer_actions"
}
+
+@Composable
+private fun interactionsConfig() =
+ InteractionsConfig(
+ hoverOverlayColor = MaterialTheme.colorScheme.onSurface,
+ hoverOverlayAlpha = 0.11f,
+ pressedOverlayColor = MaterialTheme.colorScheme.onSurface,
+ pressedOverlayAlpha = 0.15f,
+ // we are OK using this as our content is clipped and all corner radius are larger than this
+ surfaceCornerRadius = 28.dp,
+ )
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeLog.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeLog.kt
new file mode 100644
index 000000000000..5f151eba5c84
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeLog.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.qs.composefragment.dagger
+
+import javax.inject.Qualifier
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class QSFragmentComposeLog
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
index 676f6a426264..4c9df116bd97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
@@ -18,8 +18,10 @@ package com.android.systemui.qs.composefragment.dagger
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.qs.flags.QSComposeFragment
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.Utils
import dagger.Module
import dagger.Provides
@@ -34,8 +36,17 @@ interface QSFragmentComposeModule {
@Provides
@SysUISingleton
@Named(QS_USING_MEDIA_PLAYER)
- fun providesUsingMedia(@Application context: Context): Boolean {
+ fun providesUsingMedia(@ShadeDisplayAware context: Context): Boolean {
return QSComposeFragment.isEnabled && Utils.useQsMediaPlayer(context)
}
+
+ @Provides
+ @SysUISingleton
+ @QSFragmentComposeLog
+ fun providesQSFragmentComposeViewModelTableLog(
+ factory: TableLogBufferFactory
+ ): TableLogBuffer {
+ return factory.create("QSFragmentComposeViewModel", 200)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
index e912a0c7faa6..02498d69b83d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
@@ -26,10 +26,13 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.lifecycle.LifecycleCoroutineScope
+import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.keyguard.BouncerPanelExpansionCalculator
import com.android.systemui.Dumpable
import com.android.systemui.animation.ShadeInterpolation
+import com.android.systemui.classifier.Classifier
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -38,6 +41,7 @@ import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QQS
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
@@ -47,6 +51,7 @@ import com.android.systemui.media.dagger.MediaModule.QS_PANEL
import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.FooterActionsController
+import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeLog
import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeModule
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.panels.domain.interactor.TileSquishinessInteractor
@@ -61,6 +66,7 @@ import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
import com.android.systemui.util.LargeScreenUtils
import com.android.systemui.util.asIndenting
import com.android.systemui.util.kotlin.emitOnStart
@@ -92,13 +98,15 @@ constructor(
private val footerActionsController: FooterActionsController,
private val sysuiStatusBarStateController: SysuiStatusBarStateController,
deviceEntryInteractor: DeviceEntryInteractor,
- disableFlagsRepository: DisableFlagsRepository,
+ DisableFlagsInteractor: DisableFlagsInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val largeScreenShadeInterpolator: LargeScreenShadeInterpolator,
@ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
private val squishinessInteractor: TileSquishinessInteractor,
+ private val falsingInteractor: FalsingInteractor,
private val inFirstPageViewModel: InFirstPageViewModel,
+ @QSFragmentComposeLog private val tableLogBuffer: TableLogBuffer,
mediaInRowInLandscapeViewModelFactory: MediaInRowInLandscapeViewModel.Factory,
@Named(QUICK_QS_PANEL) val qqsMediaHost: MediaHost,
@Named(QS_PANEL) val qsMediaHost: MediaHost,
@@ -110,7 +118,7 @@ constructor(
private val qqsMediaInRowViewModel = mediaInRowInLandscapeViewModelFactory.create(LOCATION_QQS)
private val qsMediaInRowViewModel = mediaInRowInLandscapeViewModelFactory.create(LOCATION_QS)
- private val hydrator = Hydrator("QSFragmentComposeViewModel.hydrator")
+ private val hydrator = Hydrator("QSFragmentComposeViewModel.hydrator", tableLogBuffer)
val footerActionsViewModel =
footerActionsViewModelFactory.create(lifecycleScope).also {
@@ -181,8 +189,8 @@ constructor(
val isQsEnabled by
hydrator.hydratedStateOf(
traceName = "isQsEnabled",
- initialValue = disableFlagsRepository.disableFlags.value.isQuickSettingsEnabled(),
- source = disableFlagsRepository.disableFlags.map { it.isQuickSettingsEnabled() },
+ initialValue = DisableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled(),
+ source = DisableFlagsInteractor.disableFlags.map { it.isQuickSettingsEnabled() },
)
var isInSplitShade by mutableStateOf(false)
@@ -270,6 +278,23 @@ constructor(
val qsMediaInRow: Boolean
get() = qsMediaInRowViewModel.shouldMediaShowInRow
+ var shouldUpdateSquishinessOnMedia by mutableStateOf(false)
+
+ val qsMediaTranslationY by derivedStateOf {
+ if (
+ qsExpansion > 0f &&
+ !isKeyguardState &&
+ !qqsMediaVisible &&
+ !qsMediaInRow &&
+ !isInSplitShade
+ ) {
+ val interpolation = Interpolators.ACCELERATE.getInterpolation(1f - qsExpansion)
+ -qsMediaHost.hostView.height * 1.3f * interpolation
+ } else {
+ 0f
+ }
+ }
+
val animateTilesExpansion: Boolean
get() = inFirstPage && !mediaSuddenlyAppearingInLandscape
@@ -297,6 +322,18 @@ constructor(
MediaHostState.EXPANDED
}
+ private val shouldApplySquishinessToMedia by derivedStateOf {
+ shouldUpdateSquishinessOnMedia || (isInSplitShade && statusBarState == StatusBarState.SHADE)
+ }
+
+ private val mediaSquishiness by derivedStateOf {
+ if (shouldApplySquishinessToMedia) {
+ squishinessFraction
+ } else {
+ 1f
+ }
+ }
+
private var qsBounds by mutableStateOf(Rect())
private val constrainedSquishinessFraction: Float
@@ -355,8 +392,6 @@ constructor(
private val isOverscrolling: Boolean
get() = overScrollAmount != 0
- private var shouldUpdateMediaSquishiness by mutableStateOf(false)
-
private val forceQs by derivedStateOf {
(isQsExpanded || isStackScrollerOverscrolling) &&
(isKeyguardState && !showCollapsedOnKeyguard)
@@ -394,11 +429,30 @@ constructor(
),
)
+ fun applyNewQsScrollerBounds(left: Float, top: Float, right: Float, bottom: Float) {
+ if (usingMedia) {
+ qsMediaHost.currentClipping.set(
+ left.toInt(),
+ top.toInt(),
+ right.toInt(),
+ bottom.toInt(),
+ )
+ }
+ }
+
+ fun emitMotionEventForFalsingSwipeNested() {
+ falsingInteractor.isFalseTouch(Classifier.QS_SWIPE_NESTED)
+ }
+
override suspend fun onActivated(): Nothing {
initMediaHosts() // init regardless of using media (same as current QS).
coroutineScope {
launch { hydrateSquishinessInteractor() }
- launch { hydrateQqsMediaExpansion() }
+ if (usingMedia) {
+ launch { hydrateQqsMediaExpansion() }
+ launch { hydrateMediaSquishiness() }
+ launch { hydrateMediaDisappearParameters() }
+ }
launch { hydrator.activate() }
launch { containerViewModel.activate() }
launch { qqsMediaInRowViewModel.activate() }
@@ -429,6 +483,21 @@ constructor(
snapshotFlow { qqsMediaExpansion }.collect { qqsMediaHost.expansion = it }
}
+ private suspend fun hydrateMediaSquishiness() {
+ snapshotFlow { mediaSquishiness }.collect { qsMediaHost.squishFraction = it }
+ }
+
+ private suspend fun hydrateMediaDisappearParameters() {
+ coroutineScope {
+ launch {
+ snapshotFlow { qqsMediaInRow }.collect { qqsMediaHost.applyDisappearParameters(it) }
+ }
+ launch {
+ snapshotFlow { qsMediaInRow }.collect { qsMediaHost.applyDisappearParameters(it) }
+ }
+ }
+ }
+
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.asIndenting().run {
printSection("Quick Settings state") {
@@ -474,6 +543,9 @@ constructor(
println("qsMediaInRow", qsMediaInRow)
println("collapsedLandscapeMedia", collapsedLandscapeMedia)
println("qqsMediaExpansion", qqsMediaExpansion)
+ println("shouldUpdateSquishinessOnMedia", shouldUpdateSquishinessOnMedia)
+ println("mediaSquishiness", mediaSquishiness)
+ println("qsMediaTranslationY", qsMediaTranslationY)
}
}
}
@@ -510,3 +582,22 @@ private fun mediaHostVisible(mediaHost: MediaHost): Flow<Boolean> {
// lazily.
.onStart { emit(mediaHost.visible) }
}
+
+// Taken from QSPanelControllerBase
+private fun MediaHost.applyDisappearParameters(inRow: Boolean) {
+ disappearParameters.apply {
+ fadeStartPosition = 0.95f
+ disappearStart = 0f
+ if (inRow) {
+ disappearSize.set(0f, 0.4f)
+ gonePivot.set(1f, 0f)
+ contentTranslationFraction.set(0.25f, 1f)
+ disappearEnd = 0.6f
+ } else {
+ disappearSize.set(1f, 0f)
+ gonePivot.set(0f, 0f)
+ contentTranslationFraction.set(0f, 1f)
+ disappearEnd = 0.95f
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index f8d408054d25..0e64820c984e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.qs.customize;
+import static com.android.systemui.Flags.gsfQuickSettings;
+
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
@@ -81,6 +83,10 @@ public class QSCustomizer extends LinearLayout {
mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0, com.android.internal.R.string.reset)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
mToolbar.setTitle(R.string.qs_edit);
+ if (gsfQuickSettings()) {
+ mToolbar.setTitleTextAppearance(context, R.style.TextAppearance_QSEditTitle);
+ }
+
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
DefaultItemAnimator animator = new DefaultItemAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 829c419fc07f..db778a208b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,12 +14,15 @@
package com.android.systemui.qs.customize;
+import static com.android.systemui.Flags.gsfQuickSettings;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.LayoutInflater;
@@ -309,6 +312,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
if (viewType == TYPE_HEADER) {
View v = inflater.inflate(R.layout.qs_customize_header, parent, false);
v.setMinimumHeight(calculateHeaderMinHeight(context));
+ if (gsfQuickSettings()) {
+ ((TextView) v.findViewById(android.R.id.title)).setTypeface(
+ Typeface.create("gsf-label-large", Typeface.NORMAL));
+ }
return new Holder(v);
}
if (viewType == TYPE_DIVIDER) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 89f85ab14dd6..15e34990e111 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -43,6 +43,7 @@ import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shade.ShadeDisplayAware;
import java.util.ArrayList;
import java.util.Arrays;
@@ -69,7 +70,7 @@ public class TileQueryHelper {
@Inject
public TileQueryHelper(
- Context context,
+ @ShadeDisplayAware Context context,
UserTracker userTracker,
@Main Executor mainExecutor,
@Background Executor bgExecutor
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 564bc78a3f98..8ef637545e69 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -37,6 +37,7 @@ import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.icuMessageFormat
import javax.inject.Inject
import javax.inject.Named
@@ -112,7 +113,7 @@ class FooterActionsViewModel(
class Factory
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val falsingManager: FalsingManager,
private val footerActionsInteractor: FooterActionsInteractor,
private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>,
@@ -175,7 +176,7 @@ class FooterActionsViewModel(
}
fun FooterActionsViewModel(
- @Application appContext: Context,
+ @ShadeDisplayAware appContext: Context,
footerActionsInteractor: FooterActionsInteractor,
falsingManager: FalsingManager,
globalActionsDialogLite: GlobalActionsDialogLite,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt
new file mode 100644
index 000000000000..c2764f9f338b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.compose
+
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.EditModeButtonViewModel
+import com.android.systemui.qs.ui.compose.borderOnFocus
+import com.android.systemui.res.R
+
+@Composable
+fun EditModeButton(
+ viewModelFactory: EditModeButtonViewModel.Factory,
+ modifier: Modifier = Modifier,
+) {
+ val viewModel = rememberViewModel(traceName = "EditModeButton") { viewModelFactory.create() }
+ CompositionLocalProvider(
+ value = LocalContentColor provides MaterialTheme.colorScheme.onSurface
+ ) {
+ IconButton(
+ onClick = viewModel::onButtonClick,
+ shape = RoundedCornerShape(CornerSize(28.dp)),
+ modifier =
+ modifier.borderOnFocus(
+ color = MaterialTheme.colorScheme.secondary,
+ cornerSize = CornerSize(24.dp),
+ ),
+ ) {
+ Icon(
+ imageVector = Icons.Default.Edit,
+ contentDescription = stringResource(id = R.string.qs_edit),
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
index c729c7c15176..14abfa2313d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
@@ -68,29 +68,16 @@ class EditTileListState(
return _tiles.indexOfFirst { it is TileGridCell && it.tile.tileSpec == tileSpec }
}
- /**
- * Whether the tile with this [TileSpec] is currently an icon in the [EditTileListState]
- *
- * @return true if the tile is an icon, false if it's large, null if the tile isn't in the list
- */
- fun isIcon(tileSpec: TileSpec): Boolean? {
- val index = indexOf(tileSpec)
- return if (index != -1) {
- val cell = _tiles[index]
- cell as TileGridCell
- return cell.isIcon
- } else {
- null
- }
- }
-
- /** Toggle the size of the tile corresponding to the [TileSpec] */
- fun toggleSize(tileSpec: TileSpec) {
+ /** Resize the tile corresponding to the [TileSpec] to [toIcon] */
+ fun resizeTile(tileSpec: TileSpec, toIcon: Boolean) {
val fromIndex = indexOf(tileSpec)
if (fromIndex != -1) {
- val cell = _tiles.removeAt(fromIndex)
- cell as TileGridCell
- _tiles.add(fromIndex, cell.copy(width = if (cell.isIcon) largeTilesSpan else 1))
+ val cell = _tiles[fromIndex] as TileGridCell
+
+ if (cell.isIcon == toIcon) return
+
+ _tiles.removeAt(fromIndex)
+ _tiles.add(fromIndex, cell.copy(width = if (toIcon) 1 else largeTilesSpan))
regenerateGrid(fromIndex)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index 0d375817b705..a22eb3a8d517 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -27,12 +27,7 @@ import com.android.systemui.qs.pipeline.shared.TileSpec
/** A layout of tiles, indicating how they should be composed when showing in QS or in edit mode. */
interface GridLayout {
- @Composable
- fun SceneScope.TileGrid(
- tiles: List<TileViewModel>,
- modifier: Modifier,
- editModeStart: () -> Unit,
- )
+ @Composable fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier)
@Composable
fun EditTileGrid(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index 2efe500912cd..b6dbf4db57a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -16,39 +16,43 @@
package com.android.systemui.qs.panels.ui.compose
-import androidx.compose.foundation.layout.Box
+import android.view.MotionEvent
+import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Edit
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.LocalContentColor
+import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
+import com.android.compose.modifiers.padding
import com.android.systemui.compose.modifiers.sysuiResTag
+import com.android.systemui.development.ui.compose.BuildNumber
+import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.qs.panels.dagger.PaginatedBaseLayoutType
-import com.android.systemui.qs.panels.ui.compose.PaginatedGridLayout.Dimensions.FooterHeight
-import com.android.systemui.qs.panels.ui.compose.PaginatedGridLayout.Dimensions.InterPageSpacing
+import com.android.systemui.qs.panels.ui.compose.Dimensions.FooterHeight
+import com.android.systemui.qs.panels.ui.compose.Dimensions.InterPageSpacing
+import com.android.systemui.qs.panels.ui.viewmodel.EditModeButtonViewModel
import com.android.systemui.qs.panels.ui.viewmodel.PaginatedGridViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
-import com.android.systemui.res.R
+import com.android.systemui.qs.ui.compose.borderOnFocus
import javax.inject.Inject
class PaginatedGridLayout
@@ -58,11 +62,7 @@ constructor(
@PaginatedBaseLayoutType private val delegateGridLayout: PaginatableGridLayout,
) : GridLayout by delegateGridLayout {
@Composable
- override fun SceneScope.TileGrid(
- tiles: List<TileViewModel>,
- modifier: Modifier,
- editModeStart: () -> Unit,
- ) {
+ override fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
val viewModel =
rememberViewModel(traceName = "PaginatedGridLayout-TileGrid") {
viewModelFactory.create()
@@ -89,45 +89,93 @@ constructor(
}
Column {
+ val contentPaddingValue =
+ if (pages.size > 1) {
+ InterPageSpacing
+ } else {
+ 0.dp
+ }
+ val contentPadding = PaddingValues(horizontal = contentPaddingValue)
+
+ /* Use negative padding equal with value equal to content padding. That way, each page
+ * layout extends to the sides, but the content is as if there was no padding. That
+ * way, the clipping bounds of the HorizontalPager extend beyond the tiles in each page.
+ */
HorizontalPager(
state = pagerState,
- modifier = Modifier.sysuiResTag("qs_pager"),
+ modifier =
+ Modifier.sysuiResTag("qs_pager")
+ .padding(horizontal = { -contentPaddingValue.roundToPx() })
+ .pointerInteropFilter { event ->
+ if (event.actionMasked == MotionEvent.ACTION_UP) {
+ viewModel.registerSideSwipeGesture()
+ }
+ false
+ },
+ contentPadding = contentPadding,
pageSpacing = if (pages.size > 1) InterPageSpacing else 0.dp,
beyondViewportPageCount = 1,
verticalAlignment = Alignment.Top,
) {
val page = pages[it]
- with(delegateGridLayout) {
- TileGrid(tiles = page, modifier = Modifier, editModeStart = {})
- }
- }
- // Use requiredHeight so it won't be squished if the view doesn't quite fit. As this is
- // expected to be inside a scrollable container, this should not be an issue.
- Box(modifier = Modifier.requiredHeight(FooterHeight).fillMaxWidth()) {
- PagerDots(
- pagerState = pagerState,
- activeColor = MaterialTheme.colorScheme.primary,
- nonActiveColor = MaterialTheme.colorScheme.surfaceVariant,
- modifier = Modifier.align(Alignment.Center),
- )
- CompositionLocalProvider(value = LocalContentColor provides Color.White) {
- IconButton(
- onClick = editModeStart,
- modifier = Modifier.align(Alignment.CenterEnd),
- ) {
- Icon(
- imageVector = Icons.Default.Edit,
- contentDescription = stringResource(id = R.string.qs_edit),
- )
- }
- }
+ with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier) }
}
+ FooterBar(
+ buildNumberViewModelFactory = viewModel.buildNumberViewModelFactory,
+ pagerState = pagerState,
+ editButtonViewModelFactory = viewModel.editModeButtonViewModelFactory,
+ )
}
}
+}
+
+private object Dimensions {
+ val FooterHeight = 48.dp
+ val InterPageSpacing = 16.dp
+}
- private object Dimensions {
- val FooterHeight = 48.dp
- val InterPageSpacing = 16.dp
+@Composable
+private fun FooterBar(
+ buildNumberViewModelFactory: BuildNumberViewModel.Factory,
+ pagerState: PagerState,
+ editButtonViewModelFactory: EditModeButtonViewModel.Factory,
+) {
+ // Use requiredHeight so it won't be squished if the view doesn't quite fit. As this is
+ // expected to be inside a scrollable container, this should not be an issue.
+ // Also, we construct the layout this way to do the following:
+ // * PagerDots is centered in the row, taking as much space as it needs.
+ // * On the start side, we place the BuildNumber, taking as much space as it needs, but
+ // constrained by the available space left over after PagerDots
+ // * On the end side, we place the edit mode button, with the same constraints as for
+ // BuildNumber (but it will usually fit, as it's just a square button).
+ Row(
+ modifier = Modifier.requiredHeight(FooterHeight).fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = spacedBy(8.dp),
+ ) {
+ Row(Modifier.weight(1f)) {
+ BuildNumber(
+ viewModelFactory = buildNumberViewModelFactory,
+ textColor = MaterialTheme.colorScheme.onSurface,
+ modifier =
+ Modifier.borderOnFocus(
+ color = MaterialTheme.colorScheme.secondary,
+ cornerSize = CornerSize(1.dp),
+ )
+ .wrapContentSize(),
+ )
+ Spacer(modifier = Modifier.weight(1f))
+ }
+ PagerDots(
+ pagerState = pagerState,
+ activeColor = MaterialTheme.colorScheme.primary,
+ nonActiveColor = MaterialTheme.colorScheme.surfaceVariant,
+ modifier = Modifier.wrapContentWidth(),
+ )
+ Row(Modifier.weight(1f)) {
+ Spacer(modifier = Modifier.weight(1f))
+ EditModeButton(viewModelFactory = editButtonViewModelFactory)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index 1a5297b10e37..6c1906bb906f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -24,13 +24,9 @@ import com.android.compose.animation.scene.SceneScope
import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
@Composable
-fun SceneScope.TileGrid(
- viewModel: TileGridViewModel,
- modifier: Modifier = Modifier,
- editModeStart: () -> Unit,
-) {
+fun SceneScope.TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
val tiles by viewModel.tileViewModels.collectAsStateWithLifecycle(emptyList())
- with(gridLayout) { TileGrid(tiles, modifier, editModeStart) }
+ with(gridLayout) { TileGrid(tiles, modifier) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
index 4a51bf06d4af..dbad60265645 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -17,6 +17,8 @@
package com.android.systemui.qs.panels.ui.compose.infinitegrid
import android.graphics.drawable.Animatable
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.Drawable
import android.text.TextUtils
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi
@@ -30,7 +32,9 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicText
import androidx.compose.material3.MaterialTheme
@@ -47,7 +51,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
@@ -68,8 +71,11 @@ import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.load
import com.android.systemui.compose.modifiers.sysuiResTag
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconHeight
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconWidth
import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
+import com.android.systemui.qs.ui.compose.borderOnFocus
import com.android.systemui.res.R
private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target"
@@ -79,10 +85,11 @@ fun LargeTileContent(
label: String,
secondaryLabel: String?,
icon: Icon,
+ sideDrawable: Drawable?,
colors: TileColors,
squishiness: () -> Float,
accessibilityUiState: AccessibilityUiState? = null,
- iconShape: Shape = RoundedCornerShape(CommonTileDefaults.InactiveCornerRadius),
+ iconShape: RoundedCornerShape = RoundedCornerShape(CommonTileDefaults.InactiveCornerRadius),
toggleClick: (() -> Unit)? = null,
onLongClick: (() -> Unit)? = null,
) {
@@ -94,10 +101,12 @@ fun LargeTileContent(
val longPressLabel = longPressLabel().takeIf { onLongClick != null }
val animatedBackgroundColor by
animateColorAsState(colors.iconBackground, label = "QSTileDualTargetBackgroundColor")
+ val focusBorderColor = MaterialTheme.colorScheme.secondary
Box(
modifier =
Modifier.size(CommonTileDefaults.ToggleTargetSize).thenIf(toggleClick != null) {
- Modifier.clip(iconShape)
+ Modifier.borderOnFocus(color = focusBorderColor, iconShape.topEnd)
+ .clip(iconShape)
.verticalSquish(squishiness)
.drawBehind { drawRect(animatedBackgroundColor) }
.combinedClickable(
@@ -135,6 +144,14 @@ fun LargeTileContent(
colors = colors,
accessibilityUiState = accessibilityUiState,
)
+
+ if (sideDrawable != null) {
+ Image(
+ painter = rememberDrawablePainter(sideDrawable),
+ contentDescription = null,
+ modifier = Modifier.width(SideIconWidth).height(SideIconHeight),
+ )
+ }
}
}
@@ -212,7 +229,14 @@ fun SmallTileContent(
}
}
}
- is Icon.Loaded -> rememberDrawablePainter(loadedDrawable)
+ is Icon.Loaded -> {
+ LaunchedEffect(loadedDrawable) {
+ if (loadedDrawable is AnimatedVectorDrawable) {
+ loadedDrawable.forceAnimationOnUI()
+ }
+ }
+ rememberDrawablePainter(loadedDrawable)
+ }
}
Image(
@@ -229,6 +253,8 @@ fun SmallTileContent(
object CommonTileDefaults {
val IconSize = 32.dp
val LargeTileIconSize = 28.dp
+ val SideIconWidth = 32.dp
+ val SideIconHeight = 20.dp
val ToggleTargetSize = 56.dp
val TileHeight = 72.dp
val TilePadding = 8.dp
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index 31ea60e2f0bc..c6141a1a7cc2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -20,7 +20,6 @@ package com.android.systemui.qs.panels.ui.compose.infinitegrid
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.fadeIn
@@ -75,7 +74,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -124,8 +122,12 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer
-import com.android.systemui.qs.panels.ui.compose.selection.TileWidths
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.FinalResizeOperation
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.TemporaryResizeOperation
import com.android.systemui.qs.panels.ui.compose.selection.clearSelectionTile
+import com.android.systemui.qs.panels.ui.compose.selection.rememberResizingState
import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState
import com.android.systemui.qs.panels.ui.compose.selection.selectableTile
import com.android.systemui.qs.panels.ui.model.GridCell
@@ -136,10 +138,10 @@ import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.groupAndSort
import com.android.systemui.res.R
+import kotlin.math.max
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collectLatest
object TileType
@@ -181,15 +183,7 @@ fun DefaultEditTileGrid(
onStopEditing: () -> Unit,
onReset: (() -> Unit)?,
) {
- val currentListState by rememberUpdatedState(listState)
- val selectionState =
- rememberSelectionState(
- onResize = { currentListState.toggleSize(it) },
- onResizeEnd = { spec ->
- // Commit the size currently in the list
- currentListState.isIcon(spec)?.let { onResize(spec, it) }
- },
- )
+ val selectionState = rememberSelectionState()
val reset: (() -> Unit)? =
if (onReset != null) {
{
@@ -349,10 +343,21 @@ private fun CurrentTilesGrid(
}
.testTag(CURRENT_TILES_GRID_TEST_TAG),
) {
- EditTiles(cells, columns, listState, selectionState, coroutineScope, largeTilesSpan) { spec
- ->
- // Toggle the current size of the tile
- currentListState.isIcon(spec)?.let { onResize(spec, !it) }
+ EditTiles(cells, columns, listState, selectionState, coroutineScope, largeTilesSpan) {
+ resizingOperation ->
+ when (resizingOperation) {
+ is TemporaryResizeOperation -> {
+ currentListState.resizeTile(resizingOperation.spec, resizingOperation.toIcon)
+ }
+ is FinalResizeOperation -> {
+ // Commit the new size of the tile
+ onResize(resizingOperation.spec, resizingOperation.toIcon)
+
+ // Mark the selection as automatic in case the tile ends up moving to a
+ // different row with its new size.
+ selectionState.select(resizingOperation.spec, manual = false)
+ }
+ }
}
}
}
@@ -373,7 +378,7 @@ private fun AvailableTileGrid(
// Available tiles
Column(
- verticalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+ verticalArrangement = spacedBy(TileArrangementPadding),
horizontalAlignment = Alignment.Start,
modifier =
Modifier.fillMaxWidth().wrapContentHeight().testTag(AVAILABLE_TILES_GRID_TEST_TAG),
@@ -387,7 +392,7 @@ private fun AvailableTileGrid(
)
tiles.chunked(columns).forEach { row ->
Row(
- horizontalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+ horizontalArrangement = spacedBy(TileArrangementPadding),
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max),
) {
row.forEachIndexed { index, tileGridCell ->
@@ -436,7 +441,7 @@ fun LazyGridScope.EditTiles(
selectionState: MutableSelectionState,
coroutineScope: CoroutineScope,
largeTilesSpan: Int,
- onToggleSize: (spec: TileSpec) -> Unit,
+ onResize: (operation: ResizeOperation) -> Unit,
) {
items(
count = cells.size,
@@ -464,7 +469,7 @@ fun LazyGridScope.EditTiles(
index = index,
dragAndDropState = dragAndDropState,
selectionState = selectionState,
- onToggleSize = onToggleSize,
+ onResize = onResize,
coroutineScope = coroutineScope,
bounceableInfo = cells.bounceableInfo(index, columns),
largeTilesSpan = largeTilesSpan,
@@ -482,7 +487,7 @@ private fun TileGridCell(
index: Int,
dragAndDropState: DragAndDropState,
selectionState: MutableSelectionState,
- onToggleSize: (spec: TileSpec) -> Unit,
+ onResize: (operation: ResizeOperation) -> Unit,
coroutineScope: CoroutineScope,
largeTilesSpan: Int,
bounceableInfo: BounceableInfo,
@@ -511,28 +516,47 @@ private fun TileGridCell(
selected = selectionState.selection?.tileSpec == cell.tile.tileSpec
}
- // Current base, min and max width of this tile
- var tileWidths: TileWidths? by remember { mutableStateOf(null) }
- val padding = with(LocalDensity.current) { TileArrangementPadding.roundToPx() }
+ val state = rememberResizingState(cell.tile.tileSpec, cell.isIcon)
+
+ val progress: () -> Float = {
+ if (selected) {
+ // If selected, return the manual progress from the drag
+ state.progress()
+ } else {
+ // Else, return the target progress for the tile format
+ if (cell.isIcon) 0f else 1f
+ }
+ }
+
+ if (!selected) {
+ // Update the draggable anchor state when the tile's size is not manually toggled
+ LaunchedEffect(cell.isIcon) { state.updateCurrentValue(cell.isIcon) }
+ } else {
+ // If the tile is selected, listen to new target values from the draggable anchor to toggle
+ // the tile's size
+ LaunchedEffect(state.temporaryResizeOperation) { onResize(state.temporaryResizeOperation) }
+ LaunchedEffect(state.finalResizeOperation) { onResize(state.finalResizeOperation) }
+ }
+
+ val totalPadding =
+ with(LocalDensity.current) { (largeTilesSpan - 1) * TileArrangementPadding.roundToPx() }
ResizableTileContainer(
selected = selected,
- selectionState = selectionState,
+ state = state,
selectionAlpha = { selectionAlpha },
selectionColor = selectionColor,
- tileWidths = { tileWidths },
modifier =
modifier
.height(TileHeight)
.fillMaxWidth()
.onSizeChanged {
// Grab the size before the bounceable to get the idle width
- val totalPadding = (largeTilesSpan - 1) * padding
val min =
if (cell.isIcon) it.width else (it.width - totalPadding) / largeTilesSpan
val max =
if (cell.isIcon) (it.width * largeTilesSpan) + totalPadding else it.width
- tileWidths = TileWidths(it.width, min, max)
+ state.updateAnchors(min.toFloat(), max.toFloat())
}
.bounceable(
bounceable = currentBounceableInfo.bounceable,
@@ -552,7 +576,7 @@ private fun TileGridCell(
listOf(
// TODO(b/367748260): Add final accessibility actions
CustomAccessibilityAction("Toggle size") {
- onToggleSize(cell.tile.tileSpec)
+ onResize(FinalResizeOperation(cell.tile.tileSpec, !cell.isIcon))
true
}
)
@@ -567,24 +591,7 @@ private fun TileGridCell(
)
.tileBackground(colors.background)
) {
- val targetValue = if (cell.isIcon) 0f else 1f
- val animatedProgress = remember { Animatable(targetValue) }
-
- val resizingState = selectionState.resizingState?.takeIf { selected }
- LaunchedEffect(targetValue, resizingState) {
- if (resizingState == null) {
- animatedProgress.animateTo(targetValue)
- } else {
- snapshotFlow { resizingState.progression }
- .collectLatest { animatedProgress.snapTo(it) }
- }
- }
-
- EditTile(
- tile = cell.tile,
- tileWidths = { tileWidths },
- progress = { animatedProgress.value },
- )
+ EditTile(tile = cell.tile, state = state, progress = progress)
}
}
}
@@ -651,7 +658,7 @@ private fun SpacerGridCell(modifier: Modifier = Modifier) {
@Composable
fun EditTile(
tile: EditTileViewModel,
- tileWidths: () -> TileWidths?,
+ state: ResizingState,
progress: () -> Float,
colors: TileColors = EditModeTileDefaults.editTileColors(),
) {
@@ -661,12 +668,16 @@ fun EditTile(
verticalAlignment = Alignment.CenterVertically,
modifier =
Modifier.layout { measurable, constraints ->
+ val (min, max) = state.bounds
+ val currentProgress = progress()
// Always display the tile using the large size and trust the parent composable
// to clip the content as needed. This stop the labels from being truncated.
- val width = tileWidths()?.max ?: constraints.maxWidth
+ val width =
+ max?.roundToInt()?.takeIf { it > constraints.maxWidth }
+ ?: constraints.maxWidth
val placeable =
measurable.measure(constraints.copy(minWidth = width, maxWidth = width))
- val currentProgress = progress()
+
val startPadding =
if (currentProgress == 0f) {
// Find the center of the max width when the tile is icon only
@@ -675,7 +686,7 @@ fun EditTile(
// Find the center of the minimum width to hold the same position as the
// tile is resized.
val basePadding =
- tileWidths()?.min?.let { iconHorizontalCenter(it) } ?: 0f
+ min?.let { iconHorizontalCenter(it.roundToInt()) } ?: 0f
// Large tiles, represented with a progress of 1f, have a 0.dp padding
basePadding * (1f - currentProgress)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 29ff1715dea2..cb857ae5efc6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -55,11 +55,7 @@ constructor(
) : PaginatableGridLayout {
@Composable
- override fun SceneScope.TileGrid(
- tiles: List<TileViewModel>,
- modifier: Modifier,
- editModeStart: () -> Unit,
- ) {
+ override fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
DisposableEffect(tiles) {
val token = Any()
tiles.forEach { it.startListening(token) }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index 9bbf290a53f0..0a80a19871fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -39,6 +39,7 @@ import androidx.compose.foundation.lazy.grid.LazyGridScope
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
+import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
@@ -49,6 +50,7 @@ import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalConfiguration
@@ -59,6 +61,7 @@ import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.semantics.toggleableState
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -82,6 +85,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.toUiState
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.ui.compose.borderOnFocus
import com.android.systemui.res.R
import java.util.function.Supplier
import kotlinx.coroutines.CoroutineScope
@@ -122,7 +126,7 @@ fun Tile(
val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
val resources = resources()
val uiState = remember(state, resources) { state.toUiState(resources) }
- val colors = TileDefaults.getColorForState(uiState)
+ val colors = TileDefaults.getColorForState(uiState, iconOnly)
val hapticsViewModel: TileHapticsViewModel? =
rememberViewModel(traceName = "TileHapticsViewModel") {
tileHapticsViewModelFactoryProvider.getHapticsViewModelFactory()?.create(tile)
@@ -130,15 +134,7 @@ fun Tile(
// TODO(b/361789146): Draw the shapes instead of clipping
val tileShape = TileDefaults.animateTileShape(uiState.state)
- val animatedColor by
- animateColorAsState(
- if (iconOnly || !uiState.handlesSecondaryClick) {
- colors.iconBackground
- } else {
- colors.background
- },
- label = "QSTileBackgroundColor",
- )
+ val animatedColor by animateColorAsState(colors.background, label = "QSTileBackgroundColor")
TileExpandable(
color = { animatedColor },
@@ -147,6 +143,7 @@ fun Tile(
hapticsViewModel = hapticsViewModel,
modifier =
modifier
+ .borderOnFocus(color = MaterialTheme.colorScheme.secondary, tileShape.topEnd)
.fillMaxWidth()
.bounceable(
bounceable = currentBounceableInfo.bounceable,
@@ -199,6 +196,7 @@ fun Tile(
label = uiState.label,
secondaryLabel = uiState.secondaryLabel,
icon = icon,
+ sideDrawable = uiState.sideDrawable,
colors = colors,
iconShape = iconShape,
toggleClick = secondaryClick,
@@ -367,28 +365,30 @@ private object TileDefaults {
)
@Composable
- fun getColorForState(uiState: TileUiState): TileColors {
+ fun getColorForState(uiState: TileUiState, iconOnly: Boolean): TileColors {
return when (uiState.state) {
STATE_ACTIVE -> {
- if (uiState.handlesSecondaryClick) {
+ if (uiState.handlesSecondaryClick && !iconOnly) {
activeDualTargetTileColors()
} else {
activeTileColors()
}
}
+
STATE_INACTIVE -> {
- if (uiState.handlesSecondaryClick) {
+ if (uiState.handlesSecondaryClick && !iconOnly) {
inactiveDualTargetTileColors()
} else {
inactiveTileColors()
}
}
+
else -> unavailableTileColors()
}
}
@Composable
- fun animateIconShape(state: Int): Shape {
+ fun animateIconShape(state: Int): RoundedCornerShape {
return animateShape(
state = state,
activeCornerRadius = ActiveIconCornerRadius,
@@ -397,7 +397,7 @@ private object TileDefaults {
}
@Composable
- fun animateTileShape(state: Int): Shape {
+ fun animateTileShape(state: Int): RoundedCornerShape {
return animateShape(
state = state,
activeCornerRadius = ActiveTileCornerRadius,
@@ -406,7 +406,7 @@ private object TileDefaults {
}
@Composable
- fun animateShape(state: Int, activeCornerRadius: Dp, label: String): Shape {
+ fun animateShape(state: Int, activeCornerRadius: Dp, label: String): RoundedCornerShape {
val animatedCornerRadius by
animateDpAsState(
targetValue =
@@ -417,7 +417,15 @@ private object TileDefaults {
},
label = label,
)
- return RoundedCornerShape(animatedCornerRadius)
+
+ val corner = remember {
+ object : CornerSize {
+ override fun toPx(shapeSize: Size, density: Density): Float {
+ return with(density) { animatedCornerRadius.toPx() }
+ }
+ }
+ }
+ return RoundedCornerShape(corner)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
index 1d36aee4eb85..c6c6dcaa896c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
@@ -27,11 +27,8 @@ import com.android.systemui.qs.pipeline.shared.TileSpec
/** Creates the state of the current selected tile that is remembered across compositions. */
@Composable
-fun rememberSelectionState(
- onResize: (TileSpec) -> Unit,
- onResizeEnd: (TileSpec) -> Unit,
-): MutableSelectionState {
- return remember { MutableSelectionState(onResize, onResizeEnd) }
+fun rememberSelectionState(): MutableSelectionState {
+ return remember { MutableSelectionState() }
}
/**
@@ -41,47 +38,18 @@ fun rememberSelectionState(
data class Selection(val tileSpec: TileSpec, val manual: Boolean)
/** Holds the state of the current selection. */
-class MutableSelectionState(
- val onResize: (TileSpec) -> Unit,
- private val onResizeEnd: (TileSpec) -> Unit,
-) {
+class MutableSelectionState {
private var _selection = mutableStateOf<Selection?>(null)
- private var _resizingState = mutableStateOf<ResizingState?>(null)
/** The [Selection] if a tile is selected, null if not. */
val selection by _selection
- /** The [ResizingState] of the selected tile is currently being resized, null if not. */
- val resizingState by _resizingState
-
fun select(tileSpec: TileSpec, manual: Boolean) {
_selection.value = Selection(tileSpec, manual)
}
fun unSelect() {
_selection.value = null
- onResizingDragEnd()
- }
-
- fun onResizingDrag(offset: Float) {
- _resizingState.value?.onDrag(offset)
- }
-
- fun onResizingDragStart(tileWidths: TileWidths) {
- _selection.value?.let {
- _resizingState.value = ResizingState(tileWidths) { onResize(it.tileSpec) }
- }
- }
-
- fun onResizingDragEnd() {
- _resizingState.value = null
- _selection.value?.let {
- onResizeEnd(it.tileSpec)
-
- // Mark the selection as automatic in case the tile ends up moving to a different
- // row with its new size.
- _selection.value = it.copy(manual = false)
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
index 41c3de55af70..b27c08077834 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
@@ -16,56 +16,77 @@
package com.android.systemui.qs.panels.ui.compose.selection
+import androidx.compose.foundation.gestures.AnchoredDraggableState
+import androidx.compose.foundation.gestures.DraggableAnchors
+import androidx.compose.foundation.gestures.animateTo
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.setValue
-import com.android.systemui.qs.panels.ui.compose.selection.ResizingDefaults.RESIZING_THRESHOLD
+import androidx.compose.runtime.remember
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.FinalResizeOperation
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.TemporaryResizeOperation
+import com.android.systemui.qs.pipeline.shared.TileSpec
-class ResizingState(val widths: TileWidths, private val onResize: () -> Unit) {
- /** Total drag offset of this resize operation. */
- private var totalOffset by mutableFloatStateOf(0f)
-
- /** Width in pixels of the resizing tile. */
- var width by mutableIntStateOf(widths.base)
+@Composable
+fun rememberResizingState(tileSpec: TileSpec, startsAsIcon: Boolean): ResizingState {
+ return remember(tileSpec) { ResizingState(tileSpec, startsAsIcon) }
+}
- /** Progression between icon (0) and large (1) sizes. */
- val progression
- get() = calculateProgression()
+enum class QSDragAnchor {
+ Icon,
+ Large,
+}
- // Whether the tile is currently over the threshold and should be a large tile
- private var passedThreshold: Boolean = passedThreshold(progression)
+class ResizingState(tileSpec: TileSpec, startsAsIcon: Boolean) {
+ val anchoredDraggableState =
+ AnchoredDraggableState(if (startsAsIcon) QSDragAnchor.Icon else QSDragAnchor.Large)
- fun onDrag(offset: Float) {
- totalOffset += offset
- width = (widths.base + totalOffset).toInt().coerceIn(widths.min, widths.max)
+ val bounds by derivedStateOf {
+ anchoredDraggableState.anchors.minPosition().takeIf { !it.isNaN() } to
+ anchoredDraggableState.anchors.maxPosition().takeIf { !it.isNaN() }
+ }
- passedThreshold(progression).let {
- // Resize if we went over the threshold
- if (passedThreshold != it) {
- passedThreshold = it
- onResize()
- }
- }
+ val temporaryResizeOperation by derivedStateOf {
+ TemporaryResizeOperation(
+ tileSpec,
+ toIcon = anchoredDraggableState.currentValue == QSDragAnchor.Icon,
+ )
}
- private fun passedThreshold(progression: Float): Boolean {
- return progression >= RESIZING_THRESHOLD
+ val finalResizeOperation by derivedStateOf {
+ FinalResizeOperation(
+ tileSpec,
+ toIcon = anchoredDraggableState.settledValue == QSDragAnchor.Icon,
+ )
}
- /** The progression of the resizing tile between an icon tile (0f) and a large tile (1f) */
- private fun calculateProgression(): Float {
- return ((width - widths.min) / (widths.max - widths.min).toFloat()).coerceIn(0f, 1f)
+ fun updateAnchors(min: Float, max: Float) {
+ anchoredDraggableState.updateAnchors(
+ DraggableAnchors {
+ QSDragAnchor.Icon at min
+ QSDragAnchor.Large at max
+ }
+ )
}
-}
-/** Holds the width of a tile as well as its min and max widths */
-data class TileWidths(val base: Int, val min: Int, val max: Int) {
- init {
- check(max > min) { "The max width needs to be larger than the min width." }
+ suspend fun updateCurrentValue(isIcon: Boolean) {
+ anchoredDraggableState.animateTo(if (isIcon) QSDragAnchor.Icon else QSDragAnchor.Large)
}
-}
-private object ResizingDefaults {
- const val RESIZING_THRESHOLD = .25f
+ fun progress(): Float = anchoredDraggableState.progress(QSDragAnchor.Icon, QSDragAnchor.Large)
+
+ /**
+ * Represents a resizing operation for a tile.
+ *
+ * @property spec The tile's [TileSpec]
+ * @property toIcon The new size for the tile.
+ */
+ sealed class ResizeOperation private constructor(val spec: TileSpec, val toIcon: Boolean) {
+ /** A temporary resizing operation, used while a resizing movement is in motion. */
+ class TemporaryResizeOperation(spec: TileSpec, toIcon: Boolean) :
+ ResizeOperation(spec, toIcon)
+
+ /** A final resizing operation, used while a resizing movement is done. */
+ class FinalResizeOperation(spec: TileSpec, toIcon: Boolean) : ResizeOperation(spec, toIcon)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
index 8a345ce97c84..a187ff135cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -19,10 +19,10 @@ package com.android.systemui.qs.panels.ui.compose.selection
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.spring
import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.gestures.detectHorizontalDragGestures
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.anchoredDraggable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.size
@@ -30,6 +30,7 @@ import androidx.compose.foundation.systemGestureExclusion
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -40,16 +41,15 @@ import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.drawscope.Stroke
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
import androidx.compose.ui.zIndex
-import com.android.compose.modifiers.thenIf
import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize
import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth
+import kotlin.math.roundToInt
/**
* Places a dot to handle resizing drag events. Use this on tiles to resize.
@@ -58,31 +58,24 @@ import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.Sel
* selected.
*
* @param selected whether resizing drag events should be handled
- * @param selectionState the [MutableSelectionState] on the grid
+ * @param state the [ResizingState] for the tile
* @param selectionAlpha the animated value for the dot and border alpha
* @param selectionColor the [Color] of the dot and border
- * @param tileWidths the [TileWidths] of the selected tile
*/
@Composable
fun ResizableTileContainer(
selected: Boolean,
- selectionState: MutableSelectionState,
+ state: ResizingState,
selectionAlpha: () -> Float,
selectionColor: Color,
- tileWidths: () -> TileWidths?,
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit = {},
) {
- Box(
- modifier
- .resizable(selected, selectionState, tileWidths)
- .selectionBorder(selectionColor, selectionAlpha)
- ) {
+ Box(modifier.resizable(selected, state).selectionBorder(selectionColor, selectionAlpha)) {
content()
ResizingHandle(
enabled = selected,
- selectionState = selectionState,
- tileWidths = tileWidths,
+ state = state,
modifier =
// Higher zIndex to make sure the handle is drawn above the content
Modifier.zIndex(2f),
@@ -91,12 +84,7 @@ fun ResizableTileContainer(
}
@Composable
-private fun ResizingHandle(
- enabled: Boolean,
- selectionState: MutableSelectionState,
- tileWidths: () -> TileWidths?,
- modifier: Modifier = Modifier,
-) {
+private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Modifier = Modifier) {
// Manually creating the touch target around the resizing dot to ensure that the next tile
// does not receive the touch input accidentally.
val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
@@ -112,21 +100,12 @@ private fun ResizingHandle(
)
}
}
- .thenIf(enabled) {
- Modifier.systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
- .pointerInput(Unit) {
- detectHorizontalDragGestures(
- onHorizontalDrag = { _, offset ->
- selectionState.onResizingDrag(offset)
- },
- onDragStart = {
- tileWidths()?.let { selectionState.onResizingDragStart(it) }
- },
- onDragEnd = selectionState::onResizingDragEnd,
- onDragCancel = selectionState::onResizingDragEnd,
- )
- }
- }
+ .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
+ .anchoredDraggable(
+ enabled = enabled,
+ state = state.anchoredDraggableState,
+ orientation = Orientation.Horizontal,
+ )
) {
ResizingDot(enabled = enabled, modifier = Modifier.align(Alignment.Center))
}
@@ -165,23 +144,15 @@ private fun Modifier.selectionBorder(
}
@Composable
-private fun Modifier.resizable(
- selected: Boolean,
- selectionState: MutableSelectionState,
- tileWidths: () -> TileWidths?,
-): Modifier {
+private fun Modifier.resizable(selected: Boolean, state: ResizingState): Modifier {
if (!selected) return zIndex(1f)
- // Animated diff between the current width and the resized width of the tile. We can't use
- // animateContentSize here as the tile is sometimes unbounded.
- val remainingOffset by
- animateIntAsState(
- selectionState.resizingState?.let { tileWidths()?.base?.minus(it.width) ?: 0 } ?: 0,
- label = "QSEditTileWidthOffset",
- )
return zIndex(2f).layout { measurable, constraints ->
+ val isIdle by derivedStateOf { state.progress().let { it == 0f || it == 1f } }
// Grab the width from the resizing state if a resize is in progress
- val width = selectionState.resizingState?.width ?: (constraints.maxWidth - remainingOffset)
+ val width =
+ state.anchoredDraggableState.requireOffset().roundToInt().takeIf { !isIdle }
+ ?: constraints.maxWidth
val placeable = measurable.measure(constraints.copy(minWidth = width, maxWidth = width))
layout(constraints.maxWidth, placeable.height) { placeable.place(0, 0) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt
new file mode 100644
index 000000000000..b033473a91e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.viewmodel
+
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
+import com.android.systemui.plugins.FalsingManager
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+class EditModeButtonViewModel
+@AssistedInject
+constructor(
+ private val editModeViewModel: EditModeViewModel,
+ private val falsingInteractor: FalsingInteractor,
+) {
+
+ fun onButtonClick() {
+ if (!falsingInteractor.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ editModeViewModel.startEditing()
+ }
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): EditModeButtonViewModel
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
index 4e34e73654fc..faab6960a99c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
@@ -56,7 +56,7 @@ constructor(
private val tilesAvailabilityInteractor: TilesAvailabilityInteractor,
private val minTilesInteractor: MinimumTilesInteractor,
@ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
- @Application private val applicationContext: Context,
+ @ShadeDisplayAware private val context: Context,
@Named("Default") private val defaultGridLayout: GridLayout,
@Application private val applicationScope: CoroutineScope,
gridLayoutTypeInteractor: GridLayoutTypeInteractor,
@@ -140,7 +140,7 @@ constructor(
.combine(configurationInteractor.onAnyConfigurationChange.emitOnStart()) {
tiles,
_ ->
- tiles.fastMap { it.load(applicationContext) }
+ tiles.fastMap { it.load(context) }
}
} else {
emptyFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
index e5607eb6e620..4a18872ad6f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
@@ -17,6 +17,9 @@
package com.android.systemui.qs.panels.ui.viewmodel
import androidx.compose.runtime.getValue
+import com.android.systemui.classifier.Classifier.QS_SWIPE_SIDE
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
+import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
@@ -34,6 +37,9 @@ constructor(
columnsWithMediaViewModelFactory: QSColumnsViewModel.Factory,
paginatedGridInteractor: PaginatedGridInteractor,
inFirstPageViewModel: InFirstPageViewModel,
+ val buildNumberViewModelFactory: BuildNumberViewModel.Factory,
+ val editModeButtonViewModelFactory: EditModeButtonViewModel.Factory,
+ private val falsingInteractor: FalsingInteractor,
) : IconTilesViewModel by iconTilesViewModel, ExclusiveActivatable() {
private val hydrator = Hydrator("PaginatedGridViewModel")
@@ -51,6 +57,10 @@ constructor(
val columns: Int
get() = columnsWithMediaViewModel.columns
+ fun registerSideSwipeGesture() {
+ falsingInteractor.isFalseTouch(QS_SWIPE_SIDE)
+ }
+
override suspend fun onActivated(): Nothing {
coroutineScope {
launch { hydrator.activate() }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
index 56675e49d4e6..2fc7f0f9d67b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.panels.ui.viewmodel
import android.content.res.Resources
+import android.graphics.drawable.Drawable
import android.service.quicksettings.Tile
import android.text.TextUtils
import android.widget.Switch
@@ -36,6 +37,7 @@ data class TileUiState(
val handlesLongClick: Boolean,
val handlesSecondaryClick: Boolean,
val icon: Supplier<QSTile.Icon?>,
+ val sideDrawable: Drawable?,
val accessibilityUiState: AccessibilityUiState,
)
@@ -90,6 +92,7 @@ fun QSTile.State.toUiState(resources: Resources): TileUiState {
handlesLongClick = handlesLongClick,
handlesSecondaryClick = handlesSecondaryClick,
icon = icon?.let { Supplier { icon } } ?: iconSupplier ?: Supplier { null },
+ sideDrawable = sideViewCustomDrawable,
AccessibilityUiState(
contentDescription?.toString() ?: "",
stateDescription.toString(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
index c5b27376a82a..41cdefdb2396 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
@@ -30,8 +30,8 @@ import androidx.annotation.GuardedBy
import com.android.systemui.common.data.repository.PackageChangeRepository
import com.android.systemui.common.shared.model.PackageChangeModel
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.kotlin.isComponentActuallyEnabled
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -54,7 +54,7 @@ interface InstalledTilesComponentRepository {
class InstalledTilesComponentRepositoryImpl
@Inject
constructor(
- @Application private val applicationContext: Context,
+ @ShadeDisplayAware private val context: Context,
@Background private val backgroundScope: CoroutineScope,
private val packageChangeRepository: PackageChangeRepository
) : InstalledTilesComponentRepository {
@@ -77,10 +77,10 @@ constructor(
* context.
*/
val packageManager =
- if (applicationContext.userId == userId) {
- applicationContext.packageManager
+ if (context.userId == userId) {
+ context.packageManager
} else {
- applicationContext
+ context
.createContextAsUser(
UserHandle.of(userId),
/* flags */ 0,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
index 31ea734fb842..e9c91ca0db12 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
@@ -27,6 +27,7 @@ import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.NightDisplayTile
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -42,7 +43,7 @@ class NightDisplayAutoAddable
@Inject
constructor(
private val nightDisplayListenerBuilder: NightDisplayListenerModule.Builder,
- context: Context,
+ @ShadeDisplayAware context: Context,
) : AutoAddable {
private val enabled = ColorDisplayManager.isNightDisplayAvailable(context)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 18b1f071f44e..b7ebce247ec9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -27,6 +27,7 @@ import android.content.res.Resources.ID_NULL
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.Rect
+import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
@@ -308,6 +309,14 @@ constructor(
}
setLabelColor(getLabelColorForState(QSTile.State.DEFAULT_STATE))
setSecondaryLabelColor(getSecondaryLabelColorForState(QSTile.State.DEFAULT_STATE))
+
+ if (Flags.gsfQuickSettings()) {
+ label.apply {
+ typeface = Typeface.create("gsf-title-small-emphasized", Typeface.NORMAL)
+ }
+ secondaryLabel.apply { typeface = Typeface.create("gsf-label-medium", Typeface.NORMAL) }
+ }
+
addView(labelContainer)
}
@@ -415,7 +424,10 @@ constructor(
initLongPressEffectCallback()
init(
{ _: View -> longPressEffect.onTileClick() },
- { _: View -> true }, // Haptics and long-clicks are handled by [QSLongPressEffect]
+ { _: View ->
+ longPressEffect.onTileLongClick()
+ true
+ }, // Haptics and long-clicks are handled by [QSLongPressEffect]
)
} else {
val expandable = Expandable.fromView(this)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 6b654beea149..fed8b60a653f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -39,6 +39,7 @@ import com.android.systemui.qs.PseudoGridView;
import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.qs.user.UserSwitchDialogController;
import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.BaseUserSwitcherAdapter;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -95,7 +96,7 @@ public class UserDetailView extends PseudoGridView {
}
@Inject
- public Adapter(Context context, UserSwitcherController controller,
+ public Adapter(@ShadeDisplayAware Context context, UserSwitcherController controller,
UiEventLogger uiEventLogger, FalsingManager falsingManager) {
super(controller);
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt
index 87b89ea6810a..45775272e01f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt
@@ -27,6 +27,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor.PolicyResult
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
@@ -70,7 +71,7 @@ interface DisabledByPolicyInteractor {
class DisabledByPolicyInteractorImpl
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val activityStarter: ActivityStarter,
private val restrictedLockProxy: RestrictedLockProxy,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@@ -105,7 +106,7 @@ constructor(
/** Mockable proxy for [RestrictedLockUtilsInternal] static methods. */
@VisibleForTesting
-class RestrictedLockProxy @Inject constructor(private val context: Context) {
+class RestrictedLockProxy @Inject constructor(@ShadeDisplayAware private val context: Context) {
@WorkerThread
fun hasBaseUserRestriction(userId: Int, userRestriction: String?): Boolean =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
index b766ee0d4333..222fa3efbe94 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
@@ -28,6 +28,7 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider
import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProviderImpl
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.shade.ShadeDisplayAware
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -66,6 +67,6 @@ interface QSTilesModule {
companion object {
- @Provides fun provideTilesTheme(context: Context): Theme = context.theme
+ @Provides fun provideTilesTheme(@ShadeDisplayAware context: Context): Theme = context.theme
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 301ab2bcdd65..244f024625db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -87,6 +87,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.LocationController;
@@ -240,7 +241,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
}
@Inject
- public InternetDialogController(@NonNull Context context, UiEventLogger uiEventLogger,
+ public InternetDialogController(@ShadeDisplayAware Context context, UiEventLogger uiEventLogger,
ActivityStarter starter, AccessPointController accessPointController,
SubscriptionManager subscriptionManager, TelephonyManager telephonyManager,
@Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
@@ -1429,7 +1430,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
void makeOverlayToast(int stringId) {
final Resources res = mContext.getResources();
- final SystemUIToast systemUIToast = mToastFactory.createToast(mContext,
+ final SystemUIToast systemUIToast = mToastFactory.createToast(mContext, mContext,
res.getString(stringId), mContext.getPackageName(), UserHandle.myUserId(),
res.getConfiguration().orientation);
if (systemUIToast == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
index 89b9eee52f2a..0ab533bb9838 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
@@ -71,6 +71,7 @@ import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wifitrackerlib.WifiEntry;
@@ -190,7 +191,7 @@ public class InternetDialogDelegate implements
@AssistedInject
public InternetDialogDelegate(
- Context context,
+ @ShadeDisplayAware Context context,
InternetDialogManager internetDialogManager,
InternetDialogController internetDialogController,
@Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt
index 1546ec2c54bd..32fb1d18724d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt
@@ -26,6 +26,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults
import com.android.systemui.qs.tiles.impl.di.QSTileScope
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -68,7 +69,7 @@ interface CustomTileDefaultsRepository {
class CustomTileDefaultsRepositoryImpl
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
@Application applicationScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : CustomTileDefaultsRepository {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
index 0ebd6f2b4ac3..cd4938f01b63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
@@ -28,6 +28,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.impl.di.QSTileScope
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
@@ -51,7 +52,7 @@ class CustomTilePackageUpdatesRepositoryImpl
@Inject
constructor(
private val tileSpec: TileSpec.CustomTileSpec,
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
@QSTileScope private val tileScope: CoroutineScope,
@Background private val backgroundCoroutineContext: CoroutineContext,
) : CustomTilePackageUpdatesRepository {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt
index 60aa4ea4759f..c446865f31af 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt
@@ -30,12 +30,16 @@ import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
@SysUISingleton
class CustomTileMapper
@Inject
-constructor(private val context: Context, private val uriGrantsManager: IUriGrantsManager) :
+constructor(
+ @ShadeDisplayAware private val context: Context,
+ private val uriGrantsManager: IUriGrantsManager
+) :
QSTileDataToStateMapper<CustomTileDataModel> {
override fun map(config: QSTileConfig, data: CustomTileDataModel): QSTileState {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt
index af2bb9d0d2f7..1153b5c67261 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt
@@ -42,6 +42,7 @@ import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataMod
import com.android.systemui.qs.tiles.impl.di.QSTileScope
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.shade.ShadeDisplayAware
import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -51,7 +52,7 @@ import kotlinx.coroutines.withContext
class CustomTileUserActionInteractor
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val tileSpec: TileSpec,
private val qsTileLogger: QSTileLogger,
private val windowManager: IWindowManager,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
index fc945851cdad..1a6876d0b765 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
@@ -30,6 +30,7 @@ import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileMode
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.pipeline.shared.ui.model.InternetTileIconModel
import javax.inject.Inject
@@ -37,9 +38,9 @@ import javax.inject.Inject
class InternetTileMapper
@Inject
constructor(
- @Main private val resources: Resources,
+ @ShadeDisplayAware private val resources: Resources,
private val theme: Resources.Theme,
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
@Main private val handler: Handler,
) : QSTileDataToStateMapper<InternetTileModel> {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt
index 6fe3979fa446..6d10843decc0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt
@@ -28,6 +28,7 @@ import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel
import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -54,7 +55,7 @@ import kotlinx.coroutines.flow.stateIn
class InternetTileDataInteractor
@Inject
constructor(
- private val context: Context,
+ @ShadeDisplayAware private val context: Context,
@Application private val scope: CoroutineScope,
airplaneModeRepository: AirplaneModeRepository,
private val connectivityRepository: ConnectivityRepository,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 3e44258229f9..9b2880b6d47f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -28,6 +28,7 @@ import com.android.systemui.qs.tiles.ModesTile
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
import com.android.systemui.statusbar.policy.domain.model.ActiveZenModes
import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo
@@ -42,7 +43,7 @@ import kotlinx.coroutines.flow.map
class ModesTileDataInteractor
@Inject
constructor(
- val context: Context,
+ @ShadeDisplayAware val context: Context,
val zenModeInteractor: ZenModeInteractor,
@Background val bgDispatcher: CoroutineDispatcher,
) : QSTileDataInteractor<ModesTileModel> {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
index 736e1a5cb9b6..57a60c179581 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
@@ -75,10 +75,10 @@ constructor(
override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
private fun hasSufficientPermission(): Boolean {
- val rotationPackage: String = packageManager.rotationResolverPackageName
- return rotationPackage != null &&
- packageManager.checkPermission(Manifest.permission.CAMERA, rotationPackage) ==
+ return packageManager.rotationResolverPackageName?.let {
+ packageManager.checkPermission(Manifest.permission.CAMERA, it) ==
PackageManager.PERMISSION_GRANTED
+ } ?: false
}
private fun isCameraRotationEnabled(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt
index 252e3f84df6c..05bdf0a92679 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt
@@ -32,6 +32,7 @@ import com.android.systemui.qs.tiles.impl.saver.domain.DataSaverDialogDelegate
import com.android.systemui.qs.tiles.impl.saver.domain.model.DataSaverTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.settings.UserFileManager
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.DataSaverController
import javax.inject.Inject
@@ -42,7 +43,7 @@ import kotlinx.coroutines.withContext
class DataSaverTileUserActionInteractor
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
@Main private val coroutineContext: CoroutineContext,
@Background private val backgroundContext: CoroutineContext,
private val dataSaverController: DataSaverController,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
index c928e8af17fc..7af3576d8cd9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
@@ -25,6 +25,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.LocationController
@@ -38,7 +39,7 @@ import kotlinx.coroutines.flow.flowOf
class UiModeNightTileDataInteractor
@Inject
constructor(
- @Application private val context: Context,
+ @ShadeDisplayAware private val context: Context,
private val configurationController: ConfigurationController,
private val uiModeManager: UiModeManager,
private val batteryController: BatteryController,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index 35b1b9636263..ab3862b75ee8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -81,7 +81,7 @@ constructor(
// additional
// guidance on how to auto add your tile
throw UnsupportedOperationException(
- "Turning on tile is not supported now"
+ "Turning on tile is not supported now. Tile spec: $tileSpec"
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/compose/BorderOnFocus.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/compose/BorderOnFocus.kt
new file mode 100644
index 000000000000..e6caa0d7520d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/compose/BorderOnFocus.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 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.qs.ui.compose
+
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusEventModifierNode
+import androidx.compose.ui.focus.FocusState
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.ContentDrawScope
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.node.DrawModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * Provides a rounded rect border when the element is focused.
+ *
+ * This should be used for elements that are themselves rounded rects.
+ */
+fun Modifier.borderOnFocus(
+ color: Color,
+ cornerSize: CornerSize,
+ strokeWidth: Dp = 3.dp,
+ padding: Dp = 2.dp,
+) = this then BorderOnFocusElement(color, cornerSize, strokeWidth, padding)
+
+private class BorderOnFocusNode(
+ var color: Color,
+ var cornerSize: CornerSize,
+ var strokeWidth: Dp,
+ var padding: Dp,
+) : FocusEventModifierNode, DrawModifierNode, Modifier.Node() {
+
+ private var focused by mutableStateOf(false)
+
+ override fun onFocusEvent(focusState: FocusState) {
+ focused = focusState.isFocused
+ }
+
+ override fun ContentDrawScope.draw() {
+ drawContent()
+ val focusOutline = Rect(Offset.Zero, size).inflate(padding.toPx())
+ if (focused) {
+ drawRoundRect(
+ color = color,
+ topLeft = focusOutline.topLeft,
+ size = focusOutline.size,
+ cornerRadius = CornerRadius(cornerSize.toPx(focusOutline.size, this)),
+ style = Stroke(strokeWidth.toPx()),
+ )
+ }
+ }
+}
+
+private data class BorderOnFocusElement(
+ val color: Color,
+ val cornerSize: CornerSize,
+ val strokeWidth: Dp,
+ val padding: Dp,
+) : ModifierNodeElement<BorderOnFocusNode>() {
+ override fun create(): BorderOnFocusNode {
+ return BorderOnFocusNode(color, cornerSize, strokeWidth, padding)
+ }
+
+ override fun update(node: BorderOnFocusNode) {
+ node.color = color
+ node.cornerSize = cornerSize
+ node.strokeWidth = strokeWidth
+ node.padding = padding
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "borderOnFocus"
+ properties["color"] = color
+ properties["cornerSize"] = cornerSize
+ properties["strokeWidth"] = strokeWidth
+ properties["padding"] = padding
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt
new file mode 100644
index 000000000000..bc15bbb5e57d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 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.reardisplay
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import android.hardware.devicestate.feature.flags.Flags
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+
+/**
+ * Provides a {@link com.android.systemui.statusbar.phone.SystemUIDialog} to be shown on the inner
+ * display when the device enters Rear Display Mode, containing an UI affordance to let the user
+ * know that the main content has moved to the outer display, as well as an UI affordance to cancel
+ * the Rear Display Mode.
+ */
+@SysUISingleton
+class RearDisplayCoreStartable
+@Inject
+internal constructor(
+ private val context: Context,
+ private val deviceStateManager: DeviceStateManager,
+ private val rearDisplayStateInteractor: RearDisplayStateInteractor,
+ private val rearDisplayInnerDialogDelegateFactory: RearDisplayInnerDialogDelegate.Factory,
+ @Application private val scope: CoroutineScope,
+) : CoreStartable, AutoCloseable {
+
+ companion object {
+ private const val TAG: String = "RearDisplayCoreStartable"
+ }
+
+ @VisibleForTesting var stateChangeListener: Job? = null
+
+ override fun close() {
+ stateChangeListener?.cancel()
+ }
+
+ override fun start() {
+ if (Flags.deviceStateRdmV2()) {
+ var dialog: SystemUIDialog? = null
+
+ stateChangeListener =
+ rearDisplayStateInteractor.state
+ .map {
+ when (it) {
+ is RearDisplayStateInteractor.State.Enabled -> {
+ val rearDisplayContext =
+ context.createDisplayContext(it.innerDisplay)
+ val delegate =
+ rearDisplayInnerDialogDelegateFactory.create(
+ rearDisplayContext,
+ deviceStateManager::cancelStateRequest,
+ )
+ dialog = delegate.createDialog().apply { show() }
+ }
+
+ is RearDisplayStateInteractor.State.Disabled -> {
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+ }
+ .launchIn(scope)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt
new file mode 100644
index 000000000000..2d6181aa04af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 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.reardisplay
+
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/**
+ * A {@link com.android.systemui.statusbar.phone.SystemUIDialog.Delegate} providing a dialog which
+ * lets the user know that the Rear Display Mode is active, and that the content has moved to the
+ * outer display.
+ */
+class RearDisplayInnerDialogDelegate
+@AssistedInject
+internal constructor(
+ private val systemUIDialogFactory: SystemUIDialog.Factory,
+ @Assisted private val rearDisplayContext: Context,
+ @Assisted private val onCanceledRunnable: Runnable,
+) : SystemUIDialog.Delegate {
+
+ @AssistedFactory
+ interface Factory {
+ fun create(
+ rearDisplayContext: Context,
+ onCanceledRunnable: Runnable,
+ ): RearDisplayInnerDialogDelegate
+ }
+
+ override fun createDialog(): SystemUIDialog {
+ return systemUIDialogFactory.create(this, rearDisplayContext)
+ }
+
+ override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ dialog.apply {
+ setContentView(R.layout.activity_rear_display_front_screen_on)
+ setCanceledOnTouchOutside(false)
+ requireViewById<View>(R.id.button_cancel).setOnClickListener {
+ onCanceledRunnable.run()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt
index 6ab294dd9818..5fb9cb27f90f 100644
--- a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt
@@ -41,4 +41,10 @@ interface RearDisplayModule {
fun bindRearDisplayDialogControllerConfigChanges(
impl: RearDisplayDialogController
): ConfigurationListener
+
+ /** Start RearDisplayCoreStartable. */
+ @Binds
+ @IntoMap
+ @ClassKey(RearDisplayCoreStartable::class)
+ abstract fun bindRearDisplayCoreStartable(impl: RearDisplayCoreStartable): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index 02b2bb1585bd..d94f00fff400 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -171,9 +171,16 @@ constructor(
}
ALL_ISSUE_TYPES.keys.forEach {
popupMenu.menu.add(it).apply {
+ // Set this for every item in the list to ensure equal spacing. Set it to
+ // transparent for non-selected items so icon is only visible for selected element.
setIcon(R.drawable.arrow_pointing_down)
if (it != state.issueTypeRes) {
iconTintList = ColorStateList.valueOf(Color.TRANSPARENT)
+ } else {
+ contentDescription =
+ context.getString(com.android.internal.R.string.selected) +
+ " " +
+ context.getString(it)
}
intent = Intent().putExtra(EXTRA_ISSUE_TYPE_RES, it)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractor.kt
new file mode 100644
index 000000000000..d7c3b6b43c71
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractor.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 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.scene.domain.interactor
+
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+class DisabledContentInteractor
+@Inject
+constructor(private val disableFlagsInteractor: DisableFlagsInteractor) {
+
+ /** Returns `true` if the given [key] is disabled; `false` if it's enabled */
+ fun isDisabled(
+ key: ContentKey,
+ disabledFlags: DisableFlagsModel = disableFlagsInteractor.disableFlags.value,
+ ): Boolean {
+ return with(disabledFlags) {
+ when (key) {
+ Scenes.Shade,
+ Overlays.NotificationsShade -> !isShadeEnabled()
+ Scenes.QuickSettings,
+ Overlays.QuickSettingsShade -> !isQuickSettingsEnabled()
+ else -> false
+ }
+ }
+ }
+
+ /** Runs the given [block] each time that [key] becomes disabled. */
+ suspend fun repeatWhenDisabled(key: ContentKey, block: suspend (disabled: ContentKey) -> Unit) {
+ disableFlagsInteractor.disableFlags
+ .map { isDisabled(key) }
+ .distinctUntilChanged()
+ .collectLatest { isDisabled ->
+ if (isDisabled) {
+ block(key)
+ }
+ }
+ }
+
+ /**
+ * Returns a filtered version of [unfiltered], without action-result entries that would navigate
+ * to disabled scenes.
+ */
+ fun filteredUserActions(
+ unfiltered: Flow<Map<UserAction, UserActionResult>>
+ ): Flow<Map<UserAction, UserActionResult>> {
+ return combine(disableFlagsInteractor.disableFlags, unfiltered) {
+ disabledFlags,
+ unfilteredMap ->
+ unfilteredMap.filterValues { actionResult ->
+ val destination =
+ when (actionResult) {
+ is UserActionResult.ChangeScene -> actionResult.toScene
+ is UserActionResult.ShowOverlay -> actionResult.overlay
+ is UserActionResult.ReplaceByOverlay -> actionResult.overlay
+ else -> null
+ }
+ if (destination != null) {
+ // results that lead to a disabled destination get filtered out.
+ !isDisabled(key = destination, disabledFlags = disabledFlags)
+ } else {
+ // Action results that don't lead to a destination are never filtered out.
+ true
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
index 667827ac4724..c96ea03f057a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
@@ -138,6 +138,7 @@ constructor(
Overlays.QuickSettingsShade -> false
Scenes.Bouncer -> false
Scenes.Communal -> true
+ Scenes.Dream -> false
Scenes.Gone -> true
Scenes.Lockscreen -> true
Scenes.QuickSettings -> false
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index f20e5a54f6ed..d83d74e4e538 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -21,6 +21,8 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
@@ -64,6 +66,7 @@ constructor(
private val sceneFamilyResolvers: Lazy<Map<SceneKey, @JvmSuppressWildcards SceneResolver>>,
private val deviceUnlockedInteractor: Lazy<DeviceUnlockedInteractor>,
private val keyguardEnabledInteractor: Lazy<KeyguardEnabledInteractor>,
+ private val disabledContentInteractor: DisabledContentInteractor,
) {
interface OnSceneAboutToChangeListener {
@@ -465,6 +468,10 @@ constructor(
return false
}
+ if (disabledContentInteractor.isDisabled(to)) {
+ return false
+ }
+
val inMidTransitionFromGone =
(transitionState.value as? ObservableTransitionState.Transition)?.fromContent ==
Scenes.Gone
@@ -503,6 +510,10 @@ constructor(
" Logging reason for overlay change was: $loggingReason"
}
+ if (to != null && disabledContentInteractor.isDisabled(to)) {
+ return false
+ }
+
val isFromValid = (from == null) || (from in currentOverlays.value)
val isToValid =
(to == null) || (to !in currentOverlays.value && to in repository.allContentKeys)
@@ -517,4 +528,14 @@ constructor(
/** Returns `true` if [scene] can be resolved from [family]. */
fun isSceneInFamily(scene: SceneKey, family: SceneKey): Boolean =
sceneFamilyResolvers.get()[family]?.includesScene(scene) == true
+
+ /**
+ * Returns a filtered version of [unfiltered], without action-result entries that would navigate
+ * to disabled scenes.
+ */
+ fun filteredUserActions(
+ unfiltered: Flow<Map<UserAction, UserActionResult>>
+ ): Flow<Map<UserAction, UserActionResult>> {
+ return disabledContentInteractor.filteredUserActions(unfiltered)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
index 41a3c8aff6cf..b89eb5c762e0 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
@@ -23,6 +23,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import dagger.Binds
@@ -46,6 +47,7 @@ class HomeSceneFamilyResolver
constructor(
@Application private val applicationScope: CoroutineScope,
deviceEntryInteractor: DeviceEntryInteractor,
+ keyguardInteractor: KeyguardInteractor,
keyguardEnabledInteractor: KeyguardEnabledInteractor,
) : SceneResolver {
override val targetFamily: SceneKey = SceneFamilies.Home
@@ -56,6 +58,7 @@ constructor(
deviceEntryInteractor.canSwipeToEnter,
deviceEntryInteractor.isDeviceEntered,
deviceEntryInteractor.isUnlocked,
+ keyguardInteractor.isDreamingWithOverlay,
transform = ::homeScene,
)
.stateIn(
@@ -67,7 +70,8 @@ constructor(
canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value,
isDeviceEntered = deviceEntryInteractor.isDeviceEntered.value,
isUnlocked = deviceEntryInteractor.isUnlocked.value,
- )
+ isDreamingWithOverlay = false,
+ ),
)
override fun includesScene(scene: SceneKey): Boolean = scene in homeScenes
@@ -77,8 +81,11 @@ constructor(
canSwipeToEnter: Boolean?,
isDeviceEntered: Boolean,
isUnlocked: Boolean,
+ isDreamingWithOverlay: Boolean,
): SceneKey =
when {
+ // Dream can run even if Keyguard is disabled, thus it has the highest priority here.
+ isDreamingWithOverlay -> Scenes.Dream
!isKeyguardEnabled -> Scenes.Gone
canSwipeToEnter == true -> Scenes.Lockscreen
!isDeviceEntered -> Scenes.Lockscreen
@@ -91,6 +98,9 @@ constructor(
setOf(
Scenes.Gone,
Scenes.Lockscreen,
+ // Dream is a home scene as the dream activity occludes keyguard and can show the
+ // shade on top.
+ Scenes.Dream,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 580a51a3dc0a..8d8c24eae9e2 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -19,7 +19,6 @@
package com.android.systemui.scene.domain.startable
import android.app.StatusBarManager
-import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.UiEventLogger
@@ -46,6 +45,7 @@ import com.android.systemui.deviceentry.shared.model.DeviceUnlockSource
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor.Companion.keyguardScenes
import com.android.systemui.model.SceneContainerPlugin
import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
@@ -55,6 +55,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.scene.data.model.asIterable
import com.android.systemui.scene.data.model.sceneStackOf
+import com.android.systemui.scene.domain.interactor.DisabledContentInteractor
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -62,6 +63,7 @@ import com.android.systemui.scene.session.shared.SessionStorage
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -101,6 +103,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/**
* Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
@@ -142,6 +145,7 @@ constructor(
private val alternateBouncerInteractor: AlternateBouncerInteractor,
private val vibratorHelper: VibratorHelper,
private val msdlPlayer: MSDLPlayer,
+ private val disabledContentInteractor: DisabledContentInteractor,
) : CoreStartable {
private val centralSurfaces: CentralSurfaces?
get() = centralSurfacesOptLazy.get().getOrNull()
@@ -217,7 +221,9 @@ constructor(
sceneInteractor.transitionState.mapNotNull { state ->
when (state) {
is ObservableTransitionState.Idle -> {
- if (state.currentScene != Scenes.Gone) {
+ if (state.currentScene == Scenes.Dream) {
+ false to "dream is showing"
+ } else if (state.currentScene != Scenes.Gone) {
true to "scene is not Gone"
} else if (state.currentOverlays.isNotEmpty()) {
true to "overlay is shown"
@@ -228,21 +234,30 @@ constructor(
is ObservableTransitionState.Transition -> {
if (state.fromContent == Scenes.Gone) {
true to "scene transitioning away from Gone"
+ } else if (state.fromContent == Scenes.Dream) {
+ true to "scene transitioning away from dream"
} else {
null
}
}
}
},
+ sceneInteractor.transitionState.map { state ->
+ state.isTransitioningFromOrTo(Scenes.Communal) ||
+ state.isIdle(Scenes.Communal)
+ },
headsUpInteractor.isHeadsUpOrAnimatingAway,
occlusionInteractor.invisibleDueToOcclusion,
alternateBouncerInteractor.isVisible,
) {
visibilityForTransitionState,
+ isCommunalShowing,
isHeadsUpOrAnimatingAway,
invisibleDueToOcclusion,
isAlternateBouncerVisible ->
when {
+ isCommunalShowing ->
+ true to "on or transitioning to/from communal"
isHeadsUpOrAnimatingAway -> true to "showing a HUN"
isAlternateBouncerVisible -> true to "showing alternate bouncer"
invisibleDueToOcclusion -> false to "invisible due to occlusion"
@@ -266,7 +281,9 @@ constructor(
handleSimUnlock()
handleDeviceUnlockStatus()
handlePowerState()
+ handleDreamState()
handleShadeTouchability()
+ handleDisableFlags()
}
private fun handleBouncerImeVisibility() {
@@ -339,14 +356,13 @@ constructor(
val isAlternateBouncerVisible = alternateBouncerInteractor.isVisibleState()
val isOnPrimaryBouncer = renderedScenes.contains(Scenes.Bouncer)
if (!deviceUnlockStatus.isUnlocked) {
- return@mapNotNull if (isOnLockscreen || isOnPrimaryBouncer) {
- // Already on lockscreen or bouncer, no need to change scenes.
+ return@mapNotNull if (renderedScenes.any { it in keyguardScenes }) {
+ // Already on a keyguard scene, no need to change scenes.
null
} else {
- // The device locked while on a scene that's not Lockscreen or Bouncer,
- // go to Lockscreen.
- Scenes.Lockscreen to
- "device locked in non-Lockscreen and non-Bouncer scene"
+ // The device locked while on a scene that's not a keyguard scene, go
+ // to Lockscreen.
+ Scenes.Lockscreen to "device locked in a non-keyguard scene"
}
}
@@ -373,6 +389,7 @@ constructor(
"device was unlocked with alternate bouncer showing" +
" and shade didn't need to be left open"
} else {
+ replaceLockscreenSceneOnBackStack()
null
}
}
@@ -391,16 +408,7 @@ constructor(
val prevScene = previousScene.value
val targetScene = prevScene ?: Scenes.Gone
if (targetScene != Scenes.Gone) {
- sceneBackInteractor.updateBackStack { stack ->
- val list = stack.asIterable().toMutableList()
- check(list.last() == Scenes.Lockscreen) {
- "The bottommost/last SceneKey of the back stack isn't" +
- " the Lockscreen scene like expected. The back" +
- " stack is $stack."
- }
- list[list.size - 1] = Scenes.Gone
- sceneStackOf(*list.toTypedArray())
- }
+ replaceLockscreenSceneOnBackStack()
}
targetScene to
"device was unlocked with primary bouncer showing," +
@@ -425,8 +433,13 @@ constructor(
"mechanism: ${deviceUnlockStatus.deviceUnlockSource}"
else -> null
}
- // Not on lockscreen or bouncer, so remain in the current scene.
- else -> null
+ // Not on lockscreen or bouncer, so remain in the current scene but since
+ // unlocked, replace the Lockscreen scene from the bottom of the navigation
+ // back stack with the Gone scene.
+ else -> {
+ replaceLockscreenSceneOnBackStack()
+ null
+ }
}
}
.collect { (targetSceneKey, loggingReason) ->
@@ -435,6 +448,22 @@ constructor(
}
}
+ /**
+ * If the [Scenes.Lockscreen] is on the bottom of the navigation backstack, replaces it with
+ * [Scenes.Gone].
+ */
+ private fun replaceLockscreenSceneOnBackStack() {
+ sceneBackInteractor.updateBackStack { stack ->
+ val list = stack.asIterable().toMutableList()
+ if (list.lastOrNull() == Scenes.Lockscreen) {
+ list[list.size - 1] = Scenes.Gone
+ sceneStackOf(*list.toTypedArray())
+ } else {
+ stack
+ }
+ }
+ }
+
private fun handlePowerState() {
applicationScope.launch {
powerInteractor.detailedWakefulness.collect { wakefulness ->
@@ -500,6 +529,31 @@ constructor(
}
}
+ private fun handleDreamState() {
+ applicationScope.launch {
+ keyguardInteractor.isAbleToDream
+ .sample(sceneInteractor.transitionState, ::Pair)
+ .collect { (isAbleToDream, transitionState) ->
+ if (transitionState.isIdle(Scenes.Communal)) {
+ // The dream is automatically started underneath the hub, don't transition
+ // to dream when this is happening as communal is still visible on top.
+ return@collect
+ }
+ if (isAbleToDream) {
+ switchToScene(
+ targetSceneKey = Scenes.Dream,
+ loggingReason = "dream started",
+ )
+ } else {
+ switchToScene(
+ targetSceneKey = SceneFamilies.Home,
+ loggingReason = "dream stopped",
+ )
+ }
+ }
+ }
+ }
+
private fun handleShadeTouchability() {
applicationScope.launch {
shadeInteractor.isShadeTouchable
@@ -514,6 +568,38 @@ constructor(
}
}
+ private fun handleDisableFlags() {
+ applicationScope.launch {
+ launch {
+ sceneInteractor.currentScene.collectLatest { currentScene ->
+ disabledContentInteractor.repeatWhenDisabled(currentScene) {
+ switchToScene(
+ targetSceneKey = SceneFamilies.Home,
+ loggingReason =
+ "Current scene ${currentScene.debugName} became" + " disabled",
+ )
+ }
+ }
+ }
+
+ launch {
+ sceneInteractor.currentOverlays.collectLatest { overlays ->
+ overlays.forEach { overlay ->
+ launch {
+ disabledContentInteractor.repeatWhenDisabled(overlay) {
+ sceneInteractor.hideOverlay(
+ overlay = overlay,
+ loggingReason =
+ "Overlay ${overlay.debugName} became" + " disabled",
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
private fun handleDeviceEntryHapticsWhileDeviceLocked() {
applicationScope.launch {
deviceEntryInteractor.isDeviceEntered.collectLatest { isDeviceEntered ->
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 32d5cb460cd8..c1e8032aa9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -280,6 +280,16 @@ constructor(
}
}
+ /**
+ * Returns a filtered version of [unfiltered], without action-result entries that would navigate
+ * to disabled scenes.
+ */
+ fun filteredUserActions(
+ unfiltered: Flow<Map<UserAction, UserActionResult>>
+ ): Flow<Map<UserAction, UserActionResult>> {
+ return sceneInteractor.filteredUserActions(unfiltered)
+ }
+
/** Defines interface for classes that can handle externally-reported [MotionEvent]s. */
interface MotionEventHandler {
/** Notifies that a [MotionEvent] has occurred. */
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index 3a90d2b9df7b..503d0bfbc301 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -235,8 +235,7 @@ public class BrightnessSliderController extends ViewController<BrightnessSliderV
if (mBrightnessWarningToast.isToastActive()) {
return;
}
- mBrightnessWarningToast.show(mView.getContext(),
- R.string.quick_settings_brightness_unable_adjust_msg);
+ mBrightnessWarningToast.show(mView.getContext(), resId);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt
index dfbdaa62ec44..40260d0ca29f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt
@@ -37,11 +37,14 @@ constructor(
private var toastView: View? = null
fun show(viewContext: Context, @StringRes resId: Int) {
+ if (isToastActive()) {
+ return
+ }
val res = viewContext.resources
// Show the brightness warning toast with passing the toast inflation required context,
// userId and resId from SystemUI package.
val systemUIToast = toastFactory.createToast(
- viewContext,
+ viewContext, viewContext,
res.getString(resId), viewContext.packageName, viewContext.getUserId(),
res.configuration.orientation
)
@@ -79,13 +82,15 @@ constructor(
val inAnimator = systemUIToast.inAnimation
inAnimator?.start()
- toastView!!.postDelayed({
+ toastView?.postDelayed({
val outAnimator = systemUIToast.outAnimation
if (outAnimator != null) {
outAnimator.start()
outAnimator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animator: Animator) {
- windowManager.removeViewImmediate(toastView)
+ if (isToastActive()) {
+ windowManager.removeViewImmediate(toastView)
+ }
toastView = null
}
})
@@ -94,7 +99,7 @@ constructor(
}
fun isToastActive(): Boolean {
- return toastView != null && toastView!!.isAttachedToWindow
+ return toastView?.isAttachedToWindow == true
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c15c8f946855..42a756c27de7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2053,9 +2053,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
if (mQsController.getExpanded()) {
mQsController.flingQs(0, FLING_COLLAPSE);
- } else if (mBarState == KEYGUARD) {
- mLockscreenShadeTransitionController.goToLockedShade(
- /* expandedView= */null, /* needsQSAnimation= */false);
} else {
expand(true /* animate */);
}
@@ -3112,12 +3109,21 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
if (isTracking()) {
onTrackingStopped(true);
}
- if (isExpanded() && mBarState != KEYGUARD && !mQsController.getExpanded()) {
- mShadeLog.d("Status Bar was long pressed. Expanding to QS.");
- expandToQs();
- } else {
- mShadeLog.d("Status Bar was long pressed. Expanding to Notifications.");
- expandToNotifications();
+ if (!mQsController.getExpanded()) {
+ performHapticFeedback(HapticFeedbackConstants.GESTURE_START);
+ if (isExpanded() && mBarState != KEYGUARD) {
+ mShadeLog.d("Status Bar was long pressed. Expanding to QS.");
+ mQsController.flingQs(0, FLING_EXPAND);
+ } else {
+ if (mBarState == KEYGUARD) {
+ mShadeLog.d("Lockscreen Status Bar was long pressed. Expanding to Notifications.");
+ mLockscreenShadeTransitionController.goToLockedShade(
+ /* expandedView= */null, /* needsQSAnimation= */true);
+ } else {
+ mShadeLog.d("Status Bar was long pressed. Expanding to Notifications.");
+ expandToNotifications();
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 24dba59a1d54..4d77e3ecea7b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -17,8 +17,6 @@
package com.android.systemui.shade;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -27,16 +25,13 @@ import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
-import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
-import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
import android.view.Display;
-import android.view.Gravity;
import android.view.IWindow;
import android.view.IWindowSession;
import android.view.View;
@@ -271,33 +266,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
// Now that the notification shade encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
- mLp = new LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT,
- LayoutParams.TYPE_NOTIFICATION_SHADE,
- LayoutParams.FLAG_NOT_FOCUSABLE
- | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
- | LayoutParams.FLAG_SPLIT_TOUCH
- | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
- PixelFormat.TRANSLUCENT);
- mLp.token = new Binder();
- mLp.gravity = Gravity.TOP;
- mLp.setFitInsetsTypes(0 /* types */);
- mLp.setTitle("NotificationShade");
- mLp.packageName = mContext.getPackageName();
- mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mLp.privateFlags |= PRIVATE_FLAG_OPTIMIZE_MEASURE;
-
- if (SceneContainerFlag.isEnabled()) {
- // This prevents the appearance and disappearance of the software keyboard (also known
- // as the "IME") from scrolling/panning the window to make room for the keyboard.
- //
- // The scene container logic does its own adjustment and animation when the IME appears
- // or disappears.
- mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
- }
-
+ mLp = ShadeWindowLayoutParams.INSTANCE.create(mContext);
mWindowManager.addView(mWindowRootView, mLp);
// We use BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE here, however, there is special logic in
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 7a18d7caa13f..207439e1f374 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -28,6 +28,7 @@ import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.lifecycle.lifecycleScope
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.fragments.FragmentService
@@ -314,7 +315,7 @@ constructor(
private fun setKeyguardStatusViewConstraints(constraintSet: ConstraintSet) {
val statusViewMarginHorizontal =
- resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
+ resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal)
constraintSet.apply {
setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal)
setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
index 830649be2a98..04f89be97e0a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
@@ -114,6 +114,7 @@ import kotlin.Unit;
import java.io.PrintWriter;
import javax.inject.Inject;
+import javax.inject.Provider;
/** Handles QuickSettings touch handling, expansion and animation state
* TODO (b/264460656) make this dumpable
@@ -141,6 +142,7 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
private final NotificationShadeDepthController mDepthController;
private final ShadeHeaderController mShadeHeaderController;
private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+ private final Provider<StatusBarLongPressGestureDetector> mStatusBarLongPressGestureDetector;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardBypassController mKeyguardBypassController;
private final NotificationRemoteInputManager mRemoteInputManager;
@@ -316,6 +318,7 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
NotificationShadeDepthController notificationShadeDepthController,
ShadeHeaderController shadeHeaderController,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+ Provider<StatusBarLongPressGestureDetector> statusBarLongPressGestureDetector,
KeyguardStateController keyguardStateController,
KeyguardBypassController keyguardBypassController,
ScrimController scrimController,
@@ -364,6 +367,7 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
mDepthController = notificationShadeDepthController;
mShadeHeaderController = shadeHeaderController;
mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
+ mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector;
mKeyguardStateController = keyguardStateController;
mKeyguardBypassController = keyguardBypassController;
mScrimController = scrimController;
@@ -1648,6 +1652,10 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
if (isSplitShadeAndTouchXOutsideQs(event.getX())) {
return false;
}
+ boolean isInStatusBar = event.getY(event.getActionIndex()) < mStatusBarMinHeight;
+ if (ShadeExpandsOnStatusBarLongPress.isEnabled() && isInStatusBar) {
+ mStatusBarLongPressGestureDetector.get().handleTouch(event);
+ }
final int action = event.getActionMasked();
boolean collapsedQs = !getExpanded() && !mSplitShadeEnabled;
boolean expandedShadeCollapsedQs = mShadeExpandedFraction == 1f
@@ -1684,9 +1692,7 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
if (action == MotionEvent.ACTION_DOWN && isFullyCollapsed && isExpansionEnabled()) {
mTwoFingerExpandPossible = true;
}
- if (mTwoFingerExpandPossible && isOpenQsEvent(event)
- && event.getY(event.getActionIndex())
- < mStatusBarMinHeight) {
+ if (mTwoFingerExpandPossible && isOpenQsEvent(event) && isInStatusBar) {
mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
setExpandImmediate(true);
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(!mSplitShadeEnabled);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt
index 111d335d0d0f..e8cdf836a58f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt
@@ -29,5 +29,13 @@ import javax.inject.Qualifier
* `ConfigurationController`) will be dynamically updated to reflect the current display's
* configuration. This ensures consistent rendering even when the shade window is moved to an
* external display.
+ *
+ * Note that in SystemUI, Currently, the shade window includes the lockscreen, quick settings, the
+ * notification stack, AOD, Bouncer, Glancable hub, and potentially other components that have been
+ * introduced after this comment is written.
+ *
+ * TODO: b/378016985 - The usage of this annotation in the relevant packages will be enforced by a
+ * presubmit linter that will highlight instances of the global instances used in shade window
+ * classes.
*/
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class ShadeDisplayAware
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index e15830eb22eb..0b36e685d914 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -17,9 +17,9 @@
package com.android.systemui.shade
import android.content.Context
+import android.content.MutableContextWrapper
import android.content.res.Resources
import android.view.LayoutInflater
-import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
import com.android.systemui.CoreStartable
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.common.ui.ConfigurationStateImpl
@@ -29,17 +29,20 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImp
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.res.R
-import com.android.systemui.shade.data.repository.ShadePositionRepository
-import com.android.systemui.shade.data.repository.ShadePositionRepositoryImpl
+import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
+import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.phone.ConfigurationForwarder
import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.BindsOptionalOf
import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
+import javax.inject.Provider
/**
* Module responsible for managing display-specific components and resources for the notification
@@ -53,7 +56,7 @@ import dagger.multibindings.IntoMap
* By using this dedicated module, we ensure the notification shade window always utilizes the
* correct display context and resources, regardless of the display it's on.
*/
-@Module
+@Module(includes = [OptionalShadeDisplayAwareBindings::class])
object ShadeDisplayAwareModule {
/** Creates a new context for the shade window. */
@@ -62,9 +65,7 @@ object ShadeDisplayAwareModule {
@SysUISingleton
fun provideShadeDisplayAwareContext(context: Context): Context {
return if (ShadeWindowGoesAround.isEnabled) {
- context
- .createWindowContext(context.display, TYPE_APPLICATION_OVERLAY, /* options= */ null)
- .apply { setTheme(R.style.Theme_SystemUI) }
+ MutableContextWrapper(context)
} else {
context
}
@@ -157,21 +158,35 @@ object ShadeDisplayAwareModule {
@SysUISingleton
@Provides
- fun provideShadePositionRepository(impl: ShadePositionRepositoryImpl): ShadePositionRepository {
+ fun provideShadePositionRepository(impl: ShadeDisplaysRepositoryImpl): ShadeDisplaysRepository {
ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
return impl
}
@Provides
@IntoMap
- @ClassKey(ShadePositionRepositoryImpl::class)
- fun provideShadePositionRepositoryAsCoreStartable(
- impl: ShadePositionRepositoryImpl
- ): CoreStartable {
+ @ClassKey(ShadePrimaryDisplayCommand::class)
+ fun provideShadePrimaryDisplayCommand(impl: ShadePrimaryDisplayCommand): CoreStartable {
return if (ShadeWindowGoesAround.isEnabled) {
impl
} else {
CoreStartable.NOP
}
}
+
+ @Provides
+ @IntoMap
+ @ClassKey(ShadeDisplaysInteractor::class)
+ fun provideShadeDisplaysInteractor(impl: Provider<ShadeDisplaysInteractor>): CoreStartable {
+ return if (ShadeWindowGoesAround.isEnabled) {
+ impl.get()
+ } else {
+ CoreStartable.NOP
+ }
+ }
+}
+
+@Module
+internal interface OptionalShadeDisplayAwareBindings {
+ @BindsOptionalOf fun bindOptionalOfWindowRootView(): WindowRootView
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
index 802fc0edb533..a5d9e9660ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
@@ -17,40 +17,107 @@
package com.android.systemui.shade
import android.view.Display
-import com.android.systemui.shade.data.repository.ShadePositionRepository
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
import java.io.PrintWriter
+import javax.inject.Inject
-class ShadePrimaryDisplayCommand(private val positionRepository: ShadePositionRepository) :
- Command {
+@SysUISingleton
+class ShadePrimaryDisplayCommand
+@Inject
+constructor(
+ private val commandRegistry: CommandRegistry,
+ private val displaysRepository: DisplayRepository,
+ private val positionRepository: ShadeDisplaysRepository,
+) : Command, CoreStartable {
+
+ override fun start() {
+ commandRegistry.registerCommand("shade_display_override") { this }
+ }
+
+ override fun help(pw: PrintWriter) {
+ pw.println("shade_display_override <displayId> ")
+ pw.println("Set the display which is holding the shade.")
+ pw.println()
+ pw.println("shade_display_override reset ")
+ pw.println("Reset the display which is holding the shade.")
+ pw.println()
+ pw.println("shade_display_override (list|status) ")
+ pw.println("Lists available displays and which has the shade")
+ pw.println()
+ pw.println("shade_display_override any_external")
+ pw.println("Moves the shade to the first not-default display available")
+ }
override fun execute(pw: PrintWriter, args: List<String>) {
- if (args[0].lowercase() == "reset") {
+ CommandHandler(pw, args).execute()
+ }
+
+ /** Wrapper class to avoid propagating [PrintWriter] to all methods. */
+ private inner class CommandHandler(
+ private val pw: PrintWriter,
+ private val args: List<String>,
+ ) {
+
+ fun execute() {
+ when (val command = args.getOrNull(0)?.lowercase()) {
+ "reset" -> reset()
+ "list",
+ "status" -> printStatus()
+ "any_external" -> anyExternal()
+ else -> {
+ val cmdAsInteger = command?.toIntOrNull()
+ if (cmdAsInteger != null) {
+ changeDisplay(displayId = cmdAsInteger)
+ } else {
+ help(pw)
+ }
+ }
+ }
+ }
+
+ private fun reset() {
positionRepository.resetDisplayId()
pw.println("Reset shade primary display id to ${Display.DEFAULT_DISPLAY}")
- return
}
- val displayId: Int =
- try {
- args[0].toInt()
- } catch (e: NumberFormatException) {
- pw.println("Error: task id should be an integer")
- return
+ private fun printStatus() {
+ val displays = displaysRepository.displays.value
+ val shadeDisplay = positionRepository.displayId.value
+ pw.println("Available displays: ")
+ displays.forEach {
+ pw.print(" - ${it.displayId}")
+ pw.println(if (it.displayId == shadeDisplay) " (Shade window is here)" else "")
}
+ }
- if (displayId < 0) {
- pw.println("Error: display id should be positive integer")
+ private fun anyExternal() {
+ val anyExternalDisplay =
+ displaysRepository.displays.value.firstOrNull {
+ it.displayId != Display.DEFAULT_DISPLAY
+ }
+ if (anyExternalDisplay == null) {
+ pw.println("No external displays available.")
+ return
+ }
+ setDisplay(anyExternalDisplay.displayId)
}
- positionRepository.setDisplayId(displayId)
- pw.println("New shade primary display id is $displayId")
- }
+ private fun changeDisplay(displayId: Int) {
+ if (displayId < 0) {
+ pw.println("Error: display id should be positive integer")
+ }
- override fun help(pw: PrintWriter) {
- pw.println("shade_display_override <displayId> ")
- pw.println("Set the display which is holding the shade.")
- pw.println("shade_display_override reset ")
- pw.println("Reset the display which is holding the shade.")
+ setDisplay(displayId)
+ }
+
+ private fun setDisplay(id: Int) {
+ positionRepository.setDisplayId(id)
+ pw.println("New shade primary display id is $id")
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt
new file mode 100644
index 000000000000..6bb50f99b5e7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 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.shade
+
+import android.content.Context
+import android.graphics.PixelFormat
+import android.os.Binder
+import android.view.Gravity
+import android.view.ViewGroup
+import android.view.WindowManager.LayoutParams
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+
+object ShadeWindowLayoutParams {
+ /**
+ * Creates [LayoutParams] for the shade window.
+ *
+ * This is extracted to a single place as those layout params will be used by several places:
+ * - When sysui starts, and the shade is added the first time
+ * - When the shade moves to a different window (e.g. while an external display is connected)
+ */
+ fun create(context: Context): LayoutParams {
+ return LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ LayoutParams.TYPE_NOTIFICATION_SHADE,
+ LayoutParams.FLAG_NOT_FOCUSABLE or
+ LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING or
+ LayoutParams.FLAG_SPLIT_TOUCH or
+ LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
+ LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ // Now that the notification shade encompasses the sliding panel and its
+ // translucent backdrop, the entire thing is made TRANSLUCENT and is
+ // hardware-accelerated.
+ PixelFormat.TRANSLUCENT,
+ )
+ .apply {
+ token = Binder()
+ gravity = Gravity.TOP
+ fitInsetsTypes = 0
+ title = "NotificationShade"
+ packageName = context.packageName
+ layoutInDisplayCutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ privateFlags = privateFlags or LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE
+ if (SceneContainerFlag.isEnabled) {
+ // This prevents the appearance and disappearance of the software keyboard (also
+ // known as the "IME") from scrolling/panning the window to make room for the
+ // keyboard.
+ //
+ // The scene container logic does its own adjustment and animation when the IME
+ // appears or disappears.
+ softInputMode = LayoutParams.SOFT_INPUT_ADJUST_NOTHING
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
index 37210b90ee78..71c565816362 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
@@ -20,7 +20,7 @@ import android.view.Display
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-class FakeShadePositionRepository : ShadePositionRepository {
+class FakeShadeDisplayRepository : ShadeDisplaysRepository {
private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
override fun setDisplayId(displayId: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
index 24c067ae2371..4a95e339cade 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
@@ -17,15 +17,12 @@
package com.android.systemui.shade.data.repository
import android.view.Display
-import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.shade.ShadePrimaryDisplayCommand
-import com.android.systemui.statusbar.commandline.CommandRegistry
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-interface ShadePositionRepository {
+interface ShadeDisplaysRepository {
/** ID of the display which currently hosts the shade */
val displayId: StateFlow<Int>
@@ -41,9 +38,7 @@ interface ShadePositionRepository {
/** Source of truth for the display currently holding the shade. */
@SysUISingleton
-class ShadePositionRepositoryImpl
-@Inject
-constructor(private val commandRegistry: CommandRegistry) : ShadePositionRepository, CoreStartable {
+class ShadeDisplaysRepositoryImpl @Inject constructor() : ShadeDisplaysRepository {
private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
override val displayId: StateFlow<Int>
@@ -56,10 +51,4 @@ constructor(private val commandRegistry: CommandRegistry) : ShadePositionReposit
override fun resetDisplayId() {
_displayId.value = Display.DEFAULT_DISPLAY
}
-
- override fun start() {
- commandRegistry.registerCommand("shade_display_override") {
- ShadePrimaryDisplayCommand(this)
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
new file mode 100644
index 000000000000..432d5f553fbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2024 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.shade.domain.interactor
+
+import android.content.ComponentCallbacks
+import android.content.Context
+import android.content.MutableContextWrapper
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.util.Log
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
+import com.android.app.tracing.coroutines.launchTraced
+import com.android.app.tracing.traceSection
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.ShadeDisplayAware
+import com.android.systemui.shade.ShadeWindowLayoutParams
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
+import com.android.systemui.statusbar.phone.ConfigurationForwarder
+import com.android.systemui.util.kotlin.getOrNull
+import java.util.Optional
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.withContext
+
+/** Handles Shade window display change when [ShadeDisplaysRepository.displayId] changes. */
+@SysUISingleton
+class ShadeDisplaysInteractor
+@Inject
+constructor(
+ optionalShadeRootView: Optional<WindowRootView>,
+ private val shadePositionRepository: ShadeDisplaysRepository,
+ @ShadeDisplayAware private val shadeContext: Context,
+ @ShadeDisplayAware private val shadeResources: Resources,
+ private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+ @Background private val bgScope: CoroutineScope,
+ @ShadeDisplayAware private val shadeConfigurationForwarder: ConfigurationForwarder,
+ @Main private val mainThreadContext: CoroutineContext,
+) : CoreStartable {
+
+ private val shadeRootView =
+ optionalShadeRootView.getOrNull()
+ ?: error(
+ """
+ ShadeRootView must be provided for this ShadeDisplayInteractor to work.
+ If it is not, it means this is being instantiated in a SystemUI variant that shouldn't.
+ """
+ .trimIndent()
+ )
+ // TODO: b/362719719 - Get rid of this callback as the root view should automatically get the
+ // correct configuration once it's moved to another window.
+ private var unregisterConfigChangedCallbacks: (() -> Unit)? = null
+
+ override fun start() {
+ ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
+ bgScope.launchTraced(TAG) {
+ shadePositionRepository.displayId.collect { displayId -> moveShadeWindowTo(displayId) }
+ }
+ }
+
+ /** Tries to move the shade. If anything wrong happens, fails gracefully without crashing. */
+ private suspend fun moveShadeWindowTo(destinationId: Int) {
+ Log.d(TAG, "Trying to move shade window to display with id $destinationId")
+ val currentDisplay = shadeRootView.display
+ if (currentDisplay == null) {
+ Log.w(TAG, "Current shade display is null")
+ return
+ }
+ val currentId = currentDisplay.displayId
+ if (currentId == destinationId) {
+ Log.w(TAG, "Trying to move the shade to a display it was already in")
+ return
+ }
+ try {
+ moveShadeWindow(fromId = currentId, toId = destinationId)
+ } catch (e: IllegalStateException) {
+ Log.e(
+ TAG,
+ "Unable to move the shade window from display $currentId to $destinationId",
+ e,
+ )
+ }
+ }
+
+ private suspend fun moveShadeWindow(fromId: Int, toId: Int) {
+ val (_, _, _, sourceWm) = getDisplayWindowProperties(fromId)
+ val (_, _, destContext, destWm) = getDisplayWindowProperties(toId)
+ withContext(mainThreadContext) {
+ traceSection({ "MovingShadeWindow from $fromId to $toId" }) {
+ removeShade(sourceWm)
+ addShade(destWm)
+ overrideContextAndResources(newContext = destContext)
+ registerConfigurationChange(destContext)
+ }
+ traceSection("ShadeDisplaysInteractor#onConfigurationChanged") {
+ dispatchConfigurationChanged(destContext.resources.configuration)
+ }
+ }
+ }
+
+ private fun removeShade(wm: WindowManager): Unit =
+ traceSection("removeView") { wm.removeView(shadeRootView) }
+
+ private fun addShade(wm: WindowManager): Unit =
+ traceSection("addView") {
+ wm.addView(shadeRootView, ShadeWindowLayoutParams.create(shadeContext))
+ }
+
+ private fun overrideContextAndResources(newContext: Context) {
+ val contextWrapper =
+ shadeContext as? MutableContextWrapper
+ ?: error("Shade context is not a MutableContextWrapper!")
+ contextWrapper.baseContext = newContext
+ // Override needed in case someone is keeping a reference to the resources from the old
+ // context.
+ // TODO: b/362719719 - This shouldn't be needed, as resources should be updated when the
+ // window is moved to the new display automatically.
+ shadeResources.impl = shadeContext.resources.impl
+ }
+
+ private fun dispatchConfigurationChanged(newConfig: Configuration) {
+ shadeConfigurationForwarder.onConfigurationChanged(newConfig)
+ shadeRootView.dispatchConfigurationChanged(newConfig)
+ shadeRootView.requestLayout()
+ }
+
+ private fun registerConfigurationChange(context: Context) {
+ // we should keep only one at the time.
+ unregisterConfigChangedCallbacks?.invoke()
+ val callback =
+ object : ComponentCallbacks {
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ dispatchConfigurationChanged(newConfig)
+ }
+
+ override fun onLowMemory() {}
+ }
+ context.registerComponentCallbacks(callback)
+ unregisterConfigChangedCallbacks = {
+ context.unregisterComponentCallbacks(callback)
+ unregisterConfigChangedCallbacks = null
+ }
+ }
+
+ private fun getDisplayWindowProperties(displayId: Int): DisplayWindowProperties {
+ return displayWindowPropertiesRepository.get(displayId, TYPE_NOTIFICATION_SHADE)
+ }
+
+ private companion object {
+ const val TAG = "ShadeDisplaysInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 460bfbbcb3ab..a653ca2f80a9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -25,7 +25,7 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
@@ -47,7 +47,7 @@ class ShadeInteractorImpl
constructor(
@Application val scope: CoroutineScope,
deviceProvisioningInteractor: DeviceProvisioningInteractor,
- disableFlagsRepository: DisableFlagsRepository,
+ disableFlagsInteractor: DisableFlagsInteractor,
dozeParams: DozeParameters,
keyguardRepository: KeyguardRepository,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
@@ -61,13 +61,13 @@ constructor(
BaseShadeInteractor by baseShadeInteractor,
ShadeModeInteractor by shadeModeInteractor {
override val isShadeEnabled: StateFlow<Boolean> =
- disableFlagsRepository.disableFlags
+ disableFlagsInteractor.disableFlags
.map { it.isShadeEnabled() }
.flowName("isShadeEnabled")
.stateIn(scope, SharingStarted.Eagerly, initialValue = false)
override val isQsEnabled: StateFlow<Boolean> =
- disableFlagsRepository.disableFlags
+ disableFlagsInteractor.disableFlags
.map { it.isQuickSettingsEnabled() }
.flowName("isQsEnabled")
.stateIn(scope, SharingStarted.Eagerly, initialValue = false)
@@ -114,7 +114,7 @@ constructor(
override val isExpandToQsEnabled: Flow<Boolean> =
combine(
- disableFlagsRepository.disableFlags,
+ disableFlagsInteractor.disableFlags,
isShadeEnabled,
keyguardRepository.isDozing,
userSetupRepository.isUserSetUp,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index 45516aa69cd7..0d847d84c820 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -23,6 +23,7 @@ import android.icu.text.DateFormat
import android.icu.text.DisplayContext
import android.os.UserHandle
import android.provider.Settings
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.plugins.ActivityStarter
@@ -48,7 +49,6 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
-import com.android.app.tracing.coroutines.launchTraced as launch
/** Models UI state for the shade header. */
class ShadeHeaderViewModel
@@ -87,10 +87,6 @@ constructor(
/** Whether or not the privacy chip is enabled in the device privacy config. */
val isPrivacyChipEnabled: StateFlow<Boolean> = privacyChipInteractor.isChipEnabled
- private val _isDisabled = MutableStateFlow(false)
- /** Whether or not the Shade Header should be disabled based on disableFlags. */
- val isDisabled: StateFlow<Boolean> = _isDisabled.asStateFlow()
-
private val longerPattern = context.getString(R.string.abbrev_wday_month_day_no_year_alarm)
private val shorterPattern = context.getString(R.string.abbrev_month_day_no_year)
private val longerDateFormat = MutableStateFlow(getFormatFromPattern(longerPattern))
@@ -132,8 +128,6 @@ constructor(
.collect { _mobileSubIds.value = it }
}
- launch { shadeInteractor.isQsEnabled.map { !it }.collect { _isDisabled.value = it } }
-
awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
index b0777c9e20b9..dd1b58c47b63 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
@@ -27,24 +27,28 @@ import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
/** Returns collection of [UserAction] to [UserActionResult] pairs for opening the single shade. */
fun singleShadeActions(
- requireTwoPointersForTopEdgeForQs: Boolean = false
+ isDownFromTopEdgeEnabled: Boolean = true,
+ requireTwoPointersForTopEdgeForQs: Boolean = false,
): Array<Pair<UserAction, UserActionResult>> {
val shadeUserActionResult = UserActionResult(Scenes.Shade, isIrreversible = true)
val qsSceneUserActionResult = UserActionResult(Scenes.QuickSettings, isIrreversible = true)
- return arrayOf(
- // Swiping down, not from the edge, always goes to shade.
- Swipe.Down to shadeUserActionResult,
- Swipe.Down(pointerCount = 2) to shadeUserActionResult,
-
- // Swiping down from the top edge.
- swipeDownFromTop(pointerCount = 1) to
- if (requireTwoPointersForTopEdgeForQs) {
- shadeUserActionResult
- } else {
- qsSceneUserActionResult
- },
- swipeDownFromTop(pointerCount = 2) to qsSceneUserActionResult,
- )
+ return buildList {
+ // Swiping down, not from the edge, always goes to shade.
+ add(Swipe.Down to shadeUserActionResult)
+ add(Swipe.Down(pointerCount = 2) to shadeUserActionResult)
+ if (isDownFromTopEdgeEnabled) {
+ add(
+ swipeDownFromTop(pointerCount = 1) to
+ if (requireTwoPointersForTopEdgeForQs) {
+ shadeUserActionResult
+ } else {
+ qsSceneUserActionResult
+ }
+ )
+ add(swipeDownFromTop(pointerCount = 2) to qsSceneUserActionResult)
+ }
+ }
+ .toTypedArray()
}
/** Returns collection of [UserAction] to [UserActionResult] pairs for opening the split shade. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
index c019f308d3e5..72b03bfa20c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
@@ -14,7 +14,7 @@ per-file *Keyboard* = set noparent
per-file *Keyboard* = file:../keyguard/OWNERS
per-file *Keyguard* = set noparent
per-file *Keyguard* = file:../keyguard/OWNERS
-per-file *Notification* = set noparent
+# Not setting noparent here, since *Notification* also matches some status bar notification chips files (statusbar/chips/notification) which should be owned by the status bar team.
per-file *Notification* = file:notification/OWNERS
# Not setting noparent here, since *Mode* matches many other classes (e.g., *ViewModel*)
per-file *Mode* = file:notification/OWNERS
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 33f0c64269cc..6bec86a67e9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -177,8 +177,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
private float[] mMatrix;
private ColorMatrixColorFilter mMatrixColorFilter;
private Runnable mLayoutRunnable;
- private boolean mDismissed;
- private Runnable mOnDismissListener;
private boolean mIncreasedSize;
private boolean mShowsConversation;
private float mDozeAmount;
@@ -956,21 +954,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
mLayoutRunnable = runnable;
}
- public void setDismissed() {
- mDismissed = true;
- if (mOnDismissListener != null) {
- mOnDismissListener.run();
- }
- }
-
- public boolean isDismissed() {
- return mDismissed;
- }
-
- public void setOnDismissListener(Runnable onDismissListener) {
- mOnDismissListener = onDismissListener;
- }
-
@Override
public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
int areaTint = getTint(areas, this, tint);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index da04f6edf9e2..b2ca33a4aecf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -705,6 +705,7 @@ public class StatusBarStateControllerImpl implements
final boolean onBouncer = currentScene.equals(Scenes.Bouncer);
final boolean onCommunal = currentScene.equals(Scenes.Communal);
final boolean onGone = currentScene.equals(Scenes.Gone);
+ final boolean onDream = currentScene.equals(Scenes.Dream);
final boolean onLockscreen = currentScene.equals(Scenes.Lockscreen);
final boolean onQuickSettings = currentScene.equals(Scenes.QuickSettings);
final boolean onShade = currentScene.equals(Scenes.Shade);
@@ -765,6 +766,8 @@ public class StatusBarStateControllerImpl implements
// We get here if deviceUnlockStatus.isUnlocked is false but we are no longer on or over
// a keyguardish scene; we want to return SHADE_LOCKED until isUnlocked is also true.
newState = StatusBarState.SHADE_LOCKED;
+ } else if (onDream) {
+ newState = StatusBarState.SHADE_LOCKED;
} else {
throw new IllegalArgumentException(
"unhandled input to calculateStateFromSceneFramework: " + inputLogString);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipLogTags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipLogTags.kt
new file mode 100644
index 000000000000..6c1d6c52088f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipLogTags.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.statusbar.chips
+
+/** Helper class to ensure all tags used in [StatusBarChipsLog] are exactly the same length. */
+object StatusBarChipLogTags {
+ private const val TAG_LENGTH = 20
+
+ fun String.pad(): String {
+ return this.padEnd(TAG_LENGTH)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
index eaefc111ae3d..bb0467f10e16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
@@ -20,6 +20,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
@@ -47,6 +48,6 @@ constructor(
.stateIn(scope, SharingStarted.Lazily, OngoingCallModel.NoCall)
companion object {
- private const val TAG = "OngoingCall"
+ private val TAG = "OngoingCall".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index e82525810c64..b8cdd2587774 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -28,6 +28,7 @@ import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
import com.android.systemui.statusbar.chips.ui.model.ColorsModel
@@ -112,7 +113,7 @@ constructor(
ActivityTransitionAnimator.Controller.fromView(
backgroundView,
InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
- )
+ ),
)
}
}
@@ -121,10 +122,8 @@ constructor(
private val phoneIcon =
Icon.Resource(
com.android.internal.R.drawable.ic_phone,
- ContentDescription.Resource(
- R.string.ongoing_phone_call_content_description,
- ),
+ ContentDescription.Resource(R.string.ongoing_phone_call_content_description),
)
- private const val TAG = "CallVM"
+ private val TAG = "CallVM".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
index 7c95f1e42080..b3dbf299e7cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
@@ -21,6 +21,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.mediarouter.data.repository.MediaRouterRepository
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.casttootherdevice.domain.model.MediaRouterCastModel
import com.android.systemui.statusbar.policy.CastDevice
@@ -68,6 +69,6 @@ constructor(
}
companion object {
- private const val TAG = "MediaRouter"
+ private val TAG = "MediaRouter".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
index 11072068bef9..3422337523f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
@@ -28,6 +28,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.casttootherdevice.domain.interactor.MediaRouterChipInteractor
import com.android.systemui.statusbar.chips.casttootherdevice.domain.model.MediaRouterCastModel
@@ -255,6 +256,6 @@ constructor(
companion object {
@DrawableRes val CAST_TO_OTHER_DEVICE_ICON = R.drawable.ic_cast_connected
- private const val TAG = "CastToOtherVM"
+ private val TAG = "CastToOtherVM".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
index 27b2465d52b3..49c44798d2ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
import android.content.pm.PackageManager
+import android.media.projection.StopReason
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -25,6 +27,7 @@ import com.android.systemui.log.core.LogLevel
import com.android.systemui.mediaprojection.MediaProjectionUtils.packageHasCastingCapabilities
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
import javax.inject.Inject
@@ -33,7 +36,6 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Interactor for media projection events, used to show chips in the status bar for share-to-app and
@@ -104,10 +106,10 @@ constructor(
/** Stops the currently active projection. */
fun stopProjecting() {
- scope.launch { mediaProjectionRepository.stopProjecting() }
+ scope.launch { mediaProjectionRepository.stopProjecting(StopReason.STOP_PRIVACY_CHIP) }
}
companion object {
- private const val TAG = "MediaProjection"
+ private val TAG = "MediaProjection".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
index e3dc70af5fe6..f5952f4804fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -25,6 +25,7 @@ import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.screenrecord.domain.model.ScreenRecordChipModel
import javax.inject.Inject
@@ -143,6 +144,6 @@ constructor(
}
companion object {
- private const val TAG = "ScreenRecord"
+ private val TAG = "ScreenRecord".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
index eb735211a970..0065593c7b73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
@@ -30,6 +30,7 @@ import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.res.R
import com.android.systemui.screenrecord.data.model.ScreenRecordModel.Starting.Companion.toCountdownSeconds
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndMediaProjectionDialogHelper
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
@@ -84,7 +85,7 @@ constructor(
Icon.Resource(
ICON,
ContentDescription.Resource(
- R.string.screenrecord_ongoing_screen_only,
+ R.string.screenrecord_ongoing_screen_only
),
)
),
@@ -153,6 +154,6 @@ constructor(
companion object {
@DrawableRes val ICON = R.drawable.ic_screenrecord
- private const val TAG = "ScreenRecordVM"
+ private val TAG = "ScreenRecordVM".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
index 11d077fc09f1..2af86a51cf70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
@@ -28,6 +28,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
@@ -179,6 +180,6 @@ constructor(
companion object {
@DrawableRes val SHARE_TO_APP_ICON = R.drawable.ic_present_to_all
- private const val TAG = "ShareToAppVM"
+ private val TAG = "ShareToAppVM".pad()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index ed325970ebb2..45efc57685f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -20,6 +20,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModel
import com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel.CastToOtherDeviceChipViewModel
@@ -347,7 +348,7 @@ constructor(
}
companion object {
- private const val TAG = "ChipsViewModel"
+ private val TAG = "ChipsViewModel".pad()
private val DEFAULT_INTERNAL_HIDDEN_MODEL =
InternalChipModel.Hidden(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 434120051039..9b24d451f9cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -27,6 +27,8 @@ import com.android.systemui.log.LogBufferFactory
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.data.StatusBarDataLayerModule
import com.android.systemui.statusbar.data.repository.LightBarControllerStore
+import com.android.systemui.statusbar.phone.AutoHideController
+import com.android.systemui.statusbar.phone.AutoHideControllerImpl
import com.android.systemui.statusbar.phone.LightBarController
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl
@@ -79,6 +81,8 @@ interface StatusBarModule {
implFactory: StatusBarWindowControllerImpl.Factory
): StatusBarWindowController.Factory
+ @Binds @SysUISingleton fun autoHideController(impl: AutoHideControllerImpl): AutoHideController
+
companion object {
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
index 9004e5d12663..aeeb0427d24b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
@@ -22,7 +22,7 @@ import com.android.systemui.log.LogBuffer
import com.android.systemui.log.dagger.DisableFlagsRepositoryLog
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt
new file mode 100644
index 000000000000..4f1b97841fde
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.statusbar.disableflags.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+@SysUISingleton
+class DisableFlagsInteractor @Inject constructor(repository: DisableFlagsRepository) {
+ /** A model of the disable flags last received from [IStatusBar]. */
+ val disableFlags: StateFlow<DisableFlagsModel> = repository.disableFlags
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt
index ce25cf5895c1..6507237cfc24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt
@@ -1,18 +1,20 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-package com.android.systemui.statusbar.disableflags.data.model
+package com.android.systemui.statusbar.disableflags.shared.model
import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
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 a24f2672f251..85cd50565f88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -83,39 +83,36 @@ import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Named
-
/** Controller for managing the smartspace view on the lockscreen */
@SysUISingleton
class LockscreenSmartspaceController
@Inject
constructor(
- private val context: Context,
- private val featureFlags: FeatureFlags,
- private val activityStarter: ActivityStarter,
- private val falsingManager: FalsingManager,
- private val systemClock: SystemClock,
- private val secureSettings: SecureSettings,
- private val userTracker: UserTracker,
- private val contentResolver: ContentResolver,
- private val configurationController: ConfigurationController,
- private val statusBarStateController: StatusBarStateController,
- private val deviceProvisionedController: DeviceProvisionedController,
- private val bypassController: KeyguardBypassController,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val wakefulnessLifecycle: WakefulnessLifecycle,
- private val smartspaceViewModelFactory: SmartspaceViewModel.Factory,
- private val dumpManager: DumpManager,
- private val execution: Execution,
- @Main private val uiExecutor: Executor,
- @Background private val bgExecutor: Executor,
- @Main private val handler: Handler,
- @Background private val bgHandler: Handler,
- @Named(DATE_SMARTSPACE_DATA_PLUGIN)
- optionalDatePlugin: Optional<BcSmartspaceDataPlugin>,
- @Named(WEATHER_SMARTSPACE_DATA_PLUGIN)
- optionalWeatherPlugin: Optional<BcSmartspaceDataPlugin>,
- optionalPlugin: Optional<BcSmartspaceDataPlugin>,
- optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
+ private val context: Context,
+ private val featureFlags: FeatureFlags,
+ private val activityStarter: ActivityStarter,
+ private val falsingManager: FalsingManager,
+ private val systemClock: SystemClock,
+ private val secureSettings: SecureSettings,
+ private val userTracker: UserTracker,
+ private val contentResolver: ContentResolver,
+ private val configurationController: ConfigurationController,
+ private val statusBarStateController: StatusBarStateController,
+ private val deviceProvisionedController: DeviceProvisionedController,
+ private val bypassController: KeyguardBypassController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val wakefulnessLifecycle: WakefulnessLifecycle,
+ private val smartspaceViewModelFactory: SmartspaceViewModel.Factory,
+ private val dumpManager: DumpManager,
+ private val execution: Execution,
+ @Main private val uiExecutor: Executor,
+ @Background private val bgExecutor: Executor,
+ @Main private val handler: Handler,
+ @Background private val bgHandler: Handler,
+ @Named(DATE_SMARTSPACE_DATA_PLUGIN) optionalDatePlugin: Optional<BcSmartspaceDataPlugin>,
+ @Named(WEATHER_SMARTSPACE_DATA_PLUGIN) optionalWeatherPlugin: Optional<BcSmartspaceDataPlugin>,
+ optionalPlugin: Optional<BcSmartspaceDataPlugin>,
+ optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
) : Dumpable {
companion object {
private const val TAG = "LockscreenSmartspaceController"
@@ -135,11 +132,9 @@ constructor(
// Smartspace can be used on multiple displays, such as when the user casts their screen
@VisibleForTesting var smartspaceViews = mutableSetOf<SmartspaceView>()
- private var regionSamplers =
- mutableMapOf<SmartspaceView, RegionSampler>()
+ private var regionSamplers = mutableMapOf<SmartspaceView, RegionSampler>()
- private val regionSamplingEnabled =
- featureFlags.isEnabled(Flags.REGION_SAMPLING)
+ private val regionSamplingEnabled = featureFlags.isEnabled(Flags.REGION_SAMPLING)
private var isRegionSamplersCreated = false
private var showNotifications = false
private var showSensitiveContentForCurrentUser = false
@@ -157,119 +152,130 @@ constructor(
// how we test color updates when theme changes (See testThemeChangeUpdatesTextColor).
// TODO: Move logic into SmartspaceView
- var stateChangeListener = object : View.OnAttachStateChangeListener {
- override fun onViewAttachedToWindow(v: View) {
- (v as SmartspaceView).setSplitShadeEnabled(mSplitShadeEnabled)
- smartspaceViews.add(v as SmartspaceView)
-
- connectSession()
-
- updateTextColorFromWallpaper()
- statusBarStateListener.onDozeAmountChanged(0f, statusBarStateController.dozeAmount)
-
- if (regionSamplingEnabled && (!regionSamplers.containsKey(v))) {
- var regionSampler = RegionSampler(
- v as View,
- uiExecutor,
- bgExecutor,
- regionSamplingEnabled,
- isLockscreen = true,
- ) { updateTextColorFromRegionSampler() }
- initializeTextColors(regionSampler)
- regionSamplers[v] = regionSampler
- regionSampler.startRegionSampler()
+ var stateChangeListener =
+ object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {
+ (v as SmartspaceView).setSplitShadeEnabled(mSplitShadeEnabled)
+ smartspaceViews.add(v as SmartspaceView)
+
+ connectSession()
+
+ updateTextColorFromWallpaper()
+ statusBarStateListener.onDozeAmountChanged(0f, statusBarStateController.dozeAmount)
+
+ if (regionSamplingEnabled && (!regionSamplers.containsKey(v))) {
+ var regionSampler =
+ RegionSampler(
+ v as View,
+ uiExecutor,
+ bgExecutor,
+ regionSamplingEnabled,
+ isLockscreen = true,
+ ) {
+ updateTextColorFromRegionSampler()
+ }
+ initializeTextColors(regionSampler)
+ regionSamplers[v] = regionSampler
+ regionSampler.startRegionSampler()
+ }
}
- }
- override fun onViewDetachedFromWindow(v: View) {
- smartspaceViews.remove(v as SmartspaceView)
+ override fun onViewDetachedFromWindow(v: View) {
+ smartspaceViews.remove(v as SmartspaceView)
- regionSamplers[v]?.stopRegionSampler()
- regionSamplers.remove(v as SmartspaceView)
+ regionSamplers[v]?.stopRegionSampler()
+ regionSamplers.remove(v as SmartspaceView)
- if (smartspaceViews.isEmpty()) {
- disconnect()
+ if (smartspaceViews.isEmpty()) {
+ disconnect()
+ }
}
}
- }
- private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
- execution.assertIsMainThread()
+ private val sessionListener =
+ SmartspaceSession.OnTargetsAvailableListener { targets ->
+ execution.assertIsMainThread()
- // The weather data plugin takes unfiltered targets and performs the filtering internally.
- weatherPlugin?.onTargetsAvailable(targets)
-
- val now = Instant.ofEpochMilli(systemClock.currentTimeMillis())
- val weatherTarget = targets.find { t ->
- t.featureType == SmartspaceTarget.FEATURE_WEATHER &&
- now.isAfter(Instant.ofEpochMilli(t.creationTimeMillis)) &&
- now.isBefore(Instant.ofEpochMilli(t.expiryTimeMillis))
- }
- if (weatherTarget != null) {
- val clickIntent = weatherTarget.headerAction?.intent
- val weatherData = weatherTarget.baseAction?.extras?.let { extras ->
- WeatherData.fromBundle(
- extras,
- ) { _ ->
- if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- activityStarter.startActivity(
- clickIntent,
- true, /* dismissShade */
- null,
- false)
- }
+ // The weather data plugin takes unfiltered targets and performs the filtering
+ // internally.
+ weatherPlugin?.onTargetsAvailable(targets)
+
+ val now = Instant.ofEpochMilli(systemClock.currentTimeMillis())
+ val weatherTarget =
+ targets.find { t ->
+ t.featureType == SmartspaceTarget.FEATURE_WEATHER &&
+ now.isAfter(Instant.ofEpochMilli(t.creationTimeMillis)) &&
+ now.isBefore(Instant.ofEpochMilli(t.expiryTimeMillis))
}
- }
+ if (weatherTarget != null) {
+ val clickIntent = weatherTarget.headerAction?.intent
+ val weatherData =
+ weatherTarget.baseAction?.extras?.let { extras ->
+ WeatherData.fromBundle(extras) { _ ->
+ if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ activityStarter.startActivity(
+ clickIntent,
+ true, /* dismissShade */
+ null,
+ false,
+ )
+ }
+ }
+ }
- if (weatherData != null) {
- keyguardUpdateMonitor.sendWeatherData(weatherData)
+ if (weatherData != null) {
+ keyguardUpdateMonitor.sendWeatherData(weatherData)
+ }
}
- }
- val filteredTargets = targets.filter(::filterSmartspaceTarget)
+ val filteredTargets = targets.filter(::filterSmartspaceTarget)
- synchronized(recentSmartspaceData) {
- recentSmartspaceData.offerLast(filteredTargets)
- if (recentSmartspaceData.size > MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP) {
- recentSmartspaceData.pollFirst()
+ synchronized(recentSmartspaceData) {
+ recentSmartspaceData.offerLast(filteredTargets)
+ if (recentSmartspaceData.size > MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP) {
+ recentSmartspaceData.pollFirst()
+ }
}
- }
-
- plugin?.onTargetsAvailable(filteredTargets)
- }
- private val userTrackerCallback = object : UserTracker.Callback {
- override fun onUserChanged(newUser: Int, userContext: Context) {
- execution.assertIsMainThread()
- reloadSmartspace()
+ plugin?.onTargetsAvailable(filteredTargets)
}
- }
- private val settingsObserver = object : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean, uri: Uri?) {
- execution.assertIsMainThread()
- reloadSmartspace()
+ private val userTrackerCallback =
+ object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ execution.assertIsMainThread()
+ reloadSmartspace()
+ }
}
- }
- private val configChangeListener = object : ConfigurationController.ConfigurationListener {
- override fun onThemeChanged() {
- execution.assertIsMainThread()
- updateTextColorFromWallpaper()
+ private val settingsObserver =
+ object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ execution.assertIsMainThread()
+ reloadSmartspace()
+ }
}
- }
- private val statusBarStateListener = object : StatusBarStateController.StateListener {
- override fun onDozeAmountChanged(linear: Float, eased: Float) {
- execution.assertIsMainThread()
- smartspaceViews.forEach { it.setDozeAmount(eased) }
+ private val configChangeListener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onThemeChanged() {
+ execution.assertIsMainThread()
+ updateTextColorFromWallpaper()
+ }
}
- override fun onDozingChanged(isDozing: Boolean) {
- execution.assertIsMainThread()
- smartspaceViews.forEach { it.setDozing(isDozing) }
+ private val statusBarStateListener =
+ object : StatusBarStateController.StateListener {
+ override fun onDozeAmountChanged(linear: Float, eased: Float) {
+ execution.assertIsMainThread()
+ smartspaceViews.forEach { it.setDozeAmount(eased) }
+ }
+
+ override fun onDozingChanged(isDozing: Boolean) {
+ execution.assertIsMainThread()
+ smartspaceViews.forEach { it.setDozing(isDozing) }
+ }
}
- }
private val deviceProvisionedListener =
object : DeviceProvisionedController.DeviceProvisionedListener {
@@ -313,11 +319,8 @@ constructor(
val isWeatherEnabled: Boolean
get() {
val showWeather =
- secureSettings.getIntForUser(
- LOCK_SCREEN_WEATHER_ENABLED,
- 1,
- userTracker.userId,
- ) == 1
+ secureSettings.getIntForUser(LOCK_SCREEN_WEATHER_ENABLED, 1, userTracker.userId) ==
+ 1
return showWeather
}
@@ -326,9 +329,7 @@ constructor(
smartspaceViews.forEach { it.setKeyguardBypassEnabled(bypassEnabled) }
}
- /**
- * Constructs the date view and connects it to the smartspace service.
- */
+ /** Constructs the date view and connects it to the smartspace service. */
fun buildAndConnectDateView(parent: ViewGroup): View? {
execution.assertIsMainThread()
@@ -343,16 +344,14 @@ constructor(
buildView(
surfaceName = SmartspaceViewModel.SURFACE_DATE_VIEW,
parent = parent,
- plugin = datePlugin
+ plugin = datePlugin,
)
connectSession()
return view
}
- /**
- * Constructs the weather view and connects it to the smartspace service.
- */
+ /** Constructs the weather view and connects it to the smartspace service. */
fun buildAndConnectWeatherView(parent: ViewGroup): View? {
execution.assertIsMainThread()
@@ -367,16 +366,14 @@ constructor(
buildView(
surfaceName = SmartspaceViewModel.SURFACE_WEATHER_VIEW,
parent = parent,
- plugin = weatherPlugin
+ plugin = weatherPlugin,
)
connectSession()
return view
}
- /**
- * Constructs the smartspace view and connects it to the smartspace service.
- */
+ /** Constructs the smartspace view and connects it to the smartspace service. */
fun buildAndConnectView(parent: ViewGroup): View? {
execution.assertIsMainThread()
@@ -384,12 +381,14 @@ constructor(
throw RuntimeException("Cannot build view when not enabled")
}
+ configPlugin?.let { plugin?.registerConfigProvider(it) }
+
val view =
buildView(
surfaceName = SmartspaceViewModel.SURFACE_GENERAL_VIEW,
parent = parent,
plugin = plugin,
- configPlugin = configPlugin
+ configPlugin = configPlugin,
)
connectSession()
@@ -400,7 +399,7 @@ constructor(
surfaceName: String,
parent: ViewGroup,
plugin: BcSmartspaceDataPlugin?,
- configPlugin: BcSmartspaceConfigPlugin? = null
+ configPlugin: BcSmartspaceConfigPlugin? = null,
): View? {
if (plugin == null) {
return null
@@ -413,37 +412,41 @@ constructor(
ssView.setTimeChangedDelegate(SmartspaceTimeChangedDelegate(keyguardUpdateMonitor))
ssView.registerDataProvider(plugin)
- ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
- override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
- if (showOnLockscreen) {
- activityStarter.startActivity(
+ ssView.setIntentStarter(
+ object : BcSmartspaceDataPlugin.IntentStarter {
+ override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
+ if (showOnLockscreen) {
+ activityStarter.startActivity(
intent,
true, /* dismissShade */
// launch animator - looks bad with the transparent smartspace bg
null,
- true
- )
- } else {
- activityStarter.postStartActivityDismissingKeyguard(intent, 0)
+ true,
+ )
+ } else {
+ activityStarter.postStartActivityDismissingKeyguard(intent, 0)
+ }
}
- }
- override fun startPendingIntent(
+ override fun startPendingIntent(
view: View,
pi: PendingIntent,
- showOnLockscreen: Boolean
- ) {
- if (showOnLockscreen) {
- val options = ActivityOptions.makeBasic()
- .setPendingIntentBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
- .toBundle()
- pi.send(options)
- } else {
- activityStarter.postStartActivityDismissingKeyguard(pi)
+ showOnLockscreen: Boolean,
+ ) {
+ if (showOnLockscreen) {
+ val options =
+ ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ )
+ .toBundle()
+ pi.send(options)
+ } else {
+ activityStarter.postStartActivityDismissingKeyguard(pi)
+ }
}
}
- })
+ )
ssView.setFalsingManager(falsingManager)
ssView.setKeyguardBypassEnabled(bypassController.bypassEnabled)
return (ssView as View).apply {
@@ -452,10 +455,7 @@ constructor(
if (smartspaceLockscreenViewmodel()) {
val viewModel = smartspaceViewModelFactory.create(surfaceName)
- SmartspaceViewBinder.bind(
- smartspaceView = ssView,
- viewModel = viewModel,
- )
+ SmartspaceViewBinder.bind(smartspaceView = ssView, viewModel = viewModel)
}
}
}
@@ -473,34 +473,41 @@ constructor(
// Only connect after the device is fully provisioned to avoid connection caching
// issues
- if (!deviceProvisionedController.isDeviceProvisioned() ||
- !deviceProvisionedController.isCurrentUserSetup()) {
+ if (
+ !deviceProvisionedController.isDeviceProvisioned() ||
+ !deviceProvisionedController.isCurrentUserSetup()
+ ) {
return
}
- val newSession = userSmartspaceManager?.createSmartspaceSession(
- SmartspaceConfig.Builder(
- userTracker.userContext, BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD
- ).build()
+ val newSession =
+ userSmartspaceManager?.createSmartspaceSession(
+ SmartspaceConfig.Builder(
+ userTracker.userContext,
+ BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD,
+ )
+ .build()
+ )
+ Log.d(
+ TAG,
+ "Starting smartspace session for " + BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD,
)
- Log.d(TAG, "Starting smartspace session for " +
- BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
newSession?.addOnTargetsAvailableListener(uiExecutor, sessionListener)
this.session = newSession
deviceProvisionedController.removeCallback(deviceProvisionedListener)
userTracker.addCallback(userTrackerCallback, uiExecutor)
contentResolver.registerContentObserver(
- secureSettings.getUriFor(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
- true,
- settingsObserver,
- UserHandle.USER_ALL
+ secureSettings.getUriFor(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ settingsObserver,
+ UserHandle.USER_ALL,
)
contentResolver.registerContentObserver(
- secureSettings.getUriFor(LOCK_SCREEN_SHOW_NOTIFICATIONS),
- true,
- settingsObserver,
- UserHandle.USER_ALL
+ secureSettings.getUriFor(LOCK_SCREEN_SHOW_NOTIFICATIONS),
+ true,
+ settingsObserver,
+ UserHandle.USER_ALL,
)
configurationController.addCallback(configChangeListener)
statusBarStateController.addCallback(statusBarStateListener)
@@ -522,16 +529,12 @@ constructor(
smartspaceViews.forEach { it.setSplitShadeEnabled(enabled) }
}
- /**
- * Requests the smartspace session for an update.
- */
+ /** Requests the smartspace session for an update. */
fun requestSmartspaceUpdate() {
session?.requestSmartspaceUpdate()
}
- /**
- * Disconnects the smartspace view from the smartspace service and cleans up any resources.
- */
+ /** Disconnects the smartspace view from the smartspace service and cleans up any resources. */
fun disconnect() {
if (!smartspaceViews.isEmpty()) return
if (suppressDisconnects) return
@@ -638,7 +641,7 @@ constructor(
private fun updateTextColorFromWallpaper() {
if (!regionSamplingEnabled || regionSamplers.isEmpty()) {
val wallpaperTextColor =
- Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor)
+ Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor)
smartspaceViews.forEach { it.setPrimaryTextColor(wallpaperTextColor) }
} else {
updateTextColorFromRegionSampler()
@@ -646,26 +649,25 @@ constructor(
}
private fun reloadSmartspace() {
- showNotifications = secureSettings.getIntForUser(
- LOCK_SCREEN_SHOW_NOTIFICATIONS,
- 0,
- userTracker.userId
- ) == 1
-
- showSensitiveContentForCurrentUser = secureSettings.getIntForUser(
- LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
- 0,
- userTracker.userId
- ) == 1
+ showNotifications =
+ secureSettings.getIntForUser(LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userTracker.userId) == 1
- managedUserHandle = getWorkProfileUser()
- val managedId = managedUserHandle?.identifier
- if (managedId != null) {
- showSensitiveContentForManagedUser = secureSettings.getIntForUser(
+ showSensitiveContentForCurrentUser =
+ secureSettings.getIntForUser(
LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
0,
- managedId
+ userTracker.userId,
) == 1
+
+ managedUserHandle = getWorkProfileUser()
+ val managedId = managedUserHandle?.identifier
+ if (managedId != null) {
+ showSensitiveContentForManagedUser =
+ secureSettings.getIntForUser(
+ LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ 0,
+ managedId,
+ ) == 1
}
session?.requestSmartspaceUpdate()
@@ -682,9 +684,7 @@ constructor(
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.asIndenting().run {
- printCollection("Region Samplers", regionSamplers.values) {
- it.dump(this)
- }
+ printCollection("Region Samplers", regionSamplers.values) { it.dump(this) }
}
pw.println("Recent BC Smartspace Targets (most recent first)")
@@ -707,15 +707,17 @@ constructor(
private val keyguardUpdateMonitor: KeyguardUpdateMonitor
) : TimeChangedDelegate {
private var keyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback? = null
+
override fun register(callback: Runnable) {
if (keyguardUpdateMonitorCallback != null) {
unregister()
}
- keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
- override fun onTimeChanged() {
- callback.run()
+ keyguardUpdateMonitorCallback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onTimeChanged() {
+ callback.run()
+ }
}
- }
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
callback.run()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
deleted file mode 100644
index 0299ebcdf043..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright (C) 2024 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.statusbar.notification;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Region;
-import android.os.Handler;
-import android.util.ArrayMap;
-import android.util.Pools;
-
-import androidx.collection.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.policy.SystemBarUtils;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.res.R;
-import com.android.systemui.scene.shared.flag.SceneContainerFlag;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
-import com.android.systemui.statusbar.notification.collection.provider.OnReorderingBannedListener;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
-import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.AnimationStateHandler;
-import com.android.systemui.statusbar.policy.AvalancheController;
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.android.systemui.util.kotlin.JavaAdapter;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.time.SystemClock;
-
-import kotlinx.coroutines.flow.Flow;
-import kotlinx.coroutines.flow.MutableStateFlow;
-import kotlinx.coroutines.flow.StateFlow;
-import kotlinx.coroutines.flow.StateFlowKt;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.Stack;
-
-import javax.inject.Inject;
-
-/** A implementation of HeadsUpManager for phone. */
-@SysUISingleton
-public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
- HeadsUpRepository, OnHeadsUpChangedListener {
- private static final String TAG = "HeadsUpManagerPhone";
-
- @VisibleForTesting
- public final int mExtensionTime;
- private final KeyguardBypassController mBypassController;
- private final GroupMembershipManager mGroupMembershipManager;
- private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
- private final VisualStabilityProvider mVisualStabilityProvider;
-
- private AvalancheController mAvalancheController;
-
- // TODO(b/328393698) move the topHeadsUpRow logic to an interactor
- private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
- StateFlowKt.MutableStateFlow(null);
- private final MutableStateFlow<Set<HeadsUpRowRepository>> mHeadsUpNotificationRows =
- StateFlowKt.MutableStateFlow(new HashSet<>());
- private final MutableStateFlow<Boolean> mHeadsUpAnimatingAway =
- StateFlowKt.MutableStateFlow(false);
- private boolean mReleaseOnExpandFinish;
- private boolean mTrackingHeadsUp;
- private final HashSet<String> mSwipedOutKeys = new HashSet<>();
- private final HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
- @VisibleForTesting
- public final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
- = new ArraySet<>();
- private boolean mIsShadeOrQsExpanded;
- private boolean mIsQsExpanded;
- private int mStatusBarState;
- private AnimationStateHandler mAnimationStateHandler;
-
- private int mHeadsUpInset;
-
- // Used for determining the region for touch interaction
- private final Region mTouchableRegion = new Region();
-
- private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
- private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();
-
- @Override
- public HeadsUpEntryPhone acquire() {
- NotificationThrottleHun.assertInLegacyMode();
- if (!mPoolObjects.isEmpty()) {
- return mPoolObjects.pop();
- }
- return new HeadsUpEntryPhone();
- }
-
- @Override
- public boolean release(@NonNull HeadsUpEntryPhone instance) {
- NotificationThrottleHun.assertInLegacyMode();
- mPoolObjects.push(instance);
- return true;
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Constructor:
- @Inject
- public HeadsUpManagerPhone(
- @NonNull final Context context,
- HeadsUpManagerLogger logger,
- StatusBarStateController statusBarStateController,
- KeyguardBypassController bypassController,
- GroupMembershipManager groupMembershipManager,
- VisualStabilityProvider visualStabilityProvider,
- ConfigurationController configurationController,
- @Main Handler handler,
- GlobalSettings globalSettings,
- SystemClock systemClock,
- @Main DelayableExecutor executor,
- AccessibilityManagerWrapper accessibilityManagerWrapper,
- UiEventLogger uiEventLogger,
- JavaAdapter javaAdapter,
- ShadeInteractor shadeInteractor,
- AvalancheController avalancheController) {
- super(context, logger, handler, globalSettings, systemClock, executor,
- accessibilityManagerWrapper, uiEventLogger, avalancheController);
- Resources resources = mContext.getResources();
- mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
- statusBarStateController.addCallback(mStatusBarStateListener);
- mBypassController = bypassController;
- mGroupMembershipManager = groupMembershipManager;
- mVisualStabilityProvider = visualStabilityProvider;
- mAvalancheController = avalancheController;
- updateResources();
- configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
- @Override
- public void onDensityOrFontScaleChanged() {
- updateResources();
- }
-
- @Override
- public void onThemeChanged() {
- updateResources();
- }
- });
- javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
- this::onShadeOrQsExpanded);
- if (SceneContainerFlag.isEnabled()) {
- javaAdapter.alwaysCollectFlow(shadeInteractor.isQsExpanded(),
- this::onQsExpanded);
- }
- if (NotificationThrottleHun.isEnabled()) {
- mVisualStabilityProvider.addPersistentReorderingBannedListener(
- mOnReorderingBannedListener);
- mVisualStabilityProvider.addPersistentReorderingAllowedListener(
- mOnReorderingAllowedListener);
- }
- }
-
- public void setAnimationStateHandler(AnimationStateHandler handler) {
- mAnimationStateHandler = handler;
- }
-
- private void updateResources() {
- Resources resources = mContext.getResources();
- mHeadsUpInset = SystemBarUtils.getStatusBarHeight(mContext)
- + resources.getDimensionPixelSize(R.dimen.heads_up_status_bar_padding);
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Public methods:
-
- /**
- * Add a listener to receive callbacks {@link #setHeadsUpAnimatingAway(boolean)}
- */
- @Override
- public void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {
- mHeadsUpPhoneListeners.add(listener);
- }
-
- /**
- * Gets the touchable region needed for heads up notifications. Returns null if no touchable
- * region is required (ie: no heads up notification currently exists).
- */
- // TODO(b/347007367): With scene container enabled this method may report outdated regions
- @Override
- public @Nullable Region getTouchableRegion() {
- NotificationEntry topEntry = getTopEntry();
-
- // This call could be made in an inconsistent state while the pinnedMode hasn't been
- // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's
- // therefore also check if the topEntry is null.
- if (!hasPinnedHeadsUp() || topEntry == null) {
- return null;
- } else {
- if (topEntry.rowIsChildInGroup()) {
- final NotificationEntry groupSummary =
- mGroupMembershipManager.getGroupSummary(topEntry);
- if (groupSummary != null) {
- topEntry = groupSummary;
- }
- }
- ExpandableNotificationRow topRow = topEntry.getRow();
- int[] tmpArray = new int[2];
- topRow.getLocationOnScreen(tmpArray);
- int minX = tmpArray[0];
- int maxX = tmpArray[0] + topRow.getWidth();
- int height = topRow.getIntrinsicHeight();
- final boolean stretchToTop = tmpArray[1] <= mHeadsUpInset;
- mTouchableRegion.set(minX, stretchToTop ? 0 : tmpArray[1], maxX, tmpArray[1] + height);
- return mTouchableRegion;
- }
- }
-
- /**
- * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
- * that a user might have consciously clicked on it.
- *
- * @param key the key of the touched notification
- * @return whether the touch is invalid and should be discarded
- */
- @Override
- public boolean shouldSwallowClick(@NonNull String key) {
- BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
- return entry != null && mSystemClock.elapsedRealtime() < entry.mPostTime;
- }
-
- @Override
- public void releaseAfterExpansion() {
- if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
- onExpandingFinished();
- }
-
- public void onExpandingFinished() {
- if (mReleaseOnExpandFinish) {
- releaseAllImmediately();
- mReleaseOnExpandFinish = false;
- } else {
- for (NotificationEntry entry: getAllEntries().toList()) {
- entry.setSeenInShade(true);
- }
- for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
- if (isHeadsUpEntry(entry.getKey())) {
- // Maybe the heads-up was removed already
- removeEntry(entry.getKey(), "onExpandingFinished");
- }
- }
- }
- mEntriesToRemoveAfterExpand.clear();
- }
-
- /**
- * Sets the tracking-heads-up flag. If the flag is true, HeadsUpManager doesn't remove the entry
- * from the list even after a Heads Up Notification is gone.
- */
- public void setTrackingHeadsUp(boolean trackingHeadsUp) {
- mTrackingHeadsUp = trackingHeadsUp;
- }
-
- private void onShadeOrQsExpanded(Boolean isExpanded) {
- if (isExpanded != mIsShadeOrQsExpanded) {
- mIsShadeOrQsExpanded = isExpanded;
- if (!SceneContainerFlag.isEnabled() && isExpanded) {
- mHeadsUpAnimatingAway.setValue(false);
- }
- }
- }
-
- private void onQsExpanded(Boolean isQsExpanded) {
- if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
- if (isQsExpanded != mIsQsExpanded) mIsQsExpanded = isQsExpanded;
- }
-
- /**
- * Set that we are exiting the headsUp pinned mode, but some notifications might still be
- * animating out. This is used to keep the touchable regions in a reasonable state.
- */
- @Override
- public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
- if (headsUpAnimatingAway != mHeadsUpAnimatingAway.getValue()) {
- for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
- listener.onHeadsUpAnimatingAwayStateChanged(headsUpAnimatingAway);
- }
- mHeadsUpAnimatingAway.setValue(headsUpAnimatingAway);
- }
- }
-
- @Override
- public void unpinAll(boolean userUnPinned) {
- super.unpinAll(userUnPinned);
- }
-
- /**
- * Notifies that a remote input textbox in notification gets active or inactive.
- *
- * @param entry The entry of the target notification.
- * @param remoteInputActive True to notify active, False to notify inactive.
- */
- public void setRemoteInputActive(
- @NonNull NotificationEntry entry, boolean remoteInputActive) {
- HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.getKey());
- if (headsUpEntry != null && headsUpEntry.mRemoteInputActive != remoteInputActive) {
- headsUpEntry.mRemoteInputActive = remoteInputActive;
- if (ExpandHeadsUpOnInlineReply.isEnabled() && remoteInputActive) {
- headsUpEntry.mRemoteInputActivatedAtLeastOnce = true;
- }
- if (remoteInputActive) {
- headsUpEntry.cancelAutoRemovalCallbacks("setRemoteInputActive(true)");
- } else {
- headsUpEntry.updateEntry(false /* updatePostTime */, "setRemoteInputActive(false)");
- }
- onEntryUpdated(headsUpEntry);
- }
- }
-
- /**
- * Sets whether an entry's guts are exposed and therefore it should stick in the heads up
- * area if it's pinned until it's hidden again.
- */
- public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
- HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
- if (!(headsUpEntry instanceof HeadsUpEntryPhone)) return;
- HeadsUpEntryPhone headsUpEntryPhone = (HeadsUpEntryPhone)headsUpEntry;
- if (entry.isRowPinned() || !gutsShown) {
- headsUpEntryPhone.setGutsShownPinned(gutsShown);
- }
- }
-
- /**
- * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
- * longer.
- */
- public void extendHeadsUp() {
- HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
- if (topEntry == null) {
- return;
- }
- topEntry.extendPulse();
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // HeadsUpManager public methods overrides and overloads:
-
- @Override
- public boolean isTrackingHeadsUp() {
- return mTrackingHeadsUp;
- }
-
- @Override
- public void snooze() {
- super.snooze();
- mReleaseOnExpandFinish = true;
- }
-
- public void addSwipedOutNotification(@NonNull String key) {
- mSwipedOutKeys.add(key);
- }
-
- @Override
- public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
- boolean animate, @NonNull String reason) {
- if (animate) {
- return removeNotification(key, releaseImmediately,
- "removeNotification(animate: true), reason: " + reason);
- } else {
- mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
- final boolean removed = removeNotification(key, releaseImmediately,
- "removeNotification(animate: false), reason: " + reason);
- mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
- return removed;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Dumpable overrides:
-
- @Override
- public void dump(PrintWriter pw, String[] args) {
- pw.println("HeadsUpManagerPhone state:");
- dumpInternal(pw, args);
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // OnReorderingAllowedListener:
-
- private final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> {
- if (NotificationThrottleHun.isEnabled()) {
- mAvalancheController.setEnableAtRuntime(true);
- if (mEntriesToRemoveWhenReorderingAllowed.isEmpty()) {
- return;
- }
- }
- mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
- for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
- if (entry != null && isHeadsUpEntry(entry.getKey())) {
- // Maybe the heads-up was removed already
- removeEntry(entry.getKey(), "mOnReorderingAllowedListener");
- }
- }
- mEntriesToRemoveWhenReorderingAllowed.clear();
- mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
- };
-
- private final OnReorderingBannedListener mOnReorderingBannedListener = () -> {
- if (mAvalancheController != null) {
- // In open shade the first HUN is pinned, and visual stability logic prevents us from
- // unpinning this first HUN as long as the shade remains open. AvalancheController only
- // shows the next HUN when the currently showing HUN is unpinned, so we must disable
- // throttling here so that the incoming HUN stream is not forever paused. This is reset
- // when reorder becomes allowed.
- mAvalancheController.setEnableAtRuntime(false);
-
- // Note that we cannot do the above when
- // 1) The remove runnable runs because its delay means it may not run before shade close
- // 2) Reordering is allowed again (when shade closes) because the HUN appear animation
- // will have started by then
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // HeadsUpManager utility (protected) methods overrides:
-
- @NonNull
- @Override
- protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
- if (NotificationThrottleHun.isEnabled()) {
- return new HeadsUpEntryPhone(entry);
- } else {
- HeadsUpEntryPhone headsUpEntry = mEntryPool.acquire();
- headsUpEntry.setEntry(entry);
- return headsUpEntry;
- }
- }
-
- @Override
- protected void onEntryAdded(HeadsUpEntry headsUpEntry) {
- super.onEntryAdded(headsUpEntry);
- updateTopHeadsUpFlow();
- updateHeadsUpFlow();
- }
-
- @Override
- protected void onEntryUpdated(HeadsUpEntry headsUpEntry) {
- super.onEntryUpdated(headsUpEntry);
- // no need to update the list here
- updateTopHeadsUpFlow();
- }
-
- @Override
- protected void onEntryRemoved(HeadsUpEntry headsUpEntry) {
- super.onEntryRemoved(headsUpEntry);
- if (!NotificationThrottleHun.isEnabled()) {
- mEntryPool.release((HeadsUpEntryPhone) headsUpEntry);
- }
- updateTopHeadsUpFlow();
- updateHeadsUpFlow();
- if (NotificationThrottleHun.isEnabled()) {
- if (headsUpEntry.mEntry != null) {
- if (mEntriesToRemoveWhenReorderingAllowed.contains(headsUpEntry.mEntry)) {
- mEntriesToRemoveWhenReorderingAllowed.remove(headsUpEntry.mEntry);
- }
- }
- }
- }
-
- private void updateTopHeadsUpFlow() {
- mTopHeadsUpRow.setValue((HeadsUpRowRepository) getTopHeadsUpEntry());
- }
-
- private void updateHeadsUpFlow() {
- mHeadsUpNotificationRows.setValue(new HashSet<>(getHeadsUpEntryPhoneMap().values()));
- }
-
- @Override
- protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
- boolean pin = mStatusBarState == StatusBarState.SHADE && !mIsShadeOrQsExpanded;
- if (SceneContainerFlag.isEnabled()) {
- pin |= mIsQsExpanded;
- }
- if (mBypassController.getBypassEnabled()) {
- pin |= mStatusBarState == StatusBarState.KEYGUARD;
- }
- return pin || super.shouldHeadsUpBecomePinned(entry);
- }
-
- @Override
- protected void dumpInternal(PrintWriter pw, String[] args) {
- super.dumpInternal(pw, args);
- pw.print(" mBarState=");
- pw.println(mStatusBarState);
- pw.print(" mTouchableRegion=");
- pw.println(mTouchableRegion);
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Private utility methods:
-
- @NonNull
- private ArrayMap<String, HeadsUpEntryPhone> getHeadsUpEntryPhoneMap() {
- //noinspection unchecked
- return (ArrayMap<String, HeadsUpEntryPhone>) ((ArrayMap) mHeadsUpEntryMap);
- }
-
- @Nullable
- private HeadsUpEntryPhone getHeadsUpEntryPhone(@NonNull String key) {
- return (HeadsUpEntryPhone) mHeadsUpEntryMap.get(key);
- }
-
- @Nullable
- private HeadsUpEntryPhone getTopHeadsUpEntryPhone() {
- if (SceneContainerFlag.isEnabled()) {
- return (HeadsUpEntryPhone) mTopHeadsUpRow.getValue();
- } else {
- return (HeadsUpEntryPhone) getTopHeadsUpEntry();
- }
- }
-
- @Override
- public boolean canRemoveImmediately(@NonNull String key) {
- if (mSwipedOutKeys.contains(key)) {
- // We always instantly dismiss views being manually swiped out.
- mSwipedOutKeys.remove(key);
- return true;
- }
-
- HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(key);
- HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
-
- return headsUpEntry == null || headsUpEntry != topEntry || super.canRemoveImmediately(key);
- }
-
- @Override
- @NonNull
- public Flow<HeadsUpRowRepository> getTopHeadsUpRow() {
- return mTopHeadsUpRow;
- }
-
- @Override
- @NonNull
- public Flow<Set<HeadsUpRowRepository>> getActiveHeadsUpRows() {
- return mHeadsUpNotificationRows;
- }
-
- @Override
- @NonNull
- public StateFlow<Boolean> isHeadsUpAnimatingAway() {
- return mHeadsUpAnimatingAway;
- }
-
- @Override
- public boolean isHeadsUpAnimatingAwayValue() {
- return mHeadsUpAnimatingAway.getValue();
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // HeadsUpEntryPhone:
-
- protected class HeadsUpEntryPhone extends BaseHeadsUpManager.HeadsUpEntry implements
- HeadsUpRowRepository {
-
- private boolean mGutsShownPinned;
- private final MutableStateFlow<Boolean> mIsPinned = StateFlowKt.MutableStateFlow(false);
-
- /**
- * If the time this entry has been on was extended
- */
- private boolean extended;
-
- @Override
- public boolean isSticky() {
- return super.isSticky() || mGutsShownPinned;
- }
-
- public HeadsUpEntryPhone() {
- super();
- }
-
- public HeadsUpEntryPhone(NotificationEntry entry) {
- super(entry);
- }
-
- @Override
- @NonNull
- public String getKey() {
- return requireEntry().getKey();
- }
-
- @Override
- @NonNull
- public StateFlow<Boolean> isPinned() {
- return mIsPinned;
- }
-
- @Override
- protected void setRowPinned(boolean pinned) {
- // TODO(b/327624082): replace this super call with a ViewBinder
- super.setRowPinned(pinned);
- mIsPinned.setValue(pinned);
- }
-
- @Override
- protected void setEntry(@androidx.annotation.NonNull NotificationEntry entry,
- @androidx.annotation.Nullable Runnable removeRunnable) {
- super.setEntry(entry, removeRunnable);
-
- if (NotificationThrottleHun.isEnabled()) {
- mEntriesToRemoveWhenReorderingAllowed.add(entry);
- if (!mVisualStabilityProvider.isReorderingAllowed()) {
- entry.setSeenInShade(true);
- }
- }
- }
-
- @Override
- protected Runnable createRemoveRunnable(NotificationEntry entry) {
- return () -> {
- if (!NotificationThrottleHun.isEnabled()
- && !mVisualStabilityProvider.isReorderingAllowed()
- // We don't want to allow reordering while pulsing, but headsup need to
- // time out anyway
- && !entry.showingPulsing()) {
- mEntriesToRemoveWhenReorderingAllowed.add(entry);
- mVisualStabilityProvider.addTemporaryReorderingAllowedListener(
- mOnReorderingAllowedListener);
- } else if (mTrackingHeadsUp) {
- mEntriesToRemoveAfterExpand.add(entry);
- mLogger.logRemoveEntryAfterExpand(entry);
- } else if (mVisualStabilityProvider.isReorderingAllowed()
- || entry.showingPulsing()) {
- removeEntry(entry.getKey(), "createRemoveRunnable");
- }
- };
- }
-
- @Override
- public void updateEntry(boolean updatePostTime, String reason) {
- super.updateEntry(updatePostTime, reason);
-
- if (mEntriesToRemoveAfterExpand.contains(mEntry)) {
- mEntriesToRemoveAfterExpand.remove(mEntry);
- }
- if (!NotificationThrottleHun.isEnabled()) {
- if (mEntriesToRemoveWhenReorderingAllowed.contains(mEntry)) {
- mEntriesToRemoveWhenReorderingAllowed.remove(mEntry);
- }
- }
- }
-
- @Override
- public void setExpanded(boolean expanded) {
- if (this.mExpanded == expanded) {
- return;
- }
-
- this.mExpanded = expanded;
- if (expanded) {
- cancelAutoRemovalCallbacks("setExpanded(true)");
- } else {
- updateEntry(false /* updatePostTime */, "setExpanded(false)");
- }
- }
-
- public void setGutsShownPinned(boolean gutsShownPinned) {
- if (mGutsShownPinned == gutsShownPinned) {
- return;
- }
-
- mGutsShownPinned = gutsShownPinned;
- if (gutsShownPinned) {
- cancelAutoRemovalCallbacks("setGutsShownPinned(true)");
- } else {
- updateEntry(false /* updatePostTime */, "setGutsShownPinned(false)");
- }
- }
-
- @Override
- public void reset() {
- super.reset();
- mGutsShownPinned = false;
- extended = false;
- }
-
- private void extendPulse() {
- if (!extended) {
- extended = true;
- updateEntry(false, "extendPulse()");
- }
- }
-
- @Override
- protected long calculateFinishTime() {
- return super.calculateFinishTime() + (extended ? mExtensionTime : 0);
- }
-
- @Override
- @NonNull
- public Object getElementKey() {
- return requireEntry().getRow();
- }
-
- private NotificationEntry requireEntry() {
- /* check if */ SceneContainerFlag.isUnexpectedlyInLegacyMode();
- return Objects.requireNonNull(mEntry);
- }
- }
-
- private final StateListener mStatusBarStateListener = new StateListener() {
- @Override
- public void onStateChanged(int newState) {
- boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
- boolean isKeyguard = newState == StatusBarState.KEYGUARD;
- mStatusBarState = newState;
-
- if (wasKeyguard && !isKeyguard && mBypassController.getBypassEnabled()) {
- ArrayList<String> keysToRemove = new ArrayList<>();
- for (HeadsUpEntry entry : getHeadsUpEntryList()) {
- if (entry.mEntry != null && entry.mEntry.isBubble() && !entry.isSticky()) {
- keysToRemove.add(entry.mEntry.getKey());
- }
- }
- for (String key : keysToRemove) {
- removeEntry(key, "mStatusBarStateListener");
- }
- }
- }
-
- @Override
- public void onDozingChanged(boolean isDozing) {
- if (!isDozing) {
- // Let's make sure all huns we got while dozing time out within the normal timeout
- // duration. Otherwise they could get stuck for a very long time
- for (HeadsUpEntry entry : getHeadsUpEntryList()) {
- entry.updateEntry(true /* updatePostTime */, "onDozingChanged(false)");
- }
- }
- }
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index e74ed8d27ec2..c487ff5d35bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -49,6 +49,7 @@ import android.os.SystemClock;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import android.util.Log;
import android.view.ContentInfo;
import androidx.annotation.NonNull;
@@ -65,6 +66,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.icon.IconPack;
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
@@ -194,6 +196,10 @@ public final class NotificationEntry extends ListEntry {
*/
private boolean mIsDemoted = false;
+ // TODO(b/377565433): Move into NotificationContentModel during/after
+ // NotificationRowContentBinderRefactor.
+ private PromotedNotificationContentModel mPromotedNotificationContentModel;
+
/**
* True if both
* 1) app provided full screen intent but does not have the permission to send it
@@ -1061,6 +1067,32 @@ public final class NotificationEntry extends ListEntry {
this.mHeadsUpStatusBarTextPublic.setValue(headsUpStatusBarModel.getPublicText());
}
+ /**
+ * Gets the content needed to render this notification as a promoted notification on various
+ * surfaces (like status bar chips and AOD).
+ */
+ public PromotedNotificationContentModel getPromotedNotificationContentModel() {
+ if (PromotedNotificationContentModel.featureFlagEnabled()) {
+ return mPromotedNotificationContentModel;
+ } else {
+ Log.wtf(TAG, "getting promoted content without feature flag enabled");
+ return null;
+ }
+ }
+
+ /**
+ * Sets the content needed to render this notification as a promoted notification on various
+ * surfaces (like status bar chips and AOD).
+ */
+ public void setPromotedNotificationContentModel(
+ @Nullable PromotedNotificationContentModel promotedNotificationContentModel) {
+ if (PromotedNotificationContentModel.featureFlagEnabled()) {
+ this.mPromotedNotificationContentModel = promotedNotificationContentModel;
+ } else {
+ Log.wtf(TAG, "setting promoted content without feature flag enabled");
+ }
+ }
+
/** Information about a suggestion that is being edited. */
public static class EditedSuggestionInfo {
@@ -1101,4 +1133,6 @@ public final class NotificationEntry extends ListEntry {
private static final long INITIALIZATION_DELAY = 400;
private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
private static final int COLOR_INVALID = 1;
+
+ private static final String TAG = "NotificationEntry";
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
index 47a04291dd49..733b986b5422 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
@@ -20,13 +20,21 @@ import static android.app.NotificationManager.IMPORTANCE_MIN;
import android.app.Notification;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
+import com.google.common.primitives.Booleans;
+
import javax.inject.Inject;
/**
@@ -44,12 +52,21 @@ public class ColorizedFgsCoordinator implements Coordinator {
@Override
public void attach(NotifPipeline pipeline) {
+ if (PromotedNotificationUi.isEnabled()) {
+ pipeline.addPromoter(mPromotedOngoingPromoter);
+ }
}
public NotifSectioner getSectioner() {
return mNotifSectioner;
}
+ private final NotifPromoter mPromotedOngoingPromoter = new NotifPromoter("PromotedOngoing") {
+ @Override
+ public boolean shouldPromoteToTopLevel(NotificationEntry child) {
+ return isPromotedOngoing(child);
+ }
+ };
/**
* Puts colorized foreground service and call notifications into its own section.
@@ -64,11 +81,30 @@ public class ColorizedFgsCoordinator implements Coordinator {
}
return false;
}
+
+ private NotifComparator mPreferPromoted = new NotifComparator("PreferPromoted") {
+ @Override
+ public int compare(@NonNull ListEntry o1, @NonNull ListEntry o2) {
+ return -1 * Booleans.compare(
+ isPromotedOngoing(o1.getRepresentativeEntry()),
+ isPromotedOngoing(o2.getRepresentativeEntry()));
+ }
+ };
+
+ @Nullable
+ @Override
+ public NotifComparator getComparator() {
+ if (PromotedNotificationUi.isEnabled()) {
+ return mPreferPromoted;
+ } else {
+ return null;
+ }
+ }
};
/** Determines if the given notification is a colorized or call notification */
public static boolean isRichOngoing(NotificationEntry entry) {
- return isColorizedForegroundService(entry) || isCall(entry);
+ return isPromotedOngoing(entry) || isColorizedForegroundService(entry) || isCall(entry);
}
private static boolean isColorizedForegroundService(NotificationEntry entry) {
@@ -78,6 +114,11 @@ public class ColorizedFgsCoordinator implements Coordinator {
&& entry.getImportance() > IMPORTANCE_MIN;
}
+ private static boolean isPromotedOngoing(NotificationEntry entry) {
+ // NOTE: isPromotedOngoing already checks the android.app.ui_rich_ongoing flag.
+ return entry != null && entry.getSbn().getNotification().isPromotedOngoing();
+ }
+
private static boolean isCall(NotificationEntry entry) {
Notification notification = entry.getSbn().getNotification();
return entry.getImportance() > IMPORTANCE_MIN
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
index dc8ff63865a2..90212ed5b5f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
@@ -27,13 +27,13 @@ import com.android.systemui.statusbar.notification.collection.render.requireSumm
import javax.inject.Inject
/**
- * A small coordinator which updates the notif stack (the view layer which holds notifications)
- * with high-level data after the stack is populated with the final entries.
+ * A small coordinator which updates the notif stack (the view layer which holds notifications) with
+ * high-level data after the stack is populated with the final entries.
*/
@CoordinatorScope
-class DataStoreCoordinator @Inject internal constructor(
- private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl
-) : CoreCoordinator {
+class DataStoreCoordinator
+@Inject
+internal constructor(private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl) : CoreCoordinator {
override fun attach(pipeline: NotifPipeline) {
pipeline.addOnAfterRenderListListener { entries, _ -> onAfterRenderList(entries) }
@@ -61,4 +61,4 @@ class DataStoreCoordinator @Inject internal constructor(
}
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index e9292f8c3cb8..32de65be5b5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -43,8 +43,7 @@ internal constructor(
private val groupExpansionManagerImpl: GroupExpansionManagerImpl,
private val renderListInteractor: RenderNotificationListInteractor,
private val activeNotificationsInteractor: ActiveNotificationsInteractor,
- private val sensitiveNotificationProtectionController:
- SensitiveNotificationProtectionController,
+ private val sensitiveNotificationProtectionController: SensitiveNotificationProtectionController,
) : Coordinator {
override fun attach(pipeline: NotifPipeline) {
@@ -52,7 +51,7 @@ internal constructor(
groupExpansionManagerImpl.attach(pipeline)
}
- fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
+ private fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
traceSection("StackCoordinator.onAfterRenderList") {
val notifStats = calculateNotifStats(entries)
if (FooterViewRefactor.isEnabled) {
@@ -78,13 +77,13 @@ internal constructor(
val isSilent = section.bucket == BUCKET_SILENT
// NOTE: NotificationEntry.isClearable will internally check group children to ensure
// the group itself definitively clearable.
- val isClearable = !isSensitiveContentProtectionActive && entry.isClearable
- && !entry.isSensitive.value
+ val isClearable =
+ !isSensitiveContentProtectionActive && entry.isClearable && !entry.isSensitive.value
when {
isSilent && isClearable -> hasClearableSilentNotifs = true
isSilent && !isClearable -> hasNonClearableSilentNotifs = true
!isSilent && isClearable -> hasClearableAlertingNotifs = true
- !isSilent && !isClearable -> hasNonClearableAlertingNotifs = true
+ else -> hasNonClearableAlertingNotifs = true
}
}
return NotifStats(
@@ -92,7 +91,7 @@ internal constructor(
hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs,
hasClearableAlertingNotifs = hasClearableAlertingNotifs,
hasNonClearableSilentNotifs = hasNonClearableSilentNotifs,
- hasClearableSilentNotifs = hasClearableSilentNotifs
+ hasClearableSilentNotifs = hasClearableSilentNotifs,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
index 1ea574b2f386..410b78b9d3bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
@@ -21,15 +21,15 @@ import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
/**
- * This interface and the interfaces it returns define the main API surface that must be
- * implemented by the view implementation. The term "render" is used to indicate a handoff
- * to the view system, whether that be to attach views to the hierarchy or to update independent
- * view models, data stores, or adapters.
+ * This interface and the interfaces it returns define the main API surface that must be implemented
+ * by the view implementation. The term "render" is used to indicate a handoff to the view system,
+ * whether that be to attach views to the hierarchy or to update independent view models, data
+ * stores, or adapters.
*/
interface NotifViewRenderer {
/**
- * Hand off the list of notifications to the view implementation. This may attach views to the
+ * Hand off the list of notifications to the view implementation. This may attach views to the
* hierarchy or simply update an independent datastore, but once called, the implementer myst
* also ensure that future calls to [getStackController], [getGroupController], and
* [getRowController] will provide valid results.
@@ -37,21 +37,21 @@ interface NotifViewRenderer {
fun onRenderList(notifList: List<ListEntry>)
/**
- * Provides an interface for the pipeline to update the overall shade.
- * This will be called at most once for each time [onRenderList] is called.
+ * Provides an interface for the pipeline to update the overall shade. This will be called at
+ * most once for each time [onRenderList] is called.
*/
fun getStackController(): NotifStackController
/**
- * Provides an interface for the pipeline to update individual groups.
- * This will be called at most once for each group in the most recent call to [onRenderList].
+ * Provides an interface for the pipeline to update individual groups. This will be called at
+ * most once for each group in the most recent call to [onRenderList].
*/
fun getGroupController(group: GroupEntry): NotifGroupController
/**
- * Provides an interface for the pipeline to update individual entries.
- * This will be called at most once for each entry in the most recent call to [onRenderList].
- * This includes top level entries, group summaries, and group children.
+ * Provides an interface for the pipeline to update individual entries. This will be called at
+ * most once for each entry in the most recent call to [onRenderList]. This includes top level
+ * entries, group summaries, and group children.
*/
fun getRowController(entry: NotificationEntry): NotifRowController
@@ -62,8 +62,8 @@ interface NotifViewRenderer {
* logic now that all data from the pipeline is known to have been set for this execution.
*
* When this is called, the view system can expect that no more calls will be made to the
- * getters on this interface until after the next call to [onRenderList]. Additionally, there
+ * getters on this interface until after the next call to [onRenderList]. Additionally, there
* should be no further calls made on the objects previously returned by those getters.
*/
fun onDispatchComplete() {}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
index 9b5521018f97..9d3b098fa966 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.render
+import com.android.app.tracing.traceSection
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -26,7 +27,6 @@ import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderGroupListener
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
-import com.android.app.tracing.traceSection
import javax.inject.Inject
/**
@@ -77,16 +77,17 @@ class RenderStageManager @Inject constructor() : PipelineDumpable {
onAfterRenderEntryListeners.add(listener)
}
- override fun dumpPipeline(d: PipelineDumper) = with(d) {
- dump("viewRenderer", viewRenderer)
- dump("onAfterRenderListListeners", onAfterRenderListListeners)
- dump("onAfterRenderGroupListeners", onAfterRenderGroupListeners)
- dump("onAfterRenderEntryListeners", onAfterRenderEntryListeners)
- }
+ override fun dumpPipeline(d: PipelineDumper) =
+ with(d) {
+ dump("viewRenderer", viewRenderer)
+ dump("onAfterRenderListListeners", onAfterRenderListListeners)
+ dump("onAfterRenderGroupListeners", onAfterRenderGroupListeners)
+ dump("onAfterRenderEntryListeners", onAfterRenderEntryListeners)
+ }
private fun dispatchOnAfterRenderList(
viewRenderer: NotifViewRenderer,
- entries: List<ListEntry>
+ entries: List<ListEntry>,
) {
traceSection("RenderStageManager.dispatchOnAfterRenderList") {
val stackController = viewRenderer.getStackController()
@@ -98,7 +99,7 @@ class RenderStageManager @Inject constructor() : PipelineDumpable {
private fun dispatchOnAfterRenderGroups(
viewRenderer: NotifViewRenderer,
- entries: List<ListEntry>
+ entries: List<ListEntry>,
) {
traceSection("RenderStageManager.dispatchOnAfterRenderGroups") {
if (onAfterRenderGroupListeners.isEmpty()) {
@@ -115,7 +116,7 @@ class RenderStageManager @Inject constructor() : PipelineDumpable {
private fun dispatchOnAfterRenderEntries(
viewRenderer: NotifViewRenderer,
- entries: List<ListEntry>
+ entries: List<ListEntry>,
) {
traceSection("RenderStageManager.dispatchOnAfterRenderEntries") {
if (onAfterRenderEntryListeners.isEmpty()) {
@@ -131,8 +132,8 @@ class RenderStageManager @Inject constructor() : PipelineDumpable {
}
/**
- * Performs a forward, depth-first traversal of the list where the group's summary
- * immediately precedes the group's children.
+ * Performs a forward, depth-first traversal of the list where the group's summary immediately
+ * precedes the group's children.
*/
private inline fun List<ListEntry>.forEachNotificationEntry(
action: (NotificationEntry) -> Unit
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 684ce48d9c7f..42aadd132cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.notification.interruption.VisualInterrupti
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
+import com.android.systemui.statusbar.notification.logging.dagger.NotificationsLogModule;
import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactory;
import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactoryLooperImpl;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -116,6 +117,7 @@ import javax.inject.Provider;
ActivatableNotificationViewModelModule.class,
NotificationMemoryModule.class,
NotificationStatsLoggerModule.class,
+ NotificationsLogModule.class,
})
public interface NotificationsModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
index 63c9e8be9ead..cf4fb25f638e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -16,16 +16,11 @@
package com.android.systemui.statusbar.notification.data
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager
import dagger.Binds
import dagger.Module
-@Module(
- includes =
- [
- NotificationSettingsRepositoryModule::class,
- ]
-)
+@Module(includes = [NotificationSettingsRepositoryModule::class])
interface NotificationDataLayerModule {
- @Binds fun bindHeadsUpNotificationRepository(impl: HeadsUpManagerPhone): HeadsUpRepository
+ @Binds fun bindHeadsUpNotificationRepository(impl: BaseHeadsUpManager): HeadsUpRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
index 45d1034f2cfb..2b9e49372a63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
@@ -66,7 +66,7 @@ data class ActiveNotificationsStore(
* Map of notification key to rank, where rank is the 0-based index of the notification on the
* system server, meaning that in the unfiltered flattened list of notification entries.
*/
- val rankingsMap: Map<String, Int> = emptyMap()
+ val rankingsMap: Map<String, Int> = emptyMap(),
) {
operator fun get(key: Key): ActiveNotificationEntryModel? {
return when (key) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt
index 8079ce540e1b..4ea597a12ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt
@@ -17,17 +17,15 @@
package com.android.systemui.statusbar.notification.domain.interactor
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
import javax.inject.Inject
/** Interactor for notification alerting. */
@SysUISingleton
class NotificationAlertsInteractor
@Inject
-constructor(
- private val disableFlagsRepository: DisableFlagsRepository,
-) {
+constructor(private val disableFlagsInteractor: DisableFlagsInteractor) {
/** Returns true if notification alerts are allowed. */
fun areNotificationAlertsEnabled(): Boolean =
- disableFlagsRepository.disableFlags.value.areNotificationAlertsEnabled()
+ disableFlagsInteractor.disableFlags.value.areNotificationAlertsEnabled()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
index 23da90d426c7..8bd7a1ab7a77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
@@ -34,6 +34,7 @@ import com.android.systemui.statusbar.notification.collection.provider.SectionSt
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsProvider
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationEntryModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
@@ -151,6 +152,13 @@ private class ActiveNotificationsStoreBuilder(
} else {
null
}
+ val promotedContent =
+ if (PromotedNotificationContentModel.featureFlagEnabled()) {
+ promotedNotificationContentModel
+ } else {
+ null
+ }
+
return existingModels.createOrReuse(
key = key,
groupKey = sbn.groupKey,
@@ -173,6 +181,7 @@ private class ActiveNotificationsStoreBuilder(
isGroupSummary = sbn.notification.isGroupSummary,
bucket = bucket,
callType = sbn.toCallType(),
+ promotedContent = promotedContent,
)
}
}
@@ -199,6 +208,7 @@ private fun ActiveNotificationsStore.createOrReuse(
isGroupSummary: Boolean,
bucket: Int,
callType: CallType,
+ promotedContent: PromotedNotificationContentModel?,
): ActiveNotificationModel {
return individuals[key]?.takeIf {
it.isCurrent(
@@ -223,6 +233,7 @@ private fun ActiveNotificationsStore.createOrReuse(
contentIntent = contentIntent,
bucket = bucket,
callType = callType,
+ promotedContent = promotedContent,
)
}
?: ActiveNotificationModel(
@@ -247,6 +258,7 @@ private fun ActiveNotificationsStore.createOrReuse(
contentIntent = contentIntent,
bucket = bucket,
callType = callType,
+ promotedContent = promotedContent,
)
}
@@ -272,6 +284,7 @@ private fun ActiveNotificationModel.isCurrent(
isGroupSummary: Boolean,
bucket: Int,
callType: CallType,
+ promotedContent: PromotedNotificationContentModel?,
): Boolean {
return when {
key != this.key -> false
@@ -295,6 +308,9 @@ private fun ActiveNotificationModel.isCurrent(
contentIntent != this.contentIntent -> false
bucket != this.bucket -> false
callType != this.callType -> false
+ // QQQ: Do we need to do the same `isCurrent` thing within the content model to avoid
+ // recreating the active notification model constantly?
+ promotedContent != this.promotedContent -> false
else -> true
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
index 76e228bb54d2..2c5d9c2e449b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -38,6 +38,8 @@ interface NotificationsController {
)
fun resetUserExpandedStates()
+
fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption)
+
fun getActiveNotificationsCount(): Int
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 1677418c5c30..ea6a60bd7a1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -129,7 +129,7 @@ constructor(
} else {
notificationListener.snoozeNotification(
sbn.key,
- snoozeOption.minutesToSnoozeFor * 60 * 1000.toLong()
+ snoozeOption.minutesToSnoozeFor * 60 * 1000.toLong(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
index 65ba6de5b5cb..148b3f021643 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -28,9 +28,9 @@ import javax.inject.Inject
/**
* Implementation of [NotificationsController] that's used when notifications rendering is disabled.
*/
-class NotificationsControllerStub @Inject constructor(
- private val notificationListener: NotificationListener
-) : NotificationsController {
+class NotificationsControllerStub
+@Inject
+constructor(private val notificationListener: NotificationListener) : NotificationsController {
override fun initialize(
presenter: NotificationPresenter,
@@ -43,11 +43,9 @@ class NotificationsControllerStub @Inject constructor(
notificationListener.registerAsSystemService()
}
- override fun resetUserExpandedStates() {
- }
+ override fun resetUserExpandedStates() {}
- override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) {
- }
+ override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) {}
override fun getActiveNotificationsCount(): Int {
return 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt
new file mode 100644
index 000000000000..d3359d39e959
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2024 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.statusbar.notification.logging.dagger
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.log.dagger.NotifInteractionLog
+import com.android.systemui.log.dagger.NotificationHeadsUpLog
+import com.android.systemui.log.dagger.NotificationInterruptLog
+import com.android.systemui.log.dagger.NotificationLockscreenLog
+import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.log.dagger.NotificationRemoteInputLog
+import com.android.systemui.log.dagger.NotificationRenderLog
+import com.android.systemui.log.dagger.NotificationSectionLog
+import com.android.systemui.log.dagger.SensitiveNotificationProtectionLog
+import com.android.systemui.log.dagger.UnseenNotificationLog
+import com.android.systemui.log.dagger.VisualStabilityLog
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLog
+import com.android.systemui.util.Compile
+import dagger.Module
+import dagger.Provides
+
+@Module
+object NotificationsLogModule {
+ /** Provides a logging buffer for logs related to heads up presentation of notifications. */
+ @Provides
+ @SysUISingleton
+ @NotificationHeadsUpLog
+ fun provideNotificationHeadsUpLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifHeadsUpLog", 1000)
+ }
+
+ /** Provides a logging buffer for logs related to inflation of notifications. */
+ @Provides
+ @SysUISingleton
+ @NotifInflationLog
+ fun provideNotifInflationLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifInflationLog", 250)
+ }
+
+ /** Provides a logging buffer for all logs related to the data layer of notifications. */
+ @Provides
+ @SysUISingleton
+ @NotifInteractionLog
+ fun provideNotifInteractionLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifInteractionLog", 50)
+ }
+
+ /** Provides a logging buffer for notification interruption calculations. */
+ @Provides
+ @SysUISingleton
+ @NotificationInterruptLog
+ fun provideNotificationInterruptLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifInterruptLog", 100)
+ }
+
+ /** Provides a logging buffer for all logs related to notifications on the lockscreen. */
+ @Provides
+ @SysUISingleton
+ @NotificationLockscreenLog
+ fun provideNotificationLockScreenLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifLockscreenLog", 50, false /* systrace */)
+ }
+
+ /** Provides a logging buffer for all logs related to the data layer of notifications. */
+ @Provides
+ @SysUISingleton
+ @NotificationLog
+ fun provideNotificationsLogBuffer(
+ factory: LogBufferFactory,
+ notifPipelineFlags: NotifPipelineFlags,
+ ): LogBuffer {
+ var maxSize = 1000
+ if (Compile.IS_DEBUG && notifPipelineFlags.isDevLoggingEnabled()) {
+ maxSize *= 10
+ }
+ return factory.create("NotifLog", maxSize, Compile.IS_DEBUG /* systrace */)
+ }
+
+ /** Provides a logging buffer for all logs related to remote input controller. */
+ @Provides
+ @SysUISingleton
+ @NotificationRemoteInputLog
+ fun provideNotificationRemoteInputLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifRemoteInputLog", 50, /* maxSize */ false /* systrace */)
+ }
+
+ /** Provides a logging buffer for notification rendering events. */
+ @Provides
+ @SysUISingleton
+ @NotificationRenderLog
+ fun provideNotificationRenderLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifRenderLog", 100)
+ }
+
+ /** Provides a logging buffer for all logs related to managing notification sections. */
+ @Provides
+ @SysUISingleton
+ @NotificationSectionLog
+ fun provideNotificationSectionLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("NotifSectionLog", 1000, /* maxSize */ false /* systrace */)
+ }
+
+ /** Provides a [LogBuffer] for use by promoted notifications. */
+ @Provides
+ @SysUISingleton
+ @PromotedNotificationLog
+ fun providesPromotedNotificationLog(factory: LogBufferFactory): LogBuffer {
+ return factory.create("PromotedNotifLog", 50)
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
+ @SensitiveNotificationProtectionLog
+ fun provideSensitiveNotificationProtectionLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("SensitiveNotificationProtectionLog", 10)
+ }
+
+ /** Provides a logging buffer for all logs related to unseen notifications. */
+ @Provides
+ @SysUISingleton
+ @UnseenNotificationLog
+ fun provideUnseenNotificationLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("UnseenNotifLog", 20, /* maxSize */ false /* systrace */)
+ }
+
+ /** Provides a logging buffer for all logs related to notification visual stability. */
+ @Provides
+ @SysUISingleton
+ @VisualStabilityLog
+ fun provideVisualStabilityLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("VisualStabilityLog", 50, /* maxSize */ false /* systrace */)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt
new file mode 100644
index 000000000000..f9d9c9771e67
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.statusbar.notification.promoted
+
+import javax.inject.Qualifier
+
+/** A [com.android.systemui.log.LogBuffer] for use by promoted notifications. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class PromotedNotificationLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
new file mode 100644
index 000000000000..41ee3b992c5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 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.statusbar.notification.promoted.shared.model
+
+import android.annotation.DrawableRes
+import android.graphics.drawable.Icon
+import com.android.internal.widget.NotificationProgressModel
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
+
+/**
+ * The content needed to render a promoted notification to surfaces besides the notification stack,
+ * like the skeleton view on AOD or the status bar chip.
+ */
+data class PromotedNotificationContentModel(
+ val key: String,
+
+ // for all styles:
+ val skeletonSmallIcon: Icon?, // TODO(b/377568176): Make into an IconModel.
+ val appName: CharSequence?,
+ val subText: CharSequence?,
+ val time: When?,
+ val lastAudiblyAlertedMs: Long,
+ @DrawableRes val profileBadgeResId: Int?,
+ val title: CharSequence?,
+ val text: CharSequence?,
+ val skeletonLargeIcon: Icon?, // TODO(b/377568176): Make into an IconModel.
+ val style: Style,
+
+ // for CallStyle:
+ val personIcon: Icon?, // TODO(b/377568176): Make into an IconModel.
+ val personName: CharSequence?,
+ val verificationIcon: Icon?, // TODO(b/377568176): Make into an IconModel.
+ val verificationText: CharSequence?,
+
+ // for ProgressStyle:
+ val progress: NotificationProgressModel?,
+) {
+ class Builder(val key: String) {
+ var skeletonSmallIcon: Icon? = null
+ var appName: CharSequence? = null
+ var subText: CharSequence? = null
+ var time: When? = null
+ var lastAudiblyAlertedMs: Long = 0L
+ @DrawableRes var profileBadgeResId: Int? = null
+ var title: CharSequence? = null
+ var text: CharSequence? = null
+ var skeletonLargeIcon: Icon? = null
+ var style: Style = Style.Ineligible
+
+ // for CallStyle:
+ var personIcon: Icon? = null
+ var personName: CharSequence? = null
+ var verificationIcon: Icon? = null
+ var verificationText: CharSequence? = null
+
+ // for ProgressStyle:
+ var progress: NotificationProgressModel? = null
+
+ fun build() =
+ PromotedNotificationContentModel(
+ key = key,
+ skeletonSmallIcon = skeletonSmallIcon,
+ appName = appName,
+ subText = subText,
+ time = time,
+ lastAudiblyAlertedMs = lastAudiblyAlertedMs,
+ profileBadgeResId = profileBadgeResId,
+ title = title,
+ text = text,
+ skeletonLargeIcon = skeletonLargeIcon,
+ style = style,
+ personIcon = personIcon,
+ personName = personName,
+ verificationIcon = verificationIcon,
+ verificationText = verificationText,
+ progress = progress,
+ )
+ }
+
+ /** The timestamp associated with a notification, along with the mode used to display it. */
+ data class When(val time: Long, val mode: Mode) {
+ /** The mode used to display a notification's `when` value. */
+ enum class Mode {
+ Absolute,
+ CountDown,
+ CountUp,
+ }
+ }
+
+ /** The promotion-eligible style of a notification, or [Style.Ineligible] if not. */
+ enum class Style {
+ BigPicture,
+ BigText,
+ Call,
+ Progress,
+ Ineligible,
+ }
+
+ companion object {
+ @JvmStatic
+ fun featureFlagEnabled(): Boolean =
+ PromotedNotificationUi.isEnabled || StatusBarNotifChips.isEnabled
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfo.java
new file mode 100644
index 000000000000..aad618d50067
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BundleNotificationInfo.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 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.statusbar.notification.row;
+
+import android.app.INotificationManager;
+import android.app.NotificationChannel;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.RemoteException;
+import android.service.notification.NotificationAssistantService;
+import android.service.notification.StatusBarNotification;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.util.List;
+
+/**
+ * The guts of a notification revealed when performing a long press.
+ */
+public class BundleNotificationInfo extends NotificationInfo {
+ private static final String TAG = "BundleNotifInfoGuts";
+
+ public BundleNotificationInfo(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void bindNotification(
+ PackageManager pm,
+ INotificationManager iNotificationManager,
+ OnUserInteractionCallback onUserInteractionCallback,
+ ChannelEditorDialogController channelEditorDialogController,
+ String pkg,
+ NotificationChannel notificationChannel,
+ NotificationEntry entry,
+ OnSettingsClickListener onSettingsClick,
+ OnAppSettingsClickListener onAppSettingsClick,
+ UiEventLogger uiEventLogger,
+ boolean isDeviceProvisioned,
+ boolean isNonblockable,
+ boolean wasShownHighPriority,
+ AssistantFeedbackController assistantFeedbackController,
+ MetricsLogger metricsLogger) throws RemoteException {
+ super.bindNotification(pm, iNotificationManager, onUserInteractionCallback,
+ channelEditorDialogController, pkg, notificationChannel, entry, onSettingsClick,
+ onAppSettingsClick, uiEventLogger, isDeviceProvisioned, isNonblockable,
+ wasShownHighPriority, assistantFeedbackController, metricsLogger);
+
+ // Additionally, bind the feedback button.
+ ComponentName assistant = iNotificationManager.getAllowedNotificationAssistant();
+ bindFeedback(entry.getSbn(), pm, assistant, onAppSettingsClick);
+ }
+
+ protected void bindFeedback(StatusBarNotification sbn, PackageManager pm,
+ ComponentName assistant,
+ NotificationInfo.OnAppSettingsClickListener appSettingsClickListener) {
+ View feedbackButton = findViewById(R.id.notification_guts_bundle_feedback);
+ // If the assistant component is null, don't show the feedback button and finish.
+ if (assistant == null) {
+ feedbackButton.setVisibility(GONE);
+ return;
+ }
+ // Otherwise we extract the assistant package name.
+ String assistantPkg = assistant.getPackageName();
+
+ feedbackButton.setOnClickListener(getBundleFeedbackClickListener(sbn, pm, assistantPkg,
+ appSettingsClickListener));
+ feedbackButton.setVisibility(feedbackButton.hasOnClickListeners() ? VISIBLE : GONE);
+ }
+
+ private OnClickListener getBundleFeedbackClickListener(StatusBarNotification sbn,
+ PackageManager pm, String assistantPkg,
+ NotificationInfo.OnAppSettingsClickListener appSettingsClickListener) {
+ Intent feedbackIntent = getBundleFeedbackIntent(pm, assistantPkg, sbn.getKey());
+ if (feedbackIntent != null) {
+ return ((View view) -> {
+ appSettingsClickListener.onClick(view, feedbackIntent);
+ });
+ }
+ return null;
+ }
+
+ private Intent getBundleFeedbackIntent(PackageManager pm, String packageName, String key) {
+ Intent intent = new Intent(
+ NotificationAssistantService.ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS)
+ .setPackage(packageName);
+ final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
+ intent,
+ PackageManager.MATCH_DEFAULT_ONLY
+ );
+ if (resolveInfos == null || resolveInfos.size() == 0 || resolveInfos.get(0) == null) {
+ return null;
+ }
+ final ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
+ intent.setClassName(activityInfo.packageName, activityInfo.name);
+ intent.putExtra(NotificationAssistantService.EXTRA_NOTIFICATION_KEY, key);
+ return intent;
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 383453b4f1d8..0480212e4d59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.row;
import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
import static com.android.systemui.statusbar.policy.RemoteInputView.FOCUS_ANIMATION_MIN_SCALE;
@@ -76,8 +77,8 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
+import com.android.systemui.Flags;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.flags.RefactorFlag;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
@@ -296,7 +297,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private static boolean shouldSimulateSlowMeasure() {
return Compile.IS_DEBUG && RefactorFlag.forView(
- Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE).isEnabled();
+ ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE).isEnabled();
}
private static final String SLOW_MEASURE_SIMULATE_DELAY_PROPERTY =
@@ -1444,6 +1445,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
items.add(NotificationMenuRow.createPartialConversationItem(mContext));
items.add(NotificationMenuRow.createInfoItem(mContext));
items.add(NotificationMenuRow.createSnoozeItem(mContext));
+ if (android.app.Flags.notificationClassificationUi()) {
+ items.add(NotificationMenuRow.createBundleItem(mContext));
+ }
mMenuRow.setMenuItems(items);
}
if (existed) {
@@ -1606,6 +1610,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mPrivateLayout.getSingleLineView();
}
+ /**
+ * Whether this row is displayed over the unoccluded lockscreen. Returns false on the
+ * locked shade.
+ */
public boolean isOnKeyguard() {
return mOnKeyguard;
}
@@ -1617,7 +1625,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
setDragController(null);
mGroupParentWhenDismissed = mNotificationParent;
mChildAfterViewWhenDismissed = null;
- mEntry.getIcons().getStatusBarIcon().setDismissed();
if (isChildInGroup()) {
List<ExpandableNotificationRow> notificationChildren =
mNotificationParent.getAttachedChildren();
@@ -1754,7 +1761,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
dismiss(fromAccessibility);
if (canEntryBeDismissed()) {
if (mOnUserInteractionCallback != null) {
- mOnUserInteractionCallback.registerFutureDismissal(mEntry, REASON_CANCEL).run();
+ if (Flags.notificationReentrantDismiss()) {
+ Runnable futureDismissal = mOnUserInteractionCallback.registerFutureDismissal(
+ mEntry, REASON_CANCEL);
+ post(futureDismissal);
+ } else {
+ mOnUserInteractionCallback.registerFutureDismissal(mEntry, REASON_CANCEL).run();
+ }
}
}
}
@@ -2061,7 +2074,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mColorUpdateLogger = colorUpdateLogger;
mDismissibilityProvider = dismissibilityProvider;
mFeatureFlags = featureFlags;
- setHapticFeedbackEnabled(!com.android.systemui.Flags.msdlFeedback());
+ setHapticFeedbackEnabled(!Flags.msdlFeedback());
}
private void initDimens() {
@@ -2889,7 +2902,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- void setOnKeyguard(boolean onKeyguard) {
+ /** @see #isOnKeyguard() */
+ public void setOnKeyguard(boolean onKeyguard) {
if (onKeyguard != mOnKeyguard) {
boolean wasAboveShelf = isAboveShelf();
final boolean wasExpanded = isExpanded();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index baad616cbf02..ffe1b6f88302 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -41,6 +41,7 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.FeedbackIcon;
@@ -378,15 +379,19 @@ public class ExpandableNotificationRowController implements NotifViewController
mView.getEntry().setInitializationTime(mClock.elapsedRealtime());
mPluginManager.addPluginListener(mView,
NotificationMenuRowPlugin.class, false /* Allow multiple */);
- mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
- mStatusBarStateController.addCallback(mStatusBarStateListener);
+ if (!SceneContainerFlag.isEnabled()) {
+ mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ }
mSettingsController.addCallback(BUBBLES_SETTING_URI, mSettingsListener);
}
@Override
public void onViewDetachedFromWindow(View v) {
mPluginManager.removePluginListener(mView);
- mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ if (!SceneContainerFlag.isEnabled()) {
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ }
mSettingsController.removeCallback(BUBBLES_SETTING_URI, mSettingsListener);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index 0738a03f8237..1ff0d9262476 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Flags;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Icon;
@@ -93,12 +94,22 @@ public class HybridConversationNotificationView extends HybridNotificationView {
}
mConversationSenderName = requireViewById(R.id.conversation_notification_sender);
applyTextColor(mConversationSenderName, mSecondaryTextColor);
- mFacePileSize = getResources()
- .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_size);
- mFacePileAvatarSize = getResources()
- .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_avatar_size);
- mSingleAvatarSize = getResources()
- .getDimensionPixelSize(R.dimen.conversation_single_line_avatar_size);
+ if (Flags.notificationsRedesignTemplates()) {
+ mFacePileSize = getResources()
+ .getDimensionPixelSize(R.dimen.notification_2025_single_line_face_pile_size);
+ mFacePileAvatarSize = getResources()
+ .getDimensionPixelSize(
+ R.dimen.notification_2025_single_line_face_pile_avatar_size);
+ mSingleAvatarSize = getResources()
+ .getDimensionPixelSize(R.dimen.notification_2025_single_line_avatar_size);
+ } else {
+ mFacePileSize = getResources()
+ .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_size);
+ mFacePileAvatarSize = getResources()
+ .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_avatar_size);
+ mSingleAvatarSize = getResources()
+ .getDimensionPixelSize(R.dimen.conversation_single_line_avatar_size);
+ }
mFacePileProtectionWidth = getResources().getDimensionPixelSize(
R.dimen.conversation_single_line_face_pile_protection_width);
mTransformationHelper.setCustomTransformation(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index 09c034978977..e5e559f1a5da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -63,9 +63,8 @@ public class HybridGroupManager {
private HybridNotificationView inflateHybridView(View contentView, ViewGroup parent) {
Trace.beginSection("HybridGroupManager#inflateHybridView");
LayoutInflater inflater = LayoutInflater.from(mContext);
- int layout = contentView instanceof ConversationLayout
- ? R.layout.hybrid_conversation_notification
- : R.layout.hybrid_notification;
+ int layout = HybridNotificationView.getLayoutResource(
+ /* isConversation = */ contentView instanceof ConversationLayout);
HybridNotificationView hybrid = (HybridNotificationView)
inflater.inflate(layout, parent, false);
parent.addView(hybrid);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
index da8c4dc08bf0..61f4e96bf99a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.row;
import static android.app.Notification.COLOR_INVALID;
import android.annotation.Nullable;
+import android.app.Flags;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
@@ -73,6 +74,25 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout
return mTextView;
}
+ /**
+ * Get layout resource for this view based on {@param isConversation}.
+ */
+ public static int getLayoutResource(boolean isConversation) {
+ if (Flags.notificationsRedesignTemplates()) {
+ if (isConversation) {
+ return R.layout.notification_2025_hybrid_conversation;
+ } else {
+ return R.layout.notification_2025_hybrid;
+ }
+ } else {
+ if (isConversation) {
+ return R.layout.hybrid_conversation_notification;
+ } else {
+ return R.layout.hybrid_notification;
+ }
+ }
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9166e7e9bed2..786d7d9ea0f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -573,8 +573,29 @@ public class NotificationContentView extends FrameLayout implements Notification
return;
}
- mUiEventLogger.log(
- NotificationCompactHeadsUpEvent.NOTIFICATION_COMPACT_HUN_SHOWN);
+ final StatusBarNotification containingRowSbn = getContainingRowSbn();
+ if (containingRowSbn == null) {
+ return;
+ }
+
+ mUiEventLogger.logWithInstanceId(
+ NotificationCompactHeadsUpEvent.NOTIFICATION_COMPACT_HUN_SHOWN,
+ containingRowSbn.getUid(),
+ containingRowSbn.getPackageName(),
+ containingRowSbn.getInstanceId());
+ }
+
+ @Nullable
+ private StatusBarNotification getContainingRowSbn() {
+ if (mContainingNotification == null) {
+ return null;
+ }
+ final NotificationEntry entry = mContainingNotification.getEntry();
+ if (entry == null) {
+ return null;
+ }
+
+ return entry.getSbn();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 9e9116bd70e7..5ff9bc61f3ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -19,6 +19,7 @@ import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+import android.annotation.FlaggedApi;
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.content.Context;
@@ -317,6 +318,9 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
(PartialConversationInfo) gutsView);
} else if (gutsView instanceof FeedbackInfo) {
initializeFeedbackInfo(row, (FeedbackInfo) gutsView);
+ } else if (android.app.Flags.notificationClassificationUi()
+ && gutsView instanceof BundleNotificationInfo) {
+ initializeBundleNotificationInfo(row, (BundleNotificationInfo) gutsView);
}
return true;
} catch (Exception e) {
@@ -420,6 +424,60 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
}
/**
+ * Sets up the {@link BundleNotificationInfo} inside the notification row's guts.
+ * @param row view to set up the guts for
+ * @param notificationInfoView view to set up/bind within {@code row}
+ */
+ @VisibleForTesting
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ void initializeBundleNotificationInfo(
+ final ExpandableNotificationRow row,
+ BundleNotificationInfo notificationInfoView) throws Exception {
+ NotificationGuts guts = row.getGuts();
+ StatusBarNotification sbn = row.getEntry().getSbn();
+ String packageName = sbn.getPackageName();
+ // Settings link is only valid for notifications that specify a non-system user
+ NotificationInfo.OnSettingsClickListener onSettingsClick = null;
+ UserHandle userHandle = sbn.getUser();
+ PackageManager pmUser = CentralSurfaces.getPackageManagerForUser(
+ mContext, userHandle.getIdentifier());
+ final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick =
+ (View v, Intent intent) -> {
+ mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_APP_NOTE_SETTINGS);
+ guts.resetFalsingCheck();
+ mNotificationActivityStarter.startNotificationGutsIntent(intent, sbn.getUid(),
+ row);
+ };
+
+ if (!userHandle.equals(UserHandle.ALL)
+ || mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
+ onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
+ mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
+ guts.resetFalsingCheck();
+ mOnSettingsClickListener.onSettingsClick(sbn.getKey());
+ startAppNotificationSettingsActivity(packageName, appUid, channel, row);
+ };
+ }
+
+ notificationInfoView.bindNotification(
+ pmUser,
+ mNotificationManager,
+ mOnUserInteractionCallback,
+ mChannelEditorDialogController,
+ packageName,
+ row.getEntry().getChannel(),
+ row.getEntry(),
+ onSettingsClick,
+ onAppSettingsClick,
+ mUiEventLogger,
+ mDeviceProvisionedController.isDeviceProvisioned(),
+ row.getIsNonblockable(),
+ mHighPriorityProvider.isHighPriority(row.getEntry()),
+ mAssistantFeedbackController,
+ mMetricsLogger);
+ }
+
+ /**
* Sets up the {@link PartialConversationInfo} inside the notification row's guts.
* @param row view to set up the guts for
* @param notificationInfoView view to set up/bind within {@code row}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index bdfbc4b53943..6e8ec9576f80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
import static android.view.HapticFeedbackConstants.CLOCK_TICK;
import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
@@ -261,7 +262,11 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
mFeedbackItem = createFeedbackItem(mContext);
NotificationEntry entry = mParent.getEntry();
int personNotifType = mPeopleNotificationIdentifier.getPeopleNotificationType(entry);
- if (personNotifType == PeopleNotificationIdentifier.TYPE_PERSON) {
+ if (android.app.Flags.notificationClassificationUi()
+ && SYSTEM_RESERVED_IDS.contains(entry.getChannel().getId())) {
+ // Bundled notification; create bundle-specific guts.
+ mInfoItem = createBundleItem(mContext);
+ } else if (personNotifType == PeopleNotificationIdentifier.TYPE_PERSON) {
mInfoItem = createPartialConversationItem(mContext);
} else if (personNotifType >= PeopleNotificationIdentifier.TYPE_FULL_PERSON) {
mInfoItem = createConversationItem(mContext);
@@ -677,6 +682,16 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
R.drawable.ic_settings);
}
+ static NotificationMenuItem createBundleItem(Context context) {
+ Resources res = context.getResources();
+ String infoDescription = res.getString(R.string.notification_menu_gear_description);
+ BundleNotificationInfo infoContent =
+ (BundleNotificationInfo) LayoutInflater.from(context).inflate(
+ R.layout.bundle_notification_info, null, false);
+ return new NotificationMenuItem(context, infoDescription, infoContent,
+ R.drawable.ic_settings);
+ }
+
static NotificationMenuItem createPartialConversationItem(Context context) {
Resources res = context.getResources();
String infoDescription = res.getString(R.string.notification_menu_gear_description);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 2dcb706234b8..d0c033bb10b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -834,6 +834,15 @@ constructor(
public?.let {
it.layoutInflaterFactory = provider.provide(row, FLAG_CONTENT_VIEW_PUBLIC)
}
+ if (android.app.Flags.notificationsRedesignAppIcons()) {
+ normalGroupHeader?.let {
+ it.layoutInflaterFactory = provider.provide(row, FLAG_GROUP_SUMMARY_HEADER)
+ }
+ minimizedGroupHeader?.let {
+ it.layoutInflaterFactory =
+ provider.provide(row, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER)
+ }
+ }
return this
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
index 4e26ae85100c..e702f10d7f50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -412,10 +412,7 @@ internal object SingleLineViewInflater {
traceSection("SingleLineViewInflater#inflateSingleLineView") {
val inflater = LayoutInflater.from(context)
- val layoutRes: Int =
- if (isConversation)
- com.android.systemui.res.R.layout.hybrid_conversation_notification
- else com.android.systemui.res.R.layout.hybrid_notification
+ val layoutRes: Int = HybridNotificationView.getLayoutResource(isConversation)
view = inflater.inflate(layoutRes, /* root= */ null) as HybridNotificationView
if (view == null) {
Log.wtf(TAG, "Single-line view inflation result is null for entry: ${entry.logKey}")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
index 19a92a2230ba..a2b71551eca8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
@@ -17,7 +17,9 @@ package com.android.systemui.statusbar.notification.shared
import android.app.PendingIntent
import android.graphics.drawable.Icon
+import android.util.Log
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.stack.PriorityBucket
/**
@@ -36,6 +38,7 @@ data class ActiveNotificationModel(
val groupKey: String?,
/** When this notification was posted. */
val whenTime: Long,
+ // TODO(b/377566661): Make isPromoted just check if promotedContent != null.
/** True if this notification should be promoted and false otherwise. */
val isPromoted: Boolean,
/** Is this entry in the ambient / minimized section (lowest priority)? */
@@ -78,7 +81,24 @@ data class ActiveNotificationModel(
@PriorityBucket val bucket: Int,
/** The call type set on the notification. */
val callType: CallType,
-) : ActiveNotificationEntryModel()
+ /**
+ * The content needed to render this as a promoted notification on various surfaces, or null if
+ * this notification cannot be rendered as a promoted notification.
+ */
+ val promotedContent: PromotedNotificationContentModel?,
+) : ActiveNotificationEntryModel() {
+ init {
+ if (!PromotedNotificationContentModel.featureFlagEnabled()) {
+ if (promotedContent != null) {
+ Log.wtf(TAG, "passing non-null promoted content without feature flag enabled")
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "ActiveNotificationEntryModel"
+ }
+}
/** Model for a group of notifications. */
data class ActiveNotificationGroupModel(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 5c9a0b939dc7..f85545ef95f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -100,6 +100,9 @@ public interface NotificationListContainer extends
*/
void addContainerViewAt(View v, int index);
+ /** Sets whether the notificatios are displayed on the unoccluded lockscreen. */
+ void setOnLockscreen(boolean isOnKeyguard);
+
/**
* Sets the maximum number of notifications to display.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 57af8ea19722..bddf6dffe7c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -575,6 +575,7 @@ public class NotificationStackScrollLayout
@Nullable private SplitShadeStateController mSplitShadeStateController = null;
private boolean mIsSmallLandscapeLockscreenEnabled = false;
private boolean mSuppressHeightUpdates;
+ private boolean mIsOnLockscreen;
/** Pass splitShadeStateController to view and update split shade */
public void passSplitShadeStateController(SplitShadeStateController splitShadeStateController) {
@@ -3228,9 +3229,12 @@ public class NotificationStackScrollLayout
private void onViewAddedInternal(ExpandableView child) {
updateHideSensitiveForChild(child);
child.setOnHeightChangedListener(mOnChildHeightChangedListener);
- if (child instanceof ExpandableNotificationRow) {
+ if (child instanceof ExpandableNotificationRow row) {
NotificationEntry entry = ((ExpandableNotificationRow) child).getEntry();
entry.addOnSensitivityChangedListener(mOnChildSensitivityChangedListener);
+ if (SceneContainerFlag.isEnabled()) {
+ row.setOnKeyguard(mIsOnLockscreen);
+ }
}
generateAddAnimation(child, false /* fromMoreCard */);
updateAnimationState(child);
@@ -4752,8 +4756,11 @@ public class NotificationStackScrollLayout
}
}
- void goToFullShade(long delay) {
- SceneContainerFlag.assertInLegacyMode();
+ /**
+ * Requests an animation for the next stack height update, to animate from the constrained stack
+ * displayed on the lock screen, to the scrollable stack displayed in the expanded shade.
+ */
+ public void animateGoToFullShade(long delay) {
mGoToFullShadeNeedsAnimation = true;
mGoToFullShadeDelay = delay;
mNeedsAnimation = true;
@@ -5356,12 +5363,38 @@ public class NotificationStackScrollLayout
shelf.bind(mAmbientState, this, mController.getNotificationRoundnessManager());
}
+ /**
+ * Whether the notifications are displayed over the unoccluded lockscreen. Returns false on the
+ * locked shade.
+ */
+ public boolean isOnLockscreen() {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return false;
+ return mIsOnLockscreen;
+ }
+
+ /** @see #isOnLockscreen() */
+ public void setOnLockscreen(boolean isOnLockscreen) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ if (mIsOnLockscreen != isOnLockscreen) {
+ mIsOnLockscreen = isOnLockscreen;
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof ExpandableNotificationRow childRow) {
+ childRow.setOnKeyguard(isOnLockscreen);
+ }
+ }
+ }
+ }
+
public void setMaxDisplayedNotifications(int maxDisplayedNotifications) {
if (mMaxDisplayedNotifications != maxDisplayedNotifications) {
mMaxDisplayedNotifications = maxDisplayedNotifications;
if (SceneContainerFlag.isEnabled()) {
updateIntrinsicStackHeight();
updateStackEndHeightAndStackHeight(mAmbientState.getExpansionFraction());
+ if (maxDisplayedNotifications == -1) {
+ animateGoToFullShade(0);
+ }
} else {
updateContentHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index dc1a191ce233..3d7501deafc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1222,7 +1222,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
public void goToFullShade(long delay) {
SceneContainerFlag.assertInLegacyMode();
- mView.goToFullShade(delay);
+ mView.animateGoToFullShade(delay);
}
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
@@ -1603,6 +1603,12 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
}
+ /** Sets whether the NSSL is displayed over the unoccluded Lockscreen. */
+ public void setOnLockscreen(boolean isOnLockscreen) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ mNotificationListContainer.setOnLockscreen(isOnLockscreen);
+ }
+
/**
* Set the maximum number of notifications that can currently be displayed
*/
@@ -2029,6 +2035,11 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
@Override
+ public void setOnLockscreen(boolean isOnLockscreen) {
+ mView.setOnLockscreen(isOnLockscreen);
+ }
+
+ @Override
public void setMaxDisplayedNotifications(int maxNotifications) {
mView.setMaxDisplayedNotifications(maxNotifications);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index 4a55dfaaf7ea..ea714608ea66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -118,8 +118,12 @@ constructor(
}
launch {
- viewModel.getMaxNotifications(calculateMaxNotifications).collect {
- controller.setMaxDisplayedNotifications(it)
+ viewModel.getLockscreenDisplayConfig(calculateMaxNotifications).collect {
+ (isOnLockscreen, maxNotifications) ->
+ if (SceneContainerFlag.isEnabled) {
+ controller.setOnLockscreen(isOnLockscreen)
+ }
+ controller.setMaxDisplayedNotifications(maxNotifications)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index fb60f266e188..a55a165d9b66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -718,9 +718,11 @@ constructor(
* When expanding or when the user is interacting with the shade, keep the count stable; do not
* emit a value.
*/
- fun getMaxNotifications(calculateSpace: (Float, Boolean) -> Int): Flow<Int> {
+ fun getLockscreenDisplayConfig(
+ calculateSpace: (Float, Boolean) -> Int
+ ): Flow<LockscreenDisplayConfig> {
val showLimitedNotifications = isOnLockscreenWithoutShade
- val showUnlimitedNotifications =
+ val showUnlimitedNotificationsAndIsOnLockScreen =
combine(
isOnLockscreen,
keyguardInteractor.statusBarState,
@@ -730,28 +732,42 @@ constructor(
)
.onStart { emit(false) },
) { isOnLockscreen, statusBarState, showAllNotifications ->
- statusBarState == SHADE_LOCKED || !isOnLockscreen || showAllNotifications
+ (statusBarState == SHADE_LOCKED || !isOnLockscreen || showAllNotifications) to
+ isOnLockscreen
}
+ @Suppress("UNCHECKED_CAST")
return combineTransform(
showLimitedNotifications,
- showUnlimitedNotifications,
+ showUnlimitedNotificationsAndIsOnLockScreen,
shadeInteractor.isUserInteracting,
availableHeight,
interactor.notificationStackChanged,
interactor.useExtraShelfSpace,
) { flows ->
val showLimitedNotifications = flows[0] as Boolean
- val showUnlimitedNotifications = flows[1] as Boolean
+ val (showUnlimitedNotifications, isOnLockscreen) =
+ flows[1] as Pair<Boolean, Boolean>
val isUserInteracting = flows[2] as Boolean
val availableHeight = flows[3] as Float
val useExtraShelfSpace = flows[5] as Boolean
if (!isUserInteracting) {
if (showLimitedNotifications) {
- emit(calculateSpace(availableHeight, useExtraShelfSpace))
+ emit(
+ LockscreenDisplayConfig(
+ isOnLockscreen = isOnLockscreen,
+ maxNotifications =
+ calculateSpace(availableHeight, useExtraShelfSpace),
+ )
+ )
} else if (showUnlimitedNotifications) {
- emit(-1)
+ emit(
+ LockscreenDisplayConfig(
+ isOnLockscreen = isOnLockscreen,
+ maxNotifications = -1,
+ )
+ )
}
}
}
@@ -775,9 +791,9 @@ constructor(
SceneContainerFlag.assertInLegacyMode()
return combine(
- getMaxNotifications(calculateMaxNotifications).map {
- val height = calculateHeight(it)
- if (it == 0) {
+ getLockscreenDisplayConfig(calculateMaxNotifications).map { (_, maxNotifications) ->
+ val height = calculateHeight(maxNotifications)
+ if (maxNotifications == 0) {
height - shelfHeight
} else {
height
@@ -815,4 +831,13 @@ constructor(
*/
data class FloatAtEnd(val width: Int) : HorizontalPosition
}
+
+ /**
+ * Data class representing a configuration for displaying Notifications on the Lockscreen.
+ *
+ * @param isOnLockscreen is the user on the lockscreen
+ * @param maxNotifications Limit for the max number of top-level Notifications to be displayed.
+ * A value of -1 indicates no limit.
+ */
+ data class LockscreenDisplayConfig(val isOnLockscreen: Boolean, val maxNotifications: Int)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt
new file mode 100644
index 000000000000..636e1c45bc81
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 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.statusbar.phone
+
+import android.content.Context
+import android.view.MotionEvent
+import com.android.systemui.statusbar.AutoHideUiElement
+import java.io.PrintWriter
+
+/**
+ * Controls the auto-hide behavior of system bars (status bar, navigation bar).
+ *
+ * This interface provides methods to manage the auto-hide schedule of system bars, allowing them to
+ * be shown or hidden.
+ */
+interface AutoHideController {
+ /**
+ * Sets a [AutoHideUiElement] status bar that should be controlled by the [AutoHideController].
+ */
+ fun setStatusBar(element: AutoHideUiElement)
+
+ /**
+ * Sets a [AutoHideUiElement] navigation bar that should be controlled by the
+ * [AutoHideController].
+ */
+ fun setNavigationBar(element: AutoHideUiElement)
+
+ /** Resumes the auto-hide behavior that was previously suspended. */
+ fun resumeSuspendedAutoHide()
+
+ /** Suspends the auto-hide behavior. */
+ fun suspendAutoHide()
+
+ /** Schedules or cancels auto hide behavior based on current system bar state. */
+ fun touchAutoHide()
+
+ /** Hides system bars on user touch if the interaction requires them to be hidden. */
+ fun checkUserAutoHide(event: MotionEvent)
+
+ /** Called when work should stop and resources should be released. */
+ fun stop()
+
+ /** Dumps the current state of the [AutoHideController] */
+ fun dump(pw: PrintWriter)
+
+ /** Injectable factory for creating a [AutoHideController]. */
+ interface Factory {
+ /** Create an [AutoHideController] */
+ fun create(context: Context): AutoHideController
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java
index 1358cfd3e8da..4fbfbb254064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -28,7 +28,6 @@ import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -36,9 +35,7 @@ import java.io.PrintWriter;
import javax.inject.Inject;
-/** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */
-@SysUISingleton
-public class AutoHideController {
+public class AutoHideControllerImpl implements AutoHideController {
private static final String TAG = "AutoHideController";
private static final int AUTO_HIDE_TIMEOUT_MS = 2250;
private static final int USER_AUTO_HIDE_TIMEOUT_MS = 350;
@@ -61,7 +58,7 @@ public class AutoHideController {
};
@Inject
- public AutoHideController(Context context,
+ public AutoHideControllerImpl(Context context,
@Main Handler handler,
IWindowManager iWindowManager) {
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -70,18 +67,12 @@ public class AutoHideController {
mDisplayId = context.getDisplayId();
}
- /**
- * Sets a {@link AutoHideUiElement} status bar that should be controlled by the
- * {@link AutoHideController}.
- */
+ @Override
public void setStatusBar(AutoHideUiElement element) {
mStatusBar = element;
}
- /**
- * Sets a {@link AutoHideUiElement} navigation bar that should be controlled by the
- * {@link AutoHideController}.
- */
+ @Override
public void setNavigationBar(AutoHideUiElement element) {
mNavigationBar = element;
}
@@ -102,6 +93,7 @@ public class AutoHideController {
}
}
+ @Override
public void resumeSuspendedAutoHide() {
if (mAutoHideSuspended) {
scheduleAutoHide();
@@ -112,6 +104,7 @@ public class AutoHideController {
}
}
+ @Override
public void suspendAutoHide() {
mHandler.removeCallbacks(mAutoHide);
Runnable checkBarModesRunnable = getCheckBarModesRunnable();
@@ -121,7 +114,7 @@ public class AutoHideController {
mAutoHideSuspended = isAnyTransientBarShown();
}
- /** Schedules or cancels auto hide behavior based on current system bar state. */
+ @Override
public void touchAutoHide() {
// update transient bar auto hide
if (isAnyTransientBarShown()) {
@@ -156,6 +149,7 @@ public class AutoHideController {
FLAG_CONTENT_CONTROLS);
}
+ @Override
public void checkUserAutoHide(MotionEvent event) {
boolean shouldHide = isAnyTransientBarShown()
&& event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
@@ -196,6 +190,12 @@ public class AutoHideController {
return false;
}
+ @Override
+ public void stop() {
+ mHandler.removeCallbacks(mAutoHide);
+ }
+
+ @Override
public void dump(@NonNull PrintWriter pw) {
pw.println("AutoHideController:");
pw.println("\tmAutoHideSuspended=" + mAutoHideSuspended);
@@ -205,10 +205,7 @@ public class AutoHideController {
pw.println("\tgetUserAutoHideTimeout=" + getUserAutoHideTimeout());
}
- /**
- * Injectable factory for creating a {@link AutoHideController}.
- */
- public static class Factory {
+ public static class Factory implements AutoHideController.Factory {
private final Handler mHandler;
private final IWindowManager mIWindowManager;
@@ -219,8 +216,9 @@ public class AutoHideController {
}
/** Create an {@link AutoHideController} */
+ @Override
public AutoHideController create(Context context) {
- return new AutoHideController(context, mHandler, mIWindowManager);
+ return new AutoHideControllerImpl(context, mHandler, mIWindowManager);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
new file mode 100644
index 000000000000..744f96918eef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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.statusbar.phone
+
+import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.data.repository.PerDisplayStore
+import com.android.systemui.display.data.repository.PerDisplayStoreImpl
+import com.android.systemui.display.data.repository.SingleDisplayStore
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+
+/** Provides per display instances of [AutoHideController] */
+interface AutoHideControllerStore : PerDisplayStore<AutoHideController>
+
+@SysUISingleton
+class MultiDisplayAutoHideControllerStore
+@Inject
+constructor(
+ @Background backgroundApplicationScope: CoroutineScope,
+ displayRepository: DisplayRepository,
+ private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+ private val autoHideControllerFactory: AutoHideControllerImpl.Factory,
+) :
+ AutoHideControllerStore,
+ PerDisplayStoreImpl<AutoHideController>(backgroundApplicationScope, displayRepository) {
+
+ init {
+ StatusBarConnectedDisplays.assertInNewMode()
+ }
+
+ override fun createInstanceForDisplay(displayId: Int): AutoHideController {
+ val displayWindowProperties =
+ displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+ return autoHideControllerFactory.create(displayWindowProperties.context)
+ }
+
+ override suspend fun onDisplayRemovalAction(instance: AutoHideController) {
+ instance.stop()
+ }
+
+ override val instanceClass = AutoHideController::class.java
+}
+
+@SysUISingleton
+class SingleDisplayAutoHideControllerStore
+@Inject
+constructor(defaultController: AutoHideController) :
+ AutoHideControllerStore,
+ PerDisplayStore<AutoHideController> by SingleDisplayStore(defaultController) {
+
+ init {
+ StatusBarConnectedDisplays.assertInLegacyMode()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 80c8e8b2a109..db294934c9ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -171,14 +171,12 @@ import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeLogger;
import com.android.systemui.shade.ShadeSurface;
import com.android.systemui.shade.ShadeViewController;
-import com.android.systemui.shade.StatusBarLongPressGestureDetector;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -368,7 +366,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private PhoneStatusBarViewController mPhoneStatusBarViewController;
private PhoneStatusBarTransitions mStatusBarTransitions;
- private final Provider<StatusBarLongPressGestureDetector> mStatusBarLongPressGestureDetector;
private final AuthRippleController mAuthRippleController;
@WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
private final NotificationShadeWindowController mNotificationShadeWindowController;
@@ -674,7 +671,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
ShadeController shadeController,
WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- Provider<StatusBarLongPressGestureDetector> statusBarLongPressGestureDetector,
ViewMediatorCallback viewMediatorCallback,
InitController initController,
@Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler,
@@ -782,7 +778,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mShadeController = shadeController;
mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
- mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector;
mKeyguardViewMediatorCallback = viewMediatorCallback;
mInitController = initController;
mPluginDependencyProvider = pluginDependencyProvider;
@@ -1532,11 +1527,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// to touch outside the customizer to close it, such as on the status or nav bar.
mShadeController.onStatusBarTouch(event);
}
- if (ShadeExpandsOnStatusBarLongPress.isEnabled()
- && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
- mStatusBarLongPressGestureDetector.get().handleTouch(event);
- }
-
return getNotificationShadeWindowView().onTouchEvent(event);
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
index 7919c84152b2..83551e9b8294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
@@ -17,12 +17,12 @@
package com.android.systemui.statusbar.phone
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Binds
import dagger.Module
@Module
interface HeadsUpModule {
- @Binds @SysUISingleton fun bindsHeadsUpManager(hum: HeadsUpManagerPhone): HeadsUpManager
+ @Binds @SysUISingleton fun bindsHeadsUpManager(hum: BaseHeadsUpManager): HeadsUpManager
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
index 7ef1e416aa19..5837a498e44f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
@@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -63,17 +64,21 @@ public class ManagedProfileControllerImpl implements ManagedProfileController {
@Override
public void addCallback(@NonNull Callback callback) {
- mCallbacks.add(callback);
- if (mCallbacks.size() == 1) {
- setListening(true);
+ synchronized (mCallbacks) {
+ mCallbacks.add(callback);
+ if (mCallbacks.size() == 1) {
+ setListening(true);
+ }
+ callback.onManagedProfileChanged();
}
- callback.onManagedProfileChanged();
}
@Override
public void removeCallback(@NonNull Callback callback) {
- if (mCallbacks.remove(callback) && mCallbacks.size() == 0) {
- setListening(false);
+ synchronized (mCallbacks) {
+ if (mCallbacks.remove(callback) && mCallbacks.size() == 0) {
+ setListening(false);
+ }
}
}
@@ -109,10 +114,7 @@ public class ManagedProfileControllerImpl implements ManagedProfileController {
}
private void notifyManagedProfileRemoved() {
- ArrayList<Callback> copy = new ArrayList<>(mCallbacks);
- for (Callback callback : copy) {
- callback.onManagedProfileRemoved();
- }
+ notifyCallbacks(Callback::onManagedProfileRemoved);
}
public boolean hasActiveProfile() {
@@ -136,6 +138,16 @@ public class ManagedProfileControllerImpl implements ManagedProfileController {
}
}
+ private void notifyCallbacks(Consumer<Callback> method) {
+ ArrayList<Callback> copy;
+ synchronized (mCallbacks) {
+ copy = new ArrayList<>(mCallbacks);
+ }
+ for (Callback callback : copy) {
+ method.accept(callback);
+ }
+ }
+
private void setListening(boolean listening) {
if (mListening == listening) {
return;
@@ -154,19 +166,13 @@ public class ManagedProfileControllerImpl implements ManagedProfileController {
@Override
public void onUserChanged(int newUser, @NonNull Context userContext) {
reloadManagedProfiles();
- ArrayList<Callback> copy = new ArrayList<>(mCallbacks);
- for (Callback callback : copy) {
- callback.onManagedProfileChanged();
- }
+ notifyCallbacks(Callback::onManagedProfileChanged);
}
@Override
public void onProfilesChanged(@NonNull List<UserInfo> profiles) {
reloadManagedProfiles();
- ArrayList<Callback> copy = new ArrayList<>(mCallbacks);
- for (Callback callback : copy) {
- callback.onManagedProfileChanged();
- }
+ notifyCallbacks(Callback::onManagedProfileChanged);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 0c511aeae3e5..aef26dea3c0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -520,6 +520,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mListenForCanShowAlternateBouncer.cancel(null);
}
mListenForCanShowAlternateBouncer = null;
+
// Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot.
mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
@@ -568,6 +569,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
private void consumeCanShowAlternateBouncer(boolean canShow) {
+ if (SceneContainerFlag.isEnabled()) {
+ // When the scene framework is enabled, the alternative bouncer is hidden from the scene
+ // framework logic so there's no need for this logic here.
+ return;
+ }
+
// Hack: this is required to fix issues where
// KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never
// reset. This is caused by usages of show()/forceShow() that only read this flow to set the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 58386b0cad7c..ee8c1ae6c5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -35,7 +35,12 @@ import com.android.systemui.statusbar.data.repository.PrivacyDotViewControllerSt
import com.android.systemui.statusbar.data.repository.PrivacyDotWindowControllerStoreModule
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
import com.android.systemui.statusbar.events.PrivacyDotViewControllerModule
+import com.android.systemui.statusbar.phone.AutoHideController
+import com.android.systemui.statusbar.phone.AutoHideControllerImpl
+import com.android.systemui.statusbar.phone.AutoHideControllerStore
import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks
+import com.android.systemui.statusbar.phone.MultiDisplayAutoHideControllerStore
+import com.android.systemui.statusbar.phone.SingleDisplayAutoHideControllerStore
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore
import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStoreImpl
@@ -75,6 +80,9 @@ interface StatusBarPhoneModule {
@Binds fun statusBarInitializer(@Default impl: StatusBarInitializerImpl): StatusBarInitializer
+ @Binds
+ fun autoHideControllerFactory(impl: AutoHideControllerImpl.Factory): AutoHideController.Factory
+
companion object {
/** Binds {@link StatusBarInitializer} as a {@link CoreStartable}. */
@Provides
@@ -186,5 +194,18 @@ interface StatusBarPhoneModule {
singleDisplayStoreLazy.get()
}
}
+
+ @Provides
+ @SysUISingleton
+ fun autoHideStore(
+ singleDisplayLazy: Lazy<SingleDisplayAutoHideControllerStore>,
+ multiDisplayLazy: Lazy<MultiDisplayAutoHideControllerStore>,
+ ): AutoHideControllerStore {
+ return if (StatusBarConnectedDisplays.isEnabled) {
+ multiDisplayLazy.get()
+ } else {
+ singleDisplayLazy.get()
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
index 13ac321473f4..f3d513940bcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
@@ -113,34 +113,38 @@ constructor(
}
private val showIcon =
- canShowIcon
- .flatMapLatest { canShow ->
- if (!canShow) {
- flowOf(false)
- } else {
- combine(
- shouldShowIconForOosAfterHysteresis,
- interactor.connectionState,
- interactor.isWifiActive,
- airplaneModeRepository.isAirplaneMode,
- ) { showForOos, connectionState, isWifiActive, isAirplaneMode ->
- if (isWifiActive || isAirplaneMode) {
- false
- } else {
- showForOos ||
- connectionState == SatelliteConnectionState.On ||
- connectionState == SatelliteConnectionState.Connected
+ if (interactor.isOpportunisticSatelliteIconEnabled) {
+ canShowIcon
+ .flatMapLatest { canShow ->
+ if (!canShow) {
+ flowOf(false)
+ } else {
+ combine(
+ shouldShowIconForOosAfterHysteresis,
+ interactor.connectionState,
+ interactor.isWifiActive,
+ airplaneModeRepository.isAirplaneMode,
+ ) { showForOos, connectionState, isWifiActive, isAirplaneMode ->
+ if (isWifiActive || isAirplaneMode) {
+ false
+ } else {
+ showForOos ||
+ connectionState == SatelliteConnectionState.On ||
+ connectionState == SatelliteConnectionState.Connected
+ }
}
}
}
+ .distinctUntilChanged()
+ .logDiffsForTable(
+ tableLog,
+ columnPrefix = "vm",
+ columnName = COL_VISIBLE,
+ initialValue = false,
+ )
+ } else {
+ flowOf(false)
}
- .distinctUntilChanged()
- .logDiffsForTable(
- tableLog,
- columnPrefix = "vm",
- columnName = COL_VISIBLE,
- initialValue = false,
- )
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val icon: StateFlow<Icon?> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
index 9164da721e3a..b2a0272c06d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.shared.domain.interactor
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
import com.android.systemui.statusbar.pipeline.shared.domain.model.StatusBarDisableFlagsVisibilityModel
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -30,13 +30,13 @@ import kotlinx.coroutines.flow.map
@SysUISingleton
class CollapsedStatusBarInteractor
@Inject
-constructor(disableFlagsRepository: DisableFlagsRepository) {
+constructor(DisableFlagsInteractor: DisableFlagsInteractor) {
/**
* The visibilities of various status bar child views, based only on the information we received
* from disable flags.
*/
val visibilityViaDisableFlags: Flow<StatusBarDisableFlagsVisibilityModel> =
- disableFlagsRepository.disableFlags.map {
+ DisableFlagsInteractor.disableFlags.map {
StatusBarDisableFlagsVisibilityModel(
isClockAllowed = it.isClockEnabled,
areNotificationIconsAllowed = it.areNotificationIconsEnabled,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index c7b6be3fc4ac..a72c83e9579c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -92,8 +92,7 @@ constructor(
private var wifiPickerTracker: WifiPickerTracker? = null
- @VisibleForTesting
- val selectedUserContext: Flow<Context> =
+ private val selectedUserContext: Flow<Context> =
userRepository.selectedUserInfo.map {
applicationContext.createContextAsUser(UserHandle.of(it.id), /* flags= */ 0)
}
@@ -112,8 +111,7 @@ constructor(
selectedUserContext
.flatMapLatest { currentContext
-> // flatMapLatest because when selectedUserContext emits a new value, we want
- // to
- // re-create a whole flow
+ // to re-create a whole flow
callbackFlow {
val callback =
object : WifiPickerTracker.WifiPickerTrackerCallback {
@@ -132,20 +130,16 @@ constructor(
.map { it.toWifiNetworkModel() }
// [WifiPickerTracker.connectedWifiEntry] will return the
- // same
- // instance but with updated internals. For example, when
- // its
- // validation status changes from false to true, the same
- // instance is re-used but with the validated field updated.
+ // same instance but with updated internals. For example,
+ // when its validation status changes from false to true,
+ // the same instance is re-used but with the validated
+ // field updated.
//
// Because it's the same instance, the flow won't re-emit
- // the
- // value (even though the internals have changed). So, we
- // need
- // to transform it into our internal model immediately.
- // [toWifiNetworkModel] always returns a new instance, so
- // the
- // flow is guaranteed to emit.
+ // the value (even though the internals have changed). So,
+ // we need to transform it into our internal model
+ // immediately. [toWifiNetworkModel] always returns a new
+ // instance, so the flow is guaranteed to emit.
send(
newPrimaryNetwork =
connectedEntry?.toPrimaryWifiNetworkModel()
@@ -235,20 +229,15 @@ constructor(
.map { it.toWifiNetworkModel() }
// [WifiPickerTracker.connectedWifiEntry] will return the same
- // instance
- // but with updated internals. For example, when its validation
- // status
- // changes from false to true, the same instance is re-used but
- // with the
- // validated field updated.
+ // instance but with updated internals. For example, when its
+ // validation status changes from false to true, the same
+ // instance is re-used but with the validated field updated.
//
// Because it's the same instance, the flow won't re-emit the
- // value
- // (even though the internals have changed). So, we need to
- // transform it
- // into our internal model immediately. [toWifiNetworkModel]
- // always
- // returns a new instance, so the flow is guaranteed to emit.
+ // value (even though the internals have changed). So, we need
+ // to transform it into our internal model immediately.
+ // [toWifiNetworkModel] always returns a new instance, so the
+ // flow is guaranteed to emit.
send(
newPrimaryNetwork =
connectedEntry?.toPrimaryWifiNetworkModel()
@@ -292,12 +281,10 @@ constructor(
.create(applicationContext, lifecycle, callback, "WifiRepository")
.apply {
// By default, [WifiPickerTracker] will scan to see all
- // available wifi
- // networks in the area. Because SysUI only needs to display the
- // **connected** network, we don't need scans to be running (and
- // in fact,
- // running scans is costly and should be avoided whenever
- // possible).
+ // available wifi networks in the area. Because SysUI only
+ // needs to display the **connected** network, we don't
+ // need scans to be running (and in fact, running scans is
+ // costly and should be avoided whenever possible).
this?.disableScanning()
}
// The lifecycle must be STARTED in order for the callback to receive
@@ -382,16 +369,11 @@ constructor(
private fun MergedCarrierEntry.convertCarrierMergedToModel(): WifiNetworkModel {
// WifiEntry instance values aren't guaranteed to be stable between method calls
- // because
- // WifiPickerTracker is continuously updating the same object. Save the level in a
- // local
- // variable so that checking the level validity here guarantees that the level will
- // still be
- // valid when we create the `WifiNetworkModel.Active` instance later. Otherwise, the
- // level
- // could be valid here but become invalid later, and `WifiNetworkModel.Active` will
- // throw
- // an exception. See b/362384551.
+ // because WifiPickerTracker is continuously updating the same object. Save the
+ // level in a local variable so that checking the level validity here guarantees
+ // that the level will still be valid when we create the `WifiNetworkModel.Active`
+ // instance later. Otherwise, the level could be valid here but become invalid
+ // later, and `WifiNetworkModel.Active` will throw an exception. See b/362384551.
return WifiNetworkModel.CarrierMerged.of(
subscriptionId = this.subscriptionId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index 4284c1911b33..298ef7ee4bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -16,33 +16,48 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Region;
import android.os.Handler;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pools;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.EventLogTags;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
+import com.android.systemui.statusbar.notification.collection.provider.OnReorderingBannedListener;
+import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
@@ -50,17 +65,30 @@ import org.jetbrains.annotations.NotNull;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Stack;
import java.util.stream.Stream;
+import javax.inject.Inject;
+
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlow;
+import kotlinx.coroutines.flow.StateFlowKt;
+
/**
* A manager which handles heads up notifications which is a special mode where
* they simply peek from the top of the screen.
*/
-public abstract class BaseHeadsUpManager implements HeadsUpManager {
+@SysUISingleton
+public class BaseHeadsUpManager
+ implements HeadsUpManager, HeadsUpRepository, OnHeadsUpChangedListener {
private static final String TAG = "BaseHeadsUpManager";
private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
-
+ private static final String REASON_REORDER_ALLOWED = "mOnReorderingAllowedListener";
protected final ListenerSet<OnHeadsUpChangedListener> mListeners = new ListenerSet<>();
protected final Context mContext;
@@ -74,7 +102,11 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
private final AccessibilityManagerWrapper mAccessibilityMgr;
private final UiEventLogger mUiEventLogger;
- private final AvalancheController mAvalancheController;
+ private AvalancheController mAvalancheController;
+ private final KeyguardBypassController mBypassController;
+ private final GroupMembershipManager mGroupMembershipManager;
+ private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
+ private final VisualStabilityProvider mVisualStabilityProvider;
protected final SystemClock mSystemClock;
protected final ArrayMap<String, HeadsUpEntry> mHeadsUpEntryMap = new ArrayMap<>();
@@ -84,6 +116,53 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
protected int mAutoDismissTime;
protected DelayableExecutor mExecutor;
+ @VisibleForTesting
+ public final int mExtensionTime;
+
+ // TODO(b/328393698) move the topHeadsUpRow logic to an interactor
+ private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
+ StateFlowKt.MutableStateFlow(null);
+ private final MutableStateFlow<Set<HeadsUpRowRepository>> mHeadsUpNotificationRows =
+ StateFlowKt.MutableStateFlow(new HashSet<>());
+ private final MutableStateFlow<Boolean> mHeadsUpAnimatingAway =
+ StateFlowKt.MutableStateFlow(false);
+ private final HashSet<String> mSwipedOutKeys = new HashSet<>();
+ private final HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
+ @VisibleForTesting
+ public final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
+ = new ArraySet<>();
+
+ private boolean mReleaseOnExpandFinish;
+ private boolean mTrackingHeadsUp;
+ private boolean mIsShadeOrQsExpanded;
+ private boolean mIsQsExpanded;
+ private int mStatusBarState;
+ private AnimationStateHandler mAnimationStateHandler;
+ private int mHeadsUpInset;
+
+ // Used for determining the region for touch interaction
+ private final Region mTouchableRegion = new Region();
+
+ private final Pools.Pool<HeadsUpEntry> mEntryPool = new Pools.Pool<>() {
+ private final Stack<HeadsUpEntry> mPoolObjects = new Stack<>();
+
+ @Override
+ public HeadsUpEntry acquire() {
+ NotificationThrottleHun.assertInLegacyMode();
+ if (!mPoolObjects.isEmpty()) {
+ return mPoolObjects.pop();
+ }
+ return new HeadsUpEntry();
+ }
+
+ @Override
+ public boolean release(@NonNull HeadsUpEntry instance) {
+ NotificationThrottleHun.assertInLegacyMode();
+ mPoolObjects.push(instance);
+ return true;
+ }
+ };
+
/**
* Enum entry for notification peek logged from this class.
*/
@@ -100,14 +179,23 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
}
- public BaseHeadsUpManager(@NonNull final Context context,
+ @Inject
+ public BaseHeadsUpManager(
+ @NonNull final Context context,
HeadsUpManagerLogger logger,
+ StatusBarStateController statusBarStateController,
+ KeyguardBypassController bypassController,
+ GroupMembershipManager groupMembershipManager,
+ VisualStabilityProvider visualStabilityProvider,
+ ConfigurationController configurationController,
@Main Handler handler,
GlobalSettings globalSettings,
SystemClock systemClock,
@Main DelayableExecutor executor,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger,
+ JavaAdapter javaAdapter,
+ ShadeInteractor shadeInteractor,
AvalancheController avalancheController) {
mLogger = logger;
mExecutor = executor;
@@ -117,12 +205,16 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
mUiEventLogger = uiEventLogger;
mAvalancheController = avalancheController;
mAvalancheController.setBaseEntryMapStr(this::getEntryMapStr);
+ mBypassController = bypassController;
+ mGroupMembershipManager = groupMembershipManager;
+ mVisualStabilityProvider = visualStabilityProvider;
Resources resources = context.getResources();
mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
? 500 : resources.getInteger(R.integer.heads_up_notification_minimum_time);
mStickyForSomeTimeAutoDismissTime = resources.getInteger(
R.integer.sticky_heads_up_notification_time);
mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
+ mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
mSnoozedPackages = new ArrayMap<>();
int defaultSnoozeLengthMs =
@@ -145,11 +237,38 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
globalSettings.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS),
/* notifyForDescendants = */ false,
settingsObserver);
+
+ statusBarStateController.addCallback(mStatusBarStateListener);
+ updateResources();
+ configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ updateResources();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ updateResources();
+ }
+ });
+ javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
+ this::onShadeOrQsExpanded);
+ if (SceneContainerFlag.isEnabled()) {
+ javaAdapter.alwaysCollectFlow(shadeInteractor.isQsExpanded(),
+ this::onQsExpanded);
+ }
+ if (NotificationThrottleHun.isEnabled()) {
+ mVisualStabilityProvider.addPersistentReorderingBannedListener(
+ mOnReorderingBannedListener);
+ mVisualStabilityProvider.addPersistentReorderingAllowedListener(
+ mOnReorderingAllowedListener);
+ }
}
/**
* Adds an OnHeadUpChangedListener to observe events.
*/
+ @Override
public void addListener(@NonNull OnHeadsUpChangedListener listener) {
mListeners.addIfAbsent(listener);
}
@@ -157,11 +276,31 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
/**
* Removes the OnHeadUpChangedListener from the observer list.
*/
+ @Override
public void removeListener(@NonNull OnHeadsUpChangedListener listener) {
mListeners.remove(listener);
}
/**
+ * Add a listener to receive callbacks {@link #setHeadsUpAnimatingAway(boolean)}
+ */
+ @Override
+ public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+ mHeadsUpPhoneListeners.add(listener);
+ }
+
+ @Override
+ public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+ mAnimationStateHandler = handler;
+ }
+
+ private void updateResources() {
+ Resources resources = mContext.getResources();
+ mHeadsUpInset = SystemBarUtils.getStatusBarHeight(mContext)
+ + resources.getDimensionPixelSize(R.dimen.heads_up_status_bar_padding);
+ }
+
+ /**
* Called when posting a new notification that should appear on screen.
* Adds the notification to be managed.
* @param entry entry to show
@@ -188,14 +327,24 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
mAvalancheController.update(headsUpEntry, runnable, "showNotification");
}
- /**
- * Try to remove the notification. May not succeed if the notification has not been shown long
- * enough and needs to be kept around.
- * @param key the key of the notification to remove
- * @param releaseImmediately force a remove regardless of earliest removal time
- * @param reason reason for removing the notification
- * @return true if notification is removed, false otherwise
- */
+ @Override
+ public boolean removeNotification(
+ @NonNull String key,
+ boolean releaseImmediately,
+ boolean animate,
+ @NonNull String reason) {
+ if (animate) {
+ return removeNotification(key, releaseImmediately,
+ "removeNotification(animate: true), reason: " + reason);
+ } else {
+ mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
+ final boolean removed = removeNotification(key, releaseImmediately,
+ "removeNotification(animate: false), reason: " + reason);
+ mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
+ return removed;
+ }
+ }
+
@Override
public boolean removeNotification(@NotNull String key, boolean releaseImmediately,
@NonNull String reason) {
@@ -261,6 +410,42 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
}
+ @Override
+ public void setTrackingHeadsUp(boolean trackingHeadsUp) {
+ mTrackingHeadsUp = trackingHeadsUp;
+ }
+
+ @Override
+ public boolean shouldSwallowClick(@NonNull String key) {
+ BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
+ return entry != null && mSystemClock.elapsedRealtime() < entry.mPostTime;
+ }
+
+ @Override
+ public void releaseAfterExpansion() {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ onExpandingFinished();
+ }
+
+ @Override
+ public void onExpandingFinished() {
+ if (mReleaseOnExpandFinish) {
+ releaseAllImmediately();
+ mReleaseOnExpandFinish = false;
+ } else {
+ for (NotificationEntry entry : getAllEntries().toList()) {
+ entry.setSeenInShade(true);
+ }
+ for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
+ if (isHeadsUpEntry(entry.getKey())) {
+ // Maybe the heads-up was removed already
+ removeEntry(entry.getKey(), "onExpandingFinished");
+ }
+ }
+ }
+ mEntriesToRemoveAfterExpand.clear();
+ }
+
/**
* Clears all managed notifications.
*/
@@ -339,10 +524,19 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
return 0;
}
+ @VisibleForTesting
protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationEntry entry) {
- if (entry == null) {
- return false;
+ boolean pin = mStatusBarState == StatusBarState.SHADE && !mIsShadeOrQsExpanded;
+ if (SceneContainerFlag.isEnabled()) {
+ pin |= mIsQsExpanded;
+ }
+ if (mBypassController.getBypassEnabled()) {
+ pin |= mStatusBarState == StatusBarState.KEYGUARD;
+ }
+ if (pin) {
+ return true;
}
+
final HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
if (headsUpEntry == null) {
// This should not happen since shouldHeadsUpBecomePinned is always called after adding
@@ -392,10 +586,6 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
}
- public @InflationFlag int getContentFlag() {
- return FLAG_CONTENT_VIEW_HEADS_UP;
- }
-
/**
* Manager-specific logic that should occur when an entry is added.
* @param headsUpEntry entry added
@@ -410,6 +600,8 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpStateChanged(entry, true);
}
+ updateTopHeadsUpFlow();
+ updateHeadsUpFlow();
}
/**
@@ -441,7 +633,7 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
entry.demoteStickyHun();
mHeadsUpEntryMap.remove(key);
- onEntryRemoved(finalHeadsUpEntry);
+ onEntryRemoved(finalHeadsUpEntry, reason);
// TODO(b/328390331) move accessibility events to the view layer
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
if (NotificationThrottleHun.isEnabled()) {
@@ -456,8 +648,9 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
/**
* Manager-specific logic that should occur when an entry is removed.
* @param headsUpEntry entry removed
+ * @param reason why onEntryRemoved was called
*/
- protected void onEntryRemoved(HeadsUpEntry headsUpEntry) {
+ protected void onEntryRemoved(HeadsUpEntry headsUpEntry, String reason) {
NotificationEntry entry = headsUpEntry.mEntry;
entry.setHeadsUp(false);
setEntryPinned(headsUpEntry, false /* isPinned */, "onEntryRemoved");
@@ -466,11 +659,67 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpStateChanged(entry, false);
}
+ if (!NotificationThrottleHun.isEnabled()) {
+ mEntryPool.release(headsUpEntry);
+ }
+ updateTopHeadsUpFlow();
+ updateHeadsUpFlow();
+ if (NotificationThrottleHun.isEnabled()) {
+ NotificationEntry notifEntry = headsUpEntry.mEntry;
+ if (notifEntry == null) {
+ return;
+ }
+ // If reorder was just allowed and we called onEntryRemoved while iterating over
+ // mEntriesToRemoveWhenReorderingAllowed, we should not remove from this list (and cause
+ // ArrayIndexOutOfBoundsException). We don't need to in this case anyway, because we
+ // clear mEntriesToRemoveWhenReorderingAllowed after removing these entries.
+ if (!reason.equals(REASON_REORDER_ALLOWED)
+ && mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)) {
+ mEntriesToRemoveWhenReorderingAllowed.remove(notifEntry);
+ }
+ }
+ }
+
+ private void updateTopHeadsUpFlow() {
+ mTopHeadsUpRow.setValue((HeadsUpRowRepository) getTopHeadsUpEntry());
+ }
+
+ private void updateHeadsUpFlow() {
+ mHeadsUpNotificationRows.setValue(new HashSet<>(getHeadsUpEntryPhoneMap().values()));
+ }
+
+ @Override
+ @NonNull
+ public Flow<HeadsUpRowRepository> getTopHeadsUpRow() {
+ return mTopHeadsUpRow;
+ }
+
+ @Override
+ @NonNull
+ public Flow<Set<HeadsUpRowRepository>> getActiveHeadsUpRows() {
+ return mHeadsUpNotificationRows;
+ }
+
+ @Override
+ @NonNull
+ public StateFlow<Boolean> isHeadsUpAnimatingAway() {
+ return mHeadsUpAnimatingAway;
+ }
+
+ @Override
+ public boolean isHeadsUpAnimatingAwayValue() {
+ return mHeadsUpAnimatingAway.getValue();
+ }
+
+ @NonNull
+ private ArrayMap<String, HeadsUpEntry> getHeadsUpEntryPhoneMap() {
+ return mHeadsUpEntryMap;
}
/**
* Called to notify the listeners that the HUN animating away animation has ended.
*/
+ @Override
public void onEntryAnimatingAwayEnded(@NonNull NotificationEntry entry) {
for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpAnimatingAwayEnded(entry);
@@ -484,6 +733,8 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
* @param headsUpEntry entry updated
*/
protected void onEntryUpdated(HeadsUpEntry headsUpEntry) {
+ // no need to update the list here
+ updateTopHeadsUpFlow();
}
protected void updatePinnedMode() {
@@ -521,6 +772,7 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
/**
* Snoozes all current Heads Up Notifications.
*/
+ @Override
public void snooze() {
List<String> keySet = new ArrayList<>(mHeadsUpEntryMap.keySet());
keySet.addAll(mAvalancheController.getWaitingKeys());
@@ -534,6 +786,7 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
mLogger.logPackageSnoozed(snoozeKey);
mSnoozedPackages.put(snoozeKey, mSystemClock.elapsedRealtime() + mSnoozeLengthMs);
}
+ mReleaseOnExpandFinish = true;
}
@NonNull
@@ -541,6 +794,11 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
return user + "," + packageName;
}
+ @Override
+ public void addSwipedOutNotification(@NonNull String key) {
+ mSwipedOutKeys.add(key);
+ }
+
@Nullable
protected HeadsUpEntry getHeadsUpEntry(@NonNull String key) {
if (mHeadsUpEntryMap.containsKey(key)) {
@@ -597,6 +855,59 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
@Override
+ public @Nullable Region getTouchableRegion() {
+ NotificationEntry topEntry = getTopEntry();
+
+ // This call could be made in an inconsistent state while the pinnedMode hasn't been
+ // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's
+ // therefore also check if the topEntry is null.
+ if (!hasPinnedHeadsUp() || topEntry == null) {
+ return null;
+ } else {
+ if (topEntry.rowIsChildInGroup()) {
+ final NotificationEntry groupSummary =
+ mGroupMembershipManager.getGroupSummary(topEntry);
+ if (groupSummary != null) {
+ topEntry = groupSummary;
+ }
+ }
+ ExpandableNotificationRow topRow = topEntry.getRow();
+ int[] tmpArray = new int[2];
+ topRow.getLocationOnScreen(tmpArray);
+ int minX = tmpArray[0];
+ int maxX = tmpArray[0] + topRow.getWidth();
+ int height = topRow.getIntrinsicHeight();
+ final boolean stretchToTop = tmpArray[1] <= mHeadsUpInset;
+ mTouchableRegion.set(minX, stretchToTop ? 0 : tmpArray[1], maxX, tmpArray[1] + height);
+ return mTouchableRegion;
+ }
+ }
+
+ @Override
+ public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+ if (headsUpAnimatingAway != mHeadsUpAnimatingAway.getValue()) {
+ for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
+ listener.onHeadsUpAnimatingAwayStateChanged(headsUpAnimatingAway);
+ }
+ mHeadsUpAnimatingAway.setValue(headsUpAnimatingAway);
+ }
+ }
+
+ private void onShadeOrQsExpanded(Boolean isExpanded) {
+ if (isExpanded != mIsShadeOrQsExpanded) {
+ mIsShadeOrQsExpanded = isExpanded;
+ if (!SceneContainerFlag.isEnabled() && isExpanded) {
+ mHeadsUpAnimatingAway.setValue(false);
+ }
+ }
+ }
+
+ private void onQsExpanded(Boolean isQsExpanded) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ if (isQsExpanded != mIsQsExpanded) mIsQsExpanded = isQsExpanded;
+ }
+
+ @Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("HeadsUpManager state:");
dumpInternal(pw, args);
@@ -616,6 +927,10 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
pw.print(" "); pw.print(mSnoozedPackages.valueAt(i));
pw.print(", "); pw.println(mSnoozedPackages.keyAt(i));
}
+ pw.print(" mBarState=");
+ pw.println(mStatusBarState);
+ pw.print(" mTouchableRegion=");
+ pw.println(mTouchableRegion);
}
/**
@@ -639,6 +954,7 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
* Unpins all pinned Heads Up Notifications.
* @param userUnPinned The unpinned action is trigger by user real operation.
*/
+ @Override
public void unpinAll(boolean userUnPinned) {
for (String key : mHeadsUpEntryMap.keySet()) {
HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
@@ -662,13 +978,59 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
}
- /**
- * Returns the value of the tracking-heads-up flag. See the doc of {@code setTrackingHeadsUp} as
- * well.
- */
+ @Override
+ public void setRemoteInputActive(
+ @NonNull NotificationEntry entry, boolean remoteInputActive) {
+ HeadsUpEntry headsUpEntry = getHeadsUpEntryPhone(entry.getKey());
+ if (headsUpEntry != null && headsUpEntry.mRemoteInputActive != remoteInputActive) {
+ headsUpEntry.mRemoteInputActive = remoteInputActive;
+ if (ExpandHeadsUpOnInlineReply.isEnabled() && remoteInputActive) {
+ headsUpEntry.mRemoteInputActivatedAtLeastOnce = true;
+ }
+ if (remoteInputActive) {
+ headsUpEntry.cancelAutoRemovalCallbacks("setRemoteInputActive(true)");
+ } else {
+ headsUpEntry.updateEntry(false /* updatePostTime */, "setRemoteInputActive(false)");
+ }
+ onEntryUpdated(headsUpEntry);
+ }
+ }
+
+ @Nullable
+ private HeadsUpEntry getHeadsUpEntryPhone(@NonNull String key) {
+ return mHeadsUpEntryMap.get(key);
+ }
+
+ @Override
+ public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+ HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
+ if (headsUpEntry == null) return;
+ if (entry.isRowPinned() || !gutsShown) {
+ headsUpEntry.setGutsShownPinned(gutsShown);
+ }
+ }
+
+ @Override
+ public void extendHeadsUp() {
+ HeadsUpEntry topEntry = getTopHeadsUpEntryPhone();
+ if (topEntry == null) {
+ return;
+ }
+ topEntry.extendPulse();
+ }
+
+ @Nullable
+ private HeadsUpEntry getTopHeadsUpEntryPhone() {
+ if (SceneContainerFlag.isEnabled()) {
+ return (HeadsUpEntry) mTopHeadsUpRow.getValue();
+ } else {
+ return getTopHeadsUpEntry();
+ }
+ }
+
+ @Override
public boolean isTrackingHeadsUp() {
- // Might be implemented in subclass.
- return false;
+ return mTrackingHeadsUp;
}
/**
@@ -724,11 +1086,23 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
*/
@Override
public boolean canRemoveImmediately(@NonNull String key) {
- HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
- if (headsUpEntry != null && headsUpEntry.mUserActionMayIndirectlyRemove) {
+ if (mSwipedOutKeys.contains(key)) {
+ // We always instantly dismiss views being manually swiped out.
+ mSwipedOutKeys.remove(key);
return true;
}
- return headsUpEntry == null || headsUpEntry.wasShownLongEnough()
+
+ HeadsUpEntry headsUpEntry = getHeadsUpEntryPhone(key);
+ HeadsUpEntry topEntry = getTopHeadsUpEntryPhone();
+
+ if (headsUpEntry == null || headsUpEntry != topEntry) {
+ return true;
+ }
+
+ if (headsUpEntry.mUserActionMayIndirectlyRemove) {
+ return true;
+ }
+ return headsUpEntry.wasShownLongEnough()
|| (headsUpEntry.mEntry != null && headsUpEntry.mEntry.isRowDismissed());
}
@@ -747,7 +1121,13 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
@NonNull
protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
- return new HeadsUpEntry(entry);
+ if (NotificationThrottleHun.isEnabled()) {
+ return new HeadsUpEntry(entry);
+ } else {
+ HeadsUpEntry headsUpEntry = mEntryPool.acquire();
+ headsUpEntry.setEntry(entry);
+ return headsUpEntry;
+ }
}
/**
@@ -763,12 +1143,80 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
&& Notification.CATEGORY_CALL.equals(n.category));
}
+ @VisibleForTesting
+ public final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> {
+ if (NotificationThrottleHun.isEnabled()) {
+ mAvalancheController.setEnableAtRuntime(true);
+ if (mEntriesToRemoveWhenReorderingAllowed.isEmpty()) {
+ return;
+ }
+ }
+ mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
+ for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
+ if (entry != null && isHeadsUpEntry(entry.getKey())) {
+ // Maybe the heads-up was removed already
+ removeEntry(entry.getKey(), REASON_REORDER_ALLOWED);
+ }
+ }
+ mEntriesToRemoveWhenReorderingAllowed.clear();
+ mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
+ };
+
+ private final OnReorderingBannedListener mOnReorderingBannedListener = () -> {
+ if (mAvalancheController != null) {
+ // In open shade the first HUN is pinned, and visual stability logic prevents us from
+ // unpinning this first HUN as long as the shade remains open. AvalancheController only
+ // shows the next HUN when the currently showing HUN is unpinned, so we must disable
+ // throttling here so that the incoming HUN stream is not forever paused. This is reset
+ // when reorder becomes allowed.
+ mAvalancheController.setEnableAtRuntime(false);
+
+ // Note that we cannot do the above when
+ // 1) The remove runnable runs because its delay means it may not run before shade close
+ // 2) Reordering is allowed again (when shade closes) because the HUN appear animation
+ // will have started by then
+ }
+ };
+
+ private final StatusBarStateController.StateListener
+ mStatusBarStateListener = new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
+ boolean isKeyguard = newState == StatusBarState.KEYGUARD;
+ mStatusBarState = newState;
+
+ if (wasKeyguard && !isKeyguard && mBypassController.getBypassEnabled()) {
+ ArrayList<String> keysToRemove = new ArrayList<>();
+ for (HeadsUpEntry entry : getHeadsUpEntryList()) {
+ if (entry.mEntry != null && entry.mEntry.isBubble() && !entry.isSticky()) {
+ keysToRemove.add(entry.mEntry.getKey());
+ }
+ }
+ for (String key : keysToRemove) {
+ removeEntry(key, "mStatusBarStateListener");
+ }
+ }
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ if (!isDozing) {
+ // Let's make sure all huns we got while dozing time out within the normal timeout
+ // duration. Otherwise they could get stuck for a very long time
+ for (HeadsUpEntry entry : getHeadsUpEntryList()) {
+ entry.updateEntry(true /* updatePostTime */, "onDozingChanged(false)");
+ }
+ }
+ }
+ };
+
/**
* This represents a notification and how long it is in a heads up mode. It also manages its
* lifecycle automatically when created. This class is public because it is exposed by methods
* of AvalancheController that take it as param.
*/
- public class HeadsUpEntry implements Comparable<HeadsUpEntry> {
+ public class HeadsUpEntry implements Comparable<HeadsUpEntry>, HeadsUpRowRepository {
public boolean mRemoteInputActivatedAtLeastOnce;
public boolean mRemoteInputActive;
public boolean mUserActionMayIndirectlyRemove;
@@ -784,6 +1232,14 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
@Nullable private Runnable mCancelRemoveRunnable;
+ private boolean mGutsShownPinned;
+ private final MutableStateFlow<Boolean> mIsPinned = StateFlowKt.MutableStateFlow(false);
+
+ /**
+ * If the time this entry has been on was extended
+ */
+ private boolean extended;
+
public HeadsUpEntry() {
NotificationThrottleHun.assertInLegacyMode();
}
@@ -794,19 +1250,50 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
setEntry(entry, createRemoveRunnable(entry));
}
+ @Override
+ @NonNull
+ public String getKey() {
+ return requireEntry().getKey();
+ }
+
+ @Override
+ @NonNull
+ public Object getElementKey() {
+ return requireEntry().getRow();
+ }
+
+ private NotificationEntry requireEntry() {
+ /* check if */ SceneContainerFlag.isUnexpectedlyInLegacyMode();
+ return Objects.requireNonNull(mEntry);
+ }
+
+ @Override
+ @NonNull
+ public StateFlow<Boolean> isPinned() {
+ return mIsPinned;
+ }
+
/** Attach a NotificationEntry. */
public void setEntry(@NonNull final NotificationEntry entry) {
NotificationThrottleHun.assertInLegacyMode();
setEntry(entry, createRemoveRunnable(entry));
}
- protected void setEntry(@NonNull final NotificationEntry entry,
+ protected void setEntry(
+ @NonNull final NotificationEntry entry,
@Nullable Runnable removeRunnable) {
mEntry = entry;
mRemoveRunnable = removeRunnable;
mPostTime = calculatePostTime();
updateEntry(true /* updatePostTime */, "setEntry");
+
+ if (NotificationThrottleHun.isEnabled()) {
+ mEntriesToRemoveWhenReorderingAllowed.add(entry);
+ if (!mVisualStabilityProvider.isReorderingAllowed()) {
+ entry.setSeenInShade(true);
+ }
+ }
}
protected boolean isRowPinned() {
@@ -815,6 +1302,7 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
protected void setRowPinned(boolean pinned) {
if (mEntry != null) mEntry.setRowPinned(pinned);
+ mIsPinned.setValue(pinned);
}
/**
@@ -870,6 +1358,22 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
// Notify the manager, that the posted time has changed.
onEntryUpdated(this);
+
+ if (mEntriesToRemoveAfterExpand.contains(mEntry)) {
+ mEntriesToRemoveAfterExpand.remove(mEntry);
+ }
+ if (!NotificationThrottleHun.isEnabled()) {
+ if (mEntriesToRemoveWhenReorderingAllowed.contains(mEntry)) {
+ mEntriesToRemoveWhenReorderingAllowed.remove(mEntry);
+ }
+ }
+ }
+
+ private void extendPulse() {
+ if (!extended) {
+ extended = true;
+ updateEntry(false, "extendPulse()");
+ }
}
/**
@@ -878,6 +1382,8 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
* @return true if the notification is sticky
*/
public boolean isSticky() {
+ if (mGutsShownPinned) return true;
+
if (mEntry == null) return false;
if (ExpandHeadsUpOnInlineReply.isEnabled()) {
@@ -989,7 +1495,29 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
}
public void setExpanded(boolean expanded) {
+ if (this.mExpanded == expanded) {
+ return;
+ }
+
this.mExpanded = expanded;
+ if (expanded) {
+ cancelAutoRemovalCallbacks("setExpanded(true)");
+ } else {
+ updateEntry(false /* updatePostTime */, "setExpanded(false)");
+ }
+ }
+
+ public void setGutsShownPinned(boolean gutsShownPinned) {
+ if (mGutsShownPinned == gutsShownPinned) {
+ return;
+ }
+
+ mGutsShownPinned = gutsShownPinned;
+ if (gutsShownPinned) {
+ cancelAutoRemovalCallbacks("setGutsShownPinned(true)");
+ } else {
+ updateEntry(false /* updatePostTime */, "setGutsShownPinned(false)");
+ }
}
public void reset() {
@@ -999,6 +1527,8 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
mRemoveRunnable = null;
mExpanded = false;
mRemoteInputActive = false;
+ mGutsShownPinned = false;
+ extended = false;
}
/**
@@ -1074,7 +1604,23 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
/** Creates a runnable to remove this notification from the alerting entries. */
protected Runnable createRemoveRunnable(NotificationEntry entry) {
- return () -> removeEntry(entry.getKey(), "createRemoveRunnable");
+ return () -> {
+ if (!NotificationThrottleHun.isEnabled()
+ && !mVisualStabilityProvider.isReorderingAllowed()
+ // We don't want to allow reordering while pulsing, but headsup need to
+ // time out anyway
+ && !entry.showingPulsing()) {
+ mEntriesToRemoveWhenReorderingAllowed.add(entry);
+ mVisualStabilityProvider.addTemporaryReorderingAllowedListener(
+ mOnReorderingAllowedListener);
+ } else if (mTrackingHeadsUp) {
+ mEntriesToRemoveAfterExpand.add(entry);
+ mLogger.logRemoveEntryAfterExpand(entry);
+ } else if (mVisualStabilityProvider.isReorderingAllowed()
+ || entry.showingPulsing()) {
+ removeEntry(entry.getKey(), "createRemoveRunnable");
+ }
+ };
}
/**
@@ -1098,7 +1644,7 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {
requestedTimeOutMs = mAvalancheController.getDurationMs(this, mAutoDismissTime);
}
final long duration = getRecommendedHeadsUpTimeoutMs(requestedTimeOutMs);
- return mPostTime + duration;
+ return mPostTime + duration + (extended ? mExtensionTime : 0);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index a115baad257d..52f80fbf50fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -24,6 +24,7 @@ import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
+import android.media.projection.StopReason;
import android.os.Handler;
import android.util.ArrayMap;
@@ -190,7 +191,7 @@ public class CastControllerImpl implements CastController {
if (isProjection) {
final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag();
if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) {
- mProjectionManager.stopActiveProjection();
+ mProjectionManager.stopActiveProjection(StopReason.STOP_QS_TILE);
} else {
mLogger.logStopCastingNoProjection(projection);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
index 04fe6b3e9eb7..b37194b8b7a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
@@ -59,6 +59,7 @@ interface HeadsUpManager : Dumpable {
* Gets the touchable region needed for heads up notifications. Returns null if no touchable
* region is required (ie: no heads up notification currently exists).
*/
+ // TODO(b/347007367): With scene container enabled this method may report outdated regions
fun getTouchableRegion(): Region?
/**
@@ -83,6 +84,10 @@ interface HeadsUpManager : Dumpable {
/** Returns whether the entry is (pinned and expanded) or (has an active remote input). */
fun isSticky(key: String?): Boolean
+ /**
+ * Returns the value of the tracking-heads-up flag. See the doc of {@code setTrackingHeadsUp} as
+ * well.
+ */
fun isTrackingHeadsUp(): Boolean
fun onExpandingFinished()
@@ -115,7 +120,7 @@ interface HeadsUpManager : Dumpable {
key: String,
releaseImmediately: Boolean,
animate: Boolean,
- reason: String
+ reason: String,
): Boolean
/** Clears all managed notifications. */
@@ -149,6 +154,10 @@ interface HeadsUpManager : Dumpable {
*/
fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean)
+ /**
+ * Sets the tracking-heads-up flag. If the flag is true, HeadsUpManager doesn't remove the entry
+ * from the list even after a Heads Up Notification is gone.
+ */
fun setTrackingHeadsUp(tracking: Boolean)
/** Sets the current user. */
@@ -260,7 +269,7 @@ class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager {
key: String,
releaseImmediately: Boolean,
animate: Boolean,
- reason: String
+ reason: String,
) = false
override fun setAnimationStateHandler(handler: AnimationStateHandler) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitClockView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitClockView.java
deleted file mode 100644
index 0d36b48e9099..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitClockView.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.policy;
-
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserHandle;
-import android.text.format.DateFormat;
-import android.util.AttributeSet;
-import android.widget.LinearLayout;
-import android.widget.TextClock;
-
-import com.android.systemui.res.R;
-
-/**
- * Container for a clock which has two separate views for the clock itself and AM/PM indicator. This
- * is used to scale the clock independently of AM/PM.
- */
-public class SplitClockView extends LinearLayout {
-
- private TextClock mTimeView;
- private TextClock mAmPmView;
-
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_TIME_CHANGED.equals(action)
- || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
- || Intent.ACTION_LOCALE_CHANGED.equals(action)
- || Intent.ACTION_CONFIGURATION_CHANGED.equals(action)
- || Intent.ACTION_USER_SWITCHED.equals(action)) {
- updatePatterns();
- }
- }
- };
-
- public SplitClockView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mTimeView = findViewById(R.id.time_view);
- mAmPmView = findViewById(R.id.am_pm_view);
- mTimeView.setShowCurrentUserTime(true);
- mAmPmView.setShowCurrentUserTime(true);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- filter.addAction(Intent.ACTION_LOCALE_CHANGED);
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
-
- updatePatterns();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- getContext().unregisterReceiver(mIntentReceiver);
- }
-
- private void updatePatterns() {
- String formatString = DateFormat.getTimeFormatString(getContext(),
- ActivityManager.getCurrentUser());
- int index = getAmPmPartEndIndex(formatString);
- String timeString;
- String amPmString;
- if (index == -1) {
- timeString = formatString;
- amPmString = "";
- } else {
- timeString = formatString.substring(0, index);
- amPmString = formatString.substring(index);
- }
- mTimeView.setFormat12Hour(timeString);
- mTimeView.setFormat24Hour(timeString);
- mTimeView.setContentDescriptionFormat12Hour(formatString);
- mTimeView.setContentDescriptionFormat24Hour(formatString);
- mAmPmView.setFormat12Hour(amPmString);
- mAmPmView.setFormat24Hour(amPmString);
- }
-
- /**
- * @return the index where the AM/PM part starts at the end in {@code formatString} including
- * leading white spaces or {@code -1} if no AM/PM part is found or {@code formatString}
- * doesn't end with AM/PM part
- */
- private static int getAmPmPartEndIndex(String formatString) {
- boolean hasAmPm = false;
- int length = formatString.length();
- for (int i = length - 1; i >= 0; i--) {
- char c = formatString.charAt(i);
- boolean isAmPm = c == 'a';
- boolean isWhitespace = Character.isWhitespace(c);
- if (isAmPm) {
- hasAmPm = true;
- }
- if (isAmPm || isWhitespace) {
- continue;
- }
- if (i == length - 1) {
-
- // First character was not AM/PM and not whitespace, so it's not ending with AM/PM.
- return -1;
- } else {
-
- // If we have AM/PM at all, return last index, or -1 to indicate that it's not
- // ending with AM/PM.
- return hasAmPm ? i + 1 : -1;
- }
- }
-
- // Only AM/PM and whitespaces? The whole string is AM/PM. Else: Only whitespaces in the
- // string.
- return hasAmPm ? 0 : -1;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
index abd24533e1c4..238e56a1785f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
@@ -28,7 +28,7 @@ data class ModeTileViewModel(
val icon: Icon,
val text: String,
val subtext: String,
- val subtextDescription: String, // version of subtext without "on"/"off" for screen readers
+ val subtextDescription: String, // version of subtext (without "on"/"off") for screen readers
val enabled: Boolean,
val stateDescription: String, // "on"/"off" state of the tile, for screen readers
val onClick: () -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
index 4f595ed152e4..1c13a833ef30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
@@ -23,6 +23,7 @@ import android.provider.Settings.ACTION_AUTOMATIC_ZEN_RULE_SETTINGS
import android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID
import com.android.settingslib.notification.modes.EnableZenModeDialog
import com.android.settingslib.notification.modes.ZenMode
+import com.android.settingslib.notification.modes.ZenModeDescriptions
import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -54,6 +55,7 @@ constructor(
private val dialogEventLogger: ModesDialogEventLogger,
) {
private val zenDialogMetricsLogger = QSZenModeDialogMetricsLogger(context)
+ private val zenModeDescriptions = ZenModeDescriptions(context)
// Modes that should be displayed in the dialog
private val visibleModes: Flow<List<ZenMode>> =
@@ -92,7 +94,8 @@ constructor(
icon = zenModeInteractor.getModeIcon(mode).drawable().asIcon(),
text = mode.name,
subtext = getTileSubtext(mode),
- subtextDescription = getModeDescription(mode) ?: "",
+ subtextDescription =
+ getModeDescription(mode, forAccessibility = true) ?: "",
enabled = mode.isActive,
stateDescription =
context.getString(
@@ -145,18 +148,21 @@ constructor(
* This description is used directly for the content description of a mode tile for screen
* readers, and for the tile subtext will be augmented with the current status of the mode.
*/
- private fun getModeDescription(mode: ZenMode): String? {
+ private fun getModeDescription(mode: ZenMode, forAccessibility: Boolean): String? {
if (!mode.rule.isEnabled) {
return context.resources.getString(R.string.zen_mode_set_up)
}
if (!mode.rule.isManualInvocationAllowed && !mode.isActive) {
return context.resources.getString(R.string.zen_mode_no_manual_invocation)
}
- return mode.getDynamicDescription(context)
+ return if (forAccessibility)
+ zenModeDescriptions.getTriggerDescriptionForAccessibility(mode)
+ ?: zenModeDescriptions.getTriggerDescription(mode)
+ else zenModeDescriptions.getTriggerDescription(mode)
}
private fun getTileSubtext(mode: ZenMode): String {
- val modeDescription = getModeDescription(mode)
+ val modeDescription = getModeDescription(mode, forAccessibility = false)
return if (mode.isActive) {
if (modeDescription != null) {
context.getString(R.string.zen_mode_on_with_details, modeDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
index 584cd3b00a57..1e043ec48142 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
@@ -36,6 +36,9 @@ interface StatusBarWindowController {
/** Adds the status bar view to the window manager. */
fun attach()
+ /** Called when work should stop and resources should be released. */
+ fun stop()
+
/** Adds the given view to the status bar window view. */
fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams)
@@ -78,7 +81,7 @@ interface StatusBarWindowController {
*/
fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean)
- interface Factory {
+ fun interface Factory {
fun create(
context: Context,
viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
index 6953bbf735f1..811a2ec44ccc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
@@ -51,10 +51,12 @@ import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.animation.DelegateTransitionAnimatorController;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
+import com.android.systemui.statusbar.core.StatusBarRootModernization;
import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.window.StatusBarWindowModule.InternalWindowViewInflater;
@@ -66,6 +68,7 @@ import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
import java.util.Optional;
+import java.util.concurrent.Executor;
/**
* Encapsulates all logic for the status bar window state management.
@@ -79,6 +82,7 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController
private final StatusBarConfigurationController mStatusBarConfigurationController;
private final IWindowManager mIWindowManager;
private final StatusBarContentInsetsProvider mContentInsetsProvider;
+ private final Executor mMainExecutor;
private int mBarHeight = -1;
private final State mCurrentState = new State();
private boolean mIsAttached;
@@ -101,12 +105,14 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController
IWindowManager iWindowManager,
@Assisted StatusBarContentInsetsProvider contentInsetsProvider,
FragmentService fragmentService,
- Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider) {
+ Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider,
+ @Main Executor mainExecutor) {
mContext = context;
mWindowManager = viewCaptureAwareWindowManager;
mStatusBarConfigurationController = statusBarConfigurationController;
mIWindowManager = iWindowManager;
mContentInsetsProvider = contentInsetsProvider;
+ mMainExecutor = mainExecutor;
mStatusBarWindowView = statusBarWindowViewInflater.inflate(context);
mFragmentService = fragmentService;
mLaunchAnimationContainer = mStatusBarWindowView.findViewById(
@@ -167,6 +173,19 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController
}
@Override
+ public void stop() {
+ StatusBarConnectedDisplays.assertInNewMode();
+
+ mWindowManager.removeView(mStatusBarWindowView);
+
+ if (StatusBarRootModernization.isEnabled()) {
+ return;
+ }
+ // Fragment transactions need to happen on the main thread.
+ mMainExecutor.execute(() -> mFragmentService.removeAndDestroy(mStatusBarWindowView));
+ }
+
+ @Override
public void addViewToWindow(@NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) {
mStatusBarWindowView.addView(view, layoutParams);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
index 051d463a8b97..74031612f28e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -70,6 +70,10 @@ constructor(
)
}
+ override suspend fun onDisplayRemovalAction(instance: StatusBarWindowController) {
+ instance.stop()
+ }
+
override val instanceClass = StatusBarWindowController::class.java
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index d97cae2a99e3..d367455d26c7 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -50,6 +50,7 @@ import com.android.systemui.plugins.ToastPlugin;
public class SystemUIToast implements ToastPlugin.Toast {
static final String TAG = "SystemUIToast";
final Context mContext;
+ final Context mDisplayContext;
final CharSequence mText;
final ToastPlugin.Toast mPluginToast;
@@ -68,17 +69,18 @@ public class SystemUIToast implements ToastPlugin.Toast {
@Nullable private final Animator mInAnimator;
@Nullable private final Animator mOutAnimator;
- SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
- String packageName, int userId, int orientation) {
- this(layoutInflater, context, text, null, packageName, userId,
+ SystemUIToast(LayoutInflater layoutInflater, Context applicationContext, Context displayContext,
+ CharSequence text, String packageName, int userId, int orientation) {
+ this(layoutInflater, applicationContext, displayContext, text, null, packageName, userId,
orientation);
}
- SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
- ToastPlugin.Toast pluginToast, String packageName, @UserIdInt int userId,
- int orientation) {
+ SystemUIToast(LayoutInflater layoutInflater, Context applicationContext, Context displayContext,
+ CharSequence text, ToastPlugin.Toast pluginToast, String packageName,
+ @UserIdInt int userId, int orientation) {
mLayoutInflater = layoutInflater;
- mContext = context;
+ mContext = applicationContext;
+ mDisplayContext = displayContext;
mText = text;
mPluginToast = pluginToast;
mPackageName = packageName;
@@ -221,9 +223,9 @@ public class SystemUIToast implements ToastPlugin.Toast {
mPluginToast.onOrientationChange(orientation);
}
- mDefaultY = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
+ mDefaultY = mDisplayContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
mDefaultGravity =
- mContext.getResources().getInteger(R.integer.config_toastDefaultGravity);
+ mDisplayContext.getResources().getInteger(R.integer.config_toastDefaultGravity);
}
private Animator createInAnimator() {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
index 9ae66749aa0a..388d4bd6780b 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
@@ -65,15 +65,16 @@ public class ToastFactory implements Dumpable {
/**
* Create a toast to be shown by ToastUI.
*/
- public SystemUIToast createToast(Context context, CharSequence text, String packageName,
- int userId, int orientation) {
- LayoutInflater layoutInflater = LayoutInflater.from(context);
+ public SystemUIToast createToast(Context applicationContext, Context displayContext,
+ CharSequence text, String packageName, int userId, int orientation) {
+ LayoutInflater layoutInflater = LayoutInflater.from(displayContext);
if (isPluginAvailable()) {
- return new SystemUIToast(layoutInflater, context, text, mPlugin.createToast(text,
- packageName, userId), packageName, userId, orientation);
+ return new SystemUIToast(layoutInflater, applicationContext, displayContext, text,
+ mPlugin.createToast(text, packageName, userId), packageName, userId,
+ orientation);
}
- return new SystemUIToast(layoutInflater, context, text, packageName, userId,
- orientation);
+ return new SystemUIToast(layoutInflater, applicationContext, displayContext, text,
+ packageName, userId, orientation);
}
private boolean isPluginAvailable() {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 32a4f12777ac..12f73b8a887d 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -135,8 +135,8 @@ public class ToastUI implements
return;
}
Context displayContext = context.createDisplayContext(display);
- mToast = mToastFactory.createToast(displayContext /* sysuiContext */, text, packageName,
- userHandle.getIdentifier(), mOrientation);
+ mToast = mToastFactory.createToast(mContext, displayContext /* sysuiContext */, text,
+ packageName, userHandle.getIdentifier(), mOrientation);
if (mToast.getInAnimation() != null) {
mToast.getInAnimation().start();
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index d371acf86a28..66a900bd72d8 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -18,6 +18,7 @@ package com.android.systemui.touchpad.tutorial.ui.composable
import android.content.res.Configuration
import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -36,8 +37,12 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.pointer.pointerInteropFilter
@@ -49,6 +54,7 @@ import com.android.systemui.inputdevice.tutorial.ui.composable.DoneButton
import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.gesture.isFourFingerTouchpadSwipe
import com.android.systemui.touchpad.tutorial.ui.gesture.isThreeFingerTouchpadSwipe
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen
@Composable
fun TutorialSelectionScreen(
@@ -56,6 +62,7 @@ fun TutorialSelectionScreen(
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
onDoneButtonClicked: () -> Unit,
+ lastSelectedScreen: Screen,
) {
Column(
verticalArrangement = Arrangement.Center,
@@ -80,6 +87,7 @@ fun TutorialSelectionScreen(
onHomeTutorialClicked = onHomeTutorialClicked,
onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
modifier = Modifier.weight(1f).padding(60.dp),
+ lastSelectedScreen,
)
}
else -> {
@@ -88,6 +96,7 @@ fun TutorialSelectionScreen(
onHomeTutorialClicked = onHomeTutorialClicked,
onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
modifier = Modifier.weight(1f).padding(60.dp),
+ lastSelectedScreen,
)
}
}
@@ -105,6 +114,7 @@ private fun HorizontalSelectionButtons(
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
modifier: Modifier = Modifier,
+ lastSelectedScreen: Screen,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(20.dp),
@@ -116,6 +126,7 @@ private fun HorizontalSelectionButtons(
onHomeTutorialClicked,
onRecentAppsTutorialClicked,
modifier = Modifier.weight(1f).fillMaxSize(),
+ lastSelectedScreen,
)
}
}
@@ -126,6 +137,7 @@ private fun VerticalSelectionButtons(
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
modifier: Modifier = Modifier,
+ lastSelectedScreen: Screen,
) {
Column(
verticalArrangement = Arrangement.spacedBy(20.dp),
@@ -137,6 +149,7 @@ private fun VerticalSelectionButtons(
onHomeTutorialClicked,
onRecentAppsTutorialClicked,
modifier = Modifier.weight(1f).fillMaxSize(),
+ lastSelectedScreen,
)
}
}
@@ -147,14 +160,26 @@ private fun ThreeTutorialButtons(
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
modifier: Modifier = Modifier,
+ lastSelectedScreen: Screen,
) {
+ val homeFocusRequester = remember { FocusRequester() }
+ val backFocusRequester = remember { FocusRequester() }
+ val recentAppsFocusRequester = remember { FocusRequester() }
+ LaunchedEffect(Unit) {
+ when (lastSelectedScreen) {
+ Screen.HOME_GESTURE -> homeFocusRequester.requestFocus()
+ Screen.BACK_GESTURE -> backFocusRequester.requestFocus()
+ Screen.RECENT_APPS_GESTURE -> recentAppsFocusRequester.requestFocus()
+ else -> {} // No-Op.
+ }
+ }
TutorialButton(
text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_home_icon),
iconColor = MaterialTheme.colorScheme.onPrimary,
onClick = onHomeTutorialClicked,
backgroundColor = MaterialTheme.colorScheme.primary,
- modifier = modifier,
+ modifier = modifier.focusRequester(homeFocusRequester).focusable(),
)
TutorialButton(
text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
@@ -162,7 +187,7 @@ private fun ThreeTutorialButtons(
iconColor = MaterialTheme.colorScheme.onTertiary,
onClick = onBackTutorialClicked,
backgroundColor = MaterialTheme.colorScheme.tertiary,
- modifier = modifier,
+ modifier = modifier.focusRequester(backFocusRequester).focusable(),
)
TutorialButton(
text = stringResource(R.string.touchpad_tutorial_recent_apps_gesture_button),
@@ -170,7 +195,7 @@ private fun ThreeTutorialButtons(
iconColor = MaterialTheme.colorScheme.onSecondary,
onClick = onRecentAppsTutorialClicked,
backgroundColor = MaterialTheme.colorScheme.secondary,
- modifier = modifier,
+ modifier = modifier.focusRequester(recentAppsFocusRequester).focusable(),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index e1f7bd59005c..6662fc5c127c 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -24,12 +24,16 @@ import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.lifecycle.Lifecycle.State.STARTED
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.theme.PlatformTheme
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger.TutorialContext
import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialMetricsLogger
+import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.RecentAppsGestureTutorialScreen
@@ -54,6 +58,7 @@ constructor(
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
+ setTitle(getString(R.string.launch_touchpad_tutorial_notification_content))
setContent {
PlatformTheme { TouchpadTutorialScreen(vm, closeTutorial = ::finishTutorial) }
}
@@ -82,13 +87,24 @@ constructor(
@Composable
fun TouchpadTutorialScreen(vm: TouchpadTutorialViewModel, closeTutorial: () -> Unit) {
val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED)
+ var lastSelectedScreen by remember { mutableStateOf(TUTORIAL_SELECTION) }
when (activeScreen) {
TUTORIAL_SELECTION ->
TutorialSelectionScreen(
- onBackTutorialClicked = { vm.goTo(BACK_GESTURE) },
- onHomeTutorialClicked = { vm.goTo(HOME_GESTURE) },
- onRecentAppsTutorialClicked = { vm.goTo(RECENT_APPS_GESTURE) },
+ onBackTutorialClicked = {
+ lastSelectedScreen = BACK_GESTURE
+ vm.goTo(BACK_GESTURE)
+ },
+ onHomeTutorialClicked = {
+ lastSelectedScreen = HOME_GESTURE
+ vm.goTo(HOME_GESTURE)
+ },
+ onRecentAppsTutorialClicked = {
+ lastSelectedScreen = RECENT_APPS_GESTURE
+ vm.goTo(RECENT_APPS_GESTURE)
+ },
onDoneButtonClicked = closeTutorial,
+ lastSelectedScreen,
)
BACK_GESTURE ->
BackGestureTutorialScreen(
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index 63a5b3f1e6f6..fb09ab4462ed 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -28,6 +28,7 @@ import java.util.function.Consumer
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
+import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.Job
@@ -64,6 +65,28 @@ class JavaAdapter @Inject constructor(@Application private val scope: CoroutineS
): StateFlow<T> {
return flow.stateIn(scope, started, initialValue)
}
+
+ /** Call suspend functions from Java */
+ fun <T, R> callSuspend(
+ suspendFunction: suspend (T) -> R,
+ arg: T,
+ onSuccess: (R) -> Unit,
+ onCancel: (CancellationException) -> Unit,
+ onFailure: (Throwable) -> Unit,
+ ): Job =
+ scope.launch {
+ val result =
+ try {
+ suspendFunction(arg)
+ } catch (ex: CancellationException) {
+ onCancel(ex)
+ return@launch
+ } catch (ex: Throwable) {
+ onFailure(ex)
+ return@launch
+ }
+ onSuccess(result)
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
index 3c0682822564..e5c1e7daa25a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -17,13 +17,16 @@
package com.android.systemui.util.kotlin
import android.os.Handler
+import com.android.systemui.coroutines.newTracingContext
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Tracing
import com.android.systemui.dagger.qualifiers.UiBackground
+import com.android.systemui.util.settings.SettingsSingleThreadBackground
import dagger.Module
import dagger.Provides
+import java.util.concurrent.Executor
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
@@ -32,8 +35,6 @@ import kotlinx.coroutines.android.asCoroutineDispatcher
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.plus
-import java.util.concurrent.Executor
-import kotlin.coroutines.CoroutineContext
private const val LIMIT_BACKGROUND_DISPATCHER_THREADS = true
@@ -61,7 +62,7 @@ class SysUICoroutinesModule {
@Background
@Deprecated(
"Use @Background CoroutineContext instead",
- ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+ ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
)
fun bgDispatcher(): CoroutineDispatcher {
return if (LIMIT_BACKGROUND_DISPATCHER_THREADS) {
@@ -72,7 +73,7 @@ class SysUICoroutinesModule {
// code on those.
newFixedThreadPoolContext(
nThreads = Runtime.getRuntime().availableProcessors(),
- name = "SystemUIBg"
+ name = "SystemUIBg",
)
} else {
Dispatchers.IO
@@ -88,10 +89,17 @@ class SysUICoroutinesModule {
}
@Provides
+ @SysUISingleton
+ @SettingsSingleThreadBackground
+ fun settingsScope(@Background bgDispatcher: CoroutineDispatcher): CoroutineScope {
+ return CoroutineScope(bgDispatcher + newTracingContext("SettingsProxy"))
+ }
+
+ @Provides
@Background
@SysUISingleton
fun bgCoroutineContext(
- @Background bgCoroutineDispatcher: CoroutineDispatcher,
+ @Background bgCoroutineDispatcher: CoroutineDispatcher
): CoroutineContext {
return bgCoroutineDispatcher
}
@@ -102,7 +110,7 @@ class SysUICoroutinesModule {
@UiBackground
@Deprecated(
"Use @UiBackground CoroutineContext instead",
- ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+ ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
)
fun uiBgDispatcher(@UiBackground uiBgExecutor: Executor): CoroutineDispatcher =
uiBgExecutor.asCoroutineDispatcher()
@@ -111,7 +119,7 @@ class SysUICoroutinesModule {
@UiBackground
@SysUISingleton
fun uiBgCoroutineContext(
- @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher,
+ @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher
): CoroutineContext {
return uiBgCoroutineDispatcher
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
index 49a0f14d6b3b..af03c529cb52 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
@@ -85,6 +85,12 @@ abstract class UserAwareSettingsRepository(
}
}
+ suspend fun setBoolean(name: String, value: Boolean) {
+ withContext(bgContext) {
+ userSettings.putBoolForUser(name, value, userRepository.getSelectedUserInfo().id)
+ }
+ }
+
suspend fun getString(name: String): String? {
return withContext(bgContext) {
userSettings.getStringForUser(name, userRepository.getSelectedUserInfo().id)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index b7058722e2b3..68bffeefb0f0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -18,8 +18,6 @@ package com.android.systemui.volume;
import static android.media.AudioManager.RINGER_MODE_NORMAL;
-import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;
-
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
@@ -79,9 +77,13 @@ import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.concurrency.ThreadFactory;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.volume.domain.interactor.AudioSharingInteractor;
+import com.android.systemui.volume.shared.VolumeLogger;
import dalvik.annotation.optimization.NeverCompile;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@@ -155,6 +157,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private final VibratorHelper mVibrator;
private final AudioSharingInteractor mAudioSharingInteractor;
private final JavaAdapter mJavaAdapter;
+ private final VolumeLogger mVolumeLogger;
private final boolean mHasVibrator;
private boolean mShowA11yStream;
private boolean mShowVolumeDialog;
@@ -202,7 +205,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
UserTracker userTracker,
DumpManager dumpManager,
AudioSharingInteractor audioSharingInteractor,
- JavaAdapter javaAdapter
+ JavaAdapter javaAdapter,
+ VolumeLogger volumeLogger
) {
mContext = context.getApplicationContext();
mPackageManager = packageManager;
@@ -216,6 +220,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
mAudioSharingInteractor = audioSharingInteractor;
mJavaAdapter = javaAdapter;
+ mVolumeLogger = volumeLogger;
mAudio = audioManager;
mNoMan = notificationManager;
mObserver = new SettingObserver(mWorker);
@@ -293,15 +298,28 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
} catch (SecurityException e) {
Log.w(TAG, "No access to media sessions", e);
}
- if (volumeDialogAudioSharingFix()) {
- Slog.d(TAG, "Start collect volume changes in audio sharing");
- mJavaAdapter.alwaysCollectFlow(
- mAudioSharingInteractor.getVolume(),
- this::handleAudioSharingStreamVolumeChanges);
- mJavaAdapter.alwaysCollectFlow(
- mAudioSharingInteractor.isInAudioSharing(),
- inSharing -> mInAudioSharing = inSharing);
- }
+ Function1<Throwable, Unit> errorCallback = (ex) -> {
+ mVolumeLogger.onAudioSharingAvailabilityRequestedError("register()",
+ ex.getMessage());
+ return null;
+ };
+ var unused =
+ mJavaAdapter.<Context, Boolean>callSuspend(
+ mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+ result -> {
+ if (result) {
+ Slog.d(TAG, "Start collect volume changes in audio sharing");
+ mJavaAdapter.alwaysCollectFlow(
+ mAudioSharingInteractor.getVolume(),
+ volume -> handleAudioSharingStreamVolumeChanges(volume));
+ mJavaAdapter.alwaysCollectFlow(
+ mAudioSharingInteractor.isInAudioSharing(),
+ inSharing -> mInAudioSharing = inSharing);
+ }
+ return null;
+ },
+ errorCallback,
+ errorCallback);
}
public void setVolumePolicy(VolumePolicy policy) {
@@ -588,18 +606,34 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
mState.activeStream = activeStream;
Events.writeEvent(Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
- final int s =
- activeStream
- < (volumeDialogAudioSharingFix()
- ? DYNAMIC_STREAM_BROADCAST
- : DYNAMIC_STREAM_REMOTE_START_INDEX)
- ? activeStream
- : -1;
- if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
- mAudio.forceVolumeControlStream(s);
+ Function1<Throwable, Unit> errorCallback = (ex) -> {
+ mVolumeLogger.onAudioSharingAvailabilityRequestedError(
+ "updateActiveStreamW",
+ ex.getMessage());
+ forceVolumeControlStreamW(activeStream, false);
+ return null;
+ };
+ var unused =
+ mJavaAdapter.<Context, Boolean>callSuspend(
+ mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+ result -> {
+ forceVolumeControlStreamW(activeStream, result);
+ return null;
+ },
+ errorCallback,
+ errorCallback);
return true;
}
+ private void forceVolumeControlStreamW(int activeStream,
+ boolean audioSharingVolumeBarAvailable) {
+ final int dynamicStartIdx = audioSharingVolumeBarAvailable ? DYNAMIC_STREAM_BROADCAST
+ : DYNAMIC_STREAM_REMOTE_START_INDEX;
+ final int s = activeStream < dynamicStartIdx ? activeStream : -1;
+ if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
+ mWorker.post(() -> mAudio.forceVolumeControlStream(s));
+ }
+
private StreamState streamStateW(int stream) {
StreamState ss = mState.states.get(stream);
if (ss == null) {
@@ -773,10 +807,26 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
}
private void onSetStreamVolumeW(int stream, int level) {
- if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
- if (volumeDialogAudioSharingFix() && stream == DYNAMIC_STREAM_BROADCAST) {
- Slog.d(TAG, "onSetStreamVolumeW set broadcast stream level = " + level);
- mAudioSharingInteractor.setStreamVolume(level);
+ if (D.BUG) Log.d(TAG, "onSetStreamVolumeW " + stream + " level=" + level);
+
+ if (stream == DYNAMIC_STREAM_BROADCAST) {
+ Function1<Throwable, Unit> errorCallback = (ex) -> {
+ mVolumeLogger.onAudioSharingAvailabilityRequestedError(
+ "onSetStreamVolumeW",
+ ex.getMessage());
+ return null;
+ };
+ var unused =
+ mJavaAdapter.<Context, Boolean>callSuspend(
+ mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+ result -> {
+ if (result) {
+ mAudioSharingInteractor.setStreamVolume(level);
+ }
+ return null;
+ },
+ errorCallback,
+ errorCallback);
return;
}
if (stream >= DYNAMIC_STREAM_REMOTE_START_INDEX) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index bd4c4639e57a..a4e46f667329 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -34,6 +34,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_VOLUME_CONTROL;
import static com.android.internal.jank.InteractionJankMonitor.Configuration.Builder;
+import static com.android.settingslib.flags.Flags.audioSharingDeveloperOption;
import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;
import static com.android.systemui.volume.Events.DISMISS_REASON_POSTURE_CHANGED;
import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
@@ -121,9 +122,9 @@ import com.android.systemui.Flags;
import com.android.systemui.Prefs;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.haptics.slider.HapticSlider;
+import com.android.systemui.haptics.slider.HapticSliderPlugin;
import com.android.systemui.haptics.slider.HapticSliderViewBinder;
import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig;
-import com.android.systemui.haptics.slider.HapticSliderPlugin;
import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig;
import com.android.systemui.media.dialog.MediaOutputDialogManager;
import com.android.systemui.plugins.VolumeDialog;
@@ -1685,10 +1686,10 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
}
// Always show the stream for audio sharing if it exists.
- if (volumeDialogAudioSharingFix()
+ if ((volumeDialogAudioSharingFix() || audioSharingDeveloperOption())
&& row.ss != null
&& mContext.getString(R.string.audio_sharing_description)
- .equals(row.ss.remoteLabel)) {
+ .equals(row.ss.remoteLabel)) {
return true;
}
@@ -1894,9 +1895,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
if (!ss.dynamic) continue;
mDynamic.put(stream, true);
if (findRow(stream) == null) {
- if (volumeDialogAudioSharingFix()
- && mContext.getString(R.string.audio_sharing_description)
- .equals(ss.remoteLabel)) {
+ if ((volumeDialogAudioSharingFix() || audioSharingDeveloperOption())
+ && (mContext.getString(R.string.audio_sharing_description)
+ .equals(ss.remoteLabel))) {
addRow(
stream,
R.drawable.ic_volume_media_bt,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 536403ca970e..3ce1bde16afd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -16,8 +16,6 @@
package com.android.systemui.volume;
-import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;
-
import android.content.Context;
import android.content.res.Configuration;
import android.util.Log;
@@ -28,7 +26,12 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.volume.domain.interactor.AudioSharingInteractor;
+import com.android.systemui.volume.shared.VolumeLogger;
+
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
import java.io.PrintWriter;
@@ -44,16 +47,22 @@ public class VolumeUI implements CoreStartable, ConfigurationController.Configur
private VolumeDialogComponent mVolumeComponent;
private AudioSharingInteractor mAudioSharingInteractor;
private AudioRepository mAudioRepository;
+ private JavaAdapter mJavaAdapter;
+ private VolumeLogger mVolumeLogger;
@Inject
public VolumeUI(Context context,
VolumeDialogComponent volumeDialogComponent,
AudioRepository audioRepository,
- AudioSharingInteractor audioSharingInteractor) {
+ AudioSharingInteractor audioSharingInteractor,
+ JavaAdapter javaAdapter,
+ VolumeLogger volumeLogger) {
mContext = context;
mVolumeComponent = volumeDialogComponent;
mAudioRepository = audioRepository;
mAudioSharingInteractor = audioSharingInteractor;
+ mJavaAdapter = javaAdapter;
+ mVolumeLogger = volumeLogger;
}
@Override
@@ -67,9 +76,22 @@ public class VolumeUI implements CoreStartable, ConfigurationController.Configur
mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
setDefaultVolumeController();
- if (volumeDialogAudioSharingFix()) {
- mAudioSharingInteractor.handlePrimaryGroupChange();
- }
+ Function1<Throwable, Unit> errorCallback = (ex) -> {
+ mVolumeLogger.onAudioSharingAvailabilityRequestedError("start()",
+ ex.getMessage());
+ return null;
+ };
+ var unused =
+ mJavaAdapter.<Context, Boolean>callSuspend(
+ mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+ result -> {
+ if (result) {
+ mAudioSharingInteractor.handlePrimaryGroupChange();
+ }
+ return null;
+ },
+ errorCallback,
+ errorCallback);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
index d5b8597e36ed..d71ddb380843 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
@@ -86,7 +86,10 @@ interface AudioModule {
@Background coroutineContext: CoroutineContext,
volumeLogger: VolumeLogger,
): AudioSharingRepository =
- if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+ if (
+ (Flags.enableLeAudioSharing() || Flags.audioSharingDeveloperOption()) &&
+ localBluetoothManager != null
+ ) {
AudioSharingRepositoryImpl(
contentResolver,
localBluetoothManager,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt
index 1c80887dd3e8..f6f1e8d22133 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt
@@ -36,7 +36,7 @@ interface AudioSharingModule {
impl: Lazy<AudioSharingInteractorImpl>,
emptyImpl: Lazy<AudioSharingInteractorEmptyImpl>,
): AudioSharingInteractor =
- if (Flags.volumeDialogAudioSharingFix()) {
+ if (Flags.volumeDialogAudioSharingFix() || Flags.audioSharingDeveloperOption()) {
impl.get()
} else {
emptyImpl.get()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
index 6816d35f7699..1963ba22d444 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
@@ -18,14 +18,18 @@ package com.android.systemui.volume.dialog.ringer.ui.binder
import android.view.LayoutInflater
import android.view.View
-import android.view.ViewGroup
import android.widget.ImageButton
import androidx.annotation.LayoutRes
import androidx.compose.ui.util.fastForEachIndexed
+import androidx.constraintlayout.motion.widget.MotionLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import com.android.internal.R as internalR
+import com.android.settingslib.Utils
import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.viewModel
import com.android.systemui.res.R
+import com.android.systemui.util.children
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerButtonViewModel
import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerDrawerState
@@ -33,7 +37,6 @@ import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerViewModel
import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerViewModelState
import com.android.systemui.volume.dialog.ringer.ui.viewmodel.VolumeDialogRingerDrawerViewModel
import javax.inject.Inject
-import kotlin.math.abs
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -44,12 +47,8 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact
fun bind(view: View) {
with(view) {
- val drawerAndRingerContainer =
- requireViewById<View>(R.id.volume_ringer_and_drawer_container)
- val drawerContainer = requireViewById<View>(R.id.volume_drawer_container)
- val selectedButtonView =
- requireViewById<ImageButton>(R.id.volume_new_ringer_active_button)
- val volumeDialogView = requireViewById<ViewGroup>(R.id.volume_dialog)
+ val volumeDialogBackgroundView = requireViewById<View>(R.id.volume_dialog_background)
+ val drawerContainer = requireViewById<MotionLayout>(R.id.volume_ringer_drawer)
repeatWhenAttached {
viewModel(
traceName = "VolumeDialogRingerViewBinder",
@@ -62,46 +61,40 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact
is RingerViewModelState.Available -> {
val uiModel = ringerState.uiModel
- bindSelectedButton(viewModel, uiModel, selectedButtonView)
- bindDrawerButtons(viewModel, uiModel.availableButtons)
+ bindDrawerButtons(viewModel, uiModel)
- // Set up views background and visibility
- drawerAndRingerContainer.visibility = View.VISIBLE
+ // Set up view background and visibility
+ drawerContainer.visibility = View.VISIBLE
when (uiModel.drawerState) {
is RingerDrawerState.Initial -> {
- drawerContainer.visibility = View.GONE
- selectedButtonView.visibility = View.VISIBLE
- volumeDialogView.setBackgroundResource(
+ drawerContainer.closeDrawer(uiModel.currentButtonIndex)
+ volumeDialogBackgroundView.setBackgroundResource(
R.drawable.volume_dialog_background
)
}
-
is RingerDrawerState.Closed -> {
- drawerContainer.visibility = View.GONE
- selectedButtonView.visibility = View.VISIBLE
- volumeDialogView.setBackgroundResource(
+ drawerContainer.closeDrawer(uiModel.currentButtonIndex)
+ volumeDialogBackgroundView.setBackgroundResource(
R.drawable.volume_dialog_background
)
}
-
is RingerDrawerState.Open -> {
- drawerContainer.visibility = View.VISIBLE
- selectedButtonView.visibility = View.GONE
+ // Open drawer
+ drawerContainer.transitionToEnd()
if (
uiModel.currentButtonIndex !=
uiModel.availableButtons.size - 1
) {
- volumeDialogView.setBackgroundResource(
+ volumeDialogBackgroundView.setBackgroundResource(
R.drawable.volume_dialog_background_small_radius
)
}
}
}
}
-
is RingerViewModelState.Unavailable -> {
- drawerAndRingerContainer.visibility = View.GONE
- volumeDialogView.setBackgroundResource(
+ drawerContainer.visibility = View.GONE
+ volumeDialogBackgroundView.setBackgroundResource(
R.drawable.volume_dialog_background
)
}
@@ -115,15 +108,21 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact
private fun View.bindDrawerButtons(
viewModel: VolumeDialogRingerDrawerViewModel,
- availableButtons: List<RingerButtonViewModel?>,
+ uiModel: RingerViewModel,
) {
- val drawerOptions = requireViewById<ViewGroup>(R.id.volume_drawer_options)
- val count = availableButtons.size
- drawerOptions.ensureChildCount(R.layout.volume_ringer_button, count)
+ val drawerContainer = requireViewById<MotionLayout>(R.id.volume_ringer_drawer)
+ val count = uiModel.availableButtons.size
+ drawerContainer.ensureChildCount(R.layout.volume_ringer_button, count)
- availableButtons.fastForEachIndexed { index, ringerButton ->
+ uiModel.availableButtons.fastForEachIndexed { index, ringerButton ->
ringerButton?.let {
- drawerOptions.getChildAt(count - index - 1).bindDrawerButton(it, viewModel)
+ val view = drawerContainer.getChildAt(count - index - 1)
+ // TODO (b/369995871): object animator for button switch ( active <-> inactive )
+ if (index == uiModel.currentButtonIndex) {
+ view.bindDrawerButton(uiModel.selectedButton, viewModel, isSelected = true)
+ } else {
+ view.bindDrawerButton(it, viewModel)
+ }
}
}
}
@@ -131,15 +130,29 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact
private fun View.bindDrawerButton(
buttonViewModel: RingerButtonViewModel,
viewModel: VolumeDialogRingerDrawerViewModel,
+ isSelected: Boolean = false,
) {
with(requireViewById<ImageButton>(R.id.volume_drawer_button)) {
setImageResource(buttonViewModel.imageResId)
contentDescription = context.getString(buttonViewModel.contentDescriptionResId)
- setOnClickListener { viewModel.onRingerButtonClicked(buttonViewModel.ringerMode) }
+ if (isSelected) {
+ setBackgroundResource(R.drawable.volume_drawer_selection_bg)
+ setColorFilter(
+ Utils.getColorAttrDefaultColor(context, internalR.attr.materialColorOnPrimary)
+ )
+ } else {
+ setBackgroundResource(R.drawable.volume_ringer_item_bg)
+ setColorFilter(
+ Utils.getColorAttrDefaultColor(context, internalR.attr.materialColorOnSurface)
+ )
+ }
+ setOnClickListener {
+ viewModel.onRingerButtonClicked(buttonViewModel.ringerMode, isSelected)
+ }
}
}
- private fun ViewGroup.ensureChildCount(@LayoutRes viewLayoutId: Int, count: Int) {
+ private fun MotionLayout.ensureChildCount(@LayoutRes viewLayoutId: Int, count: Int) {
val childCountDelta = childCount - count
when {
childCountDelta > 0 -> {
@@ -147,21 +160,107 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact
}
childCountDelta < 0 -> {
val inflater = LayoutInflater.from(context)
- repeat(abs(childCountDelta)) { inflater.inflate(viewLayoutId, this, true) }
+ repeat(-childCountDelta) {
+ inflater.inflate(viewLayoutId, this, true)
+ getChildAt(childCount - 1).id = View.generateViewId()
+ }
+ cloneConstraintSet(R.id.volume_dialog_ringer_drawer_open)
+ .adjustOpenConstraintsForDrawer(this)
}
}
}
- private fun bindSelectedButton(
- viewModel: VolumeDialogRingerDrawerViewModel,
- uiModel: RingerViewModel,
- selectedButtonView: ImageButton,
+ private fun MotionLayout.closeDrawer(selectedIndex: Int) {
+ cloneConstraintSet(R.id.volume_dialog_ringer_drawer_close)
+ .adjustClosedConstraintsForDrawer(selectedIndex, this)
+ transitionToStart()
+ }
+
+ private fun ConstraintSet.adjustOpenConstraintsForDrawer(motionLayout: MotionLayout) {
+ motionLayout.children.forEachIndexed { index, button ->
+ setButtonPositionConstraints(motionLayout, index, button)
+ setAlpha(button.id, 1.0F)
+ constrainWidth(
+ button.id,
+ motionLayout.context.resources.getDimensionPixelSize(
+ R.dimen.volume_dialog_ringer_drawer_button_size
+ ),
+ )
+ constrainHeight(
+ button.id,
+ motionLayout.context.resources.getDimensionPixelSize(
+ R.dimen.volume_dialog_ringer_drawer_button_size
+ ),
+ )
+ if (index != motionLayout.childCount - 1) {
+ setMargin(
+ button.id,
+ ConstraintSet.BOTTOM,
+ motionLayout.context.resources.getDimensionPixelSize(
+ R.dimen.volume_dialog_components_spacing
+ ),
+ )
+ }
+ }
+ motionLayout.updateState(R.id.volume_dialog_ringer_drawer_open, this)
+ }
+
+ private fun ConstraintSet.adjustClosedConstraintsForDrawer(
+ selectedIndex: Int,
+ motionLayout: MotionLayout,
) {
- with(uiModel) {
- selectedButtonView.setImageResource(selectedButton.imageResId)
- selectedButtonView.setOnClickListener {
- viewModel.onRingerButtonClicked(selectedButton.ringerMode)
+ motionLayout.children.forEachIndexed { index, button ->
+ setButtonPositionConstraints(motionLayout, index, button)
+ constrainWidth(
+ button.id,
+ motionLayout.context.resources.getDimensionPixelSize(
+ R.dimen.volume_dialog_ringer_drawer_button_size
+ ),
+ )
+ if (selectedIndex != motionLayout.childCount - index - 1) {
+ setAlpha(button.id, 0.0F)
+ constrainHeight(button.id, 0)
+ setMargin(button.id, ConstraintSet.BOTTOM, 0)
+ } else {
+ setAlpha(button.id, 1.0F)
+ constrainHeight(
+ button.id,
+ motionLayout.context.resources.getDimensionPixelSize(
+ R.dimen.volume_dialog_ringer_drawer_button_size
+ ),
+ )
}
}
+ motionLayout.updateState(R.id.volume_dialog_ringer_drawer_close, this)
+ }
+
+ private fun ConstraintSet.setButtonPositionConstraints(
+ motionLayout: MotionLayout,
+ index: Int,
+ button: View,
+ ) {
+ if (motionLayout.getChildAt(index - 1) == null) {
+ connect(button.id, ConstraintSet.TOP, motionLayout.id, ConstraintSet.TOP)
+ } else {
+ connect(
+ button.id,
+ ConstraintSet.TOP,
+ motionLayout.getChildAt(index - 1).id,
+ ConstraintSet.BOTTOM,
+ )
+ }
+
+ if (motionLayout.getChildAt(index + 1) == null) {
+ connect(button.id, ConstraintSet.BOTTOM, motionLayout.id, ConstraintSet.BOTTOM)
+ } else {
+ connect(
+ button.id,
+ ConstraintSet.BOTTOM,
+ motionLayout.getChildAt(index + 1).id,
+ ConstraintSet.TOP,
+ )
+ }
+ connect(button.id, ConstraintSet.START, motionLayout.id, ConstraintSet.START)
+ connect(button.id, ConstraintSet.END, motionLayout.id, ConstraintSet.END)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
index e040638324ac..624dcc71e2a9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
@@ -84,8 +84,8 @@ constructor(
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build()
- fun onRingerButtonClicked(ringerMode: RingerMode) {
- if (drawerState.value is RingerDrawerState.Open) {
+ fun onRingerButtonClicked(ringerMode: RingerMode, isSelectedButton: Boolean = false) {
+ if (drawerState.value is RingerDrawerState.Open && !isSelectedButton) {
Events.writeEvent(Events.EVENT_RINGER_TOGGLE, ringerMode.value)
provideTouchFeedback(ringerMode)
maybeShowToast(ringerMode)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
index 538ee47915a8..772ae7736cad 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
@@ -17,6 +17,7 @@
package com.android.systemui.volume.dialog.sliders.dagger
import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
+import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderTouchesViewBinder
import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder
import dagger.BindsInstance
import dagger.Subcomponent
@@ -31,6 +32,8 @@ interface VolumeDialogSliderComponent {
fun sliderViewBinder(): VolumeDialogSliderViewBinder
+ fun sliderTouchesViewBinder(): VolumeDialogSliderTouchesViewBinder
+
@Subcomponent.Factory
interface Factory {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt
new file mode 100644
index 000000000000..adc2383c3a46
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.data.repository
+
+import android.annotation.SuppressLint
+import android.view.MotionEvent
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+@VolumeDialogSliderScope
+class VolumeDialogSliderTouchEventsRepository @Inject constructor() {
+
+ @SuppressLint("SharedFlowCreation")
+ private val mutableSliderTouchEvents: MutableStateFlow<MotionEvent?> = MutableStateFlow(null)
+ val sliderTouchEvent: Flow<MotionEvent> = mutableSliderTouchEvents.filterNotNull()
+
+ fun update(event: MotionEvent) {
+ mutableSliderTouchEvents.tryEmit(MotionEvent.obtain(event))
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractor.kt
new file mode 100644
index 000000000000..c7b4184a9f2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractor.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.domain.interactor
+
+import android.view.MotionEvent
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogCallbacksInteractor
+import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
+import com.android.systemui.volume.dialog.sliders.data.repository.VolumeDialogSliderTouchEventsRepository
+import com.android.systemui.volume.dialog.sliders.shared.model.SliderInputEvent
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
+
+@VolumeDialogSliderScope
+class VolumeDialogSliderInputEventsInteractor
+@Inject
+constructor(
+ @VolumeDialog coroutineScope: CoroutineScope,
+ volumeDialogCallbacksInteractor: VolumeDialogCallbacksInteractor,
+ private val visibilityInteractor: VolumeDialogVisibilityInteractor,
+ private val repository: VolumeDialogSliderTouchEventsRepository,
+) {
+
+ val event: Flow<SliderInputEvent> =
+ merge(
+ repository.sliderTouchEvent.map { SliderInputEvent.Touch(it) },
+ volumeDialogCallbacksInteractor.event
+ .filterIsInstance(VolumeDialogEventModel.VolumeChangedFromKey::class)
+ .map { SliderInputEvent.Button },
+ )
+
+ init {
+ event.onEach { visibilityInteractor.resetDismissTimeout() }.launchIn(coroutineScope)
+ }
+
+ fun onTouchEvent(newEvent: MotionEvent) {
+ repository.update(newEvent)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
index 7af4258930cb..c904ac5e3ae1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
@@ -35,6 +35,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.runningReduce
import kotlinx.coroutines.flow.stateIn
private const val DEFAULT_STREAM = AudioManager.STREAM_MUSIC
@@ -54,13 +55,17 @@ constructor(
volumeDialogStateInteractor.volumeDialogState
.filter { it.streamModels.isNotEmpty() }
.map { stateModel ->
- stateModel.streamModels.values
- .filter { streamModel -> shouldShowSliders(stateModel, streamModel) }
- .sortedWith(streamsSorter)
+ val sliderTypes =
+ stateModel.streamModels.values
+ .filter { streamModel -> shouldShowSliders(stateModel, streamModel) }
+ .sortedWith(streamsSorter)
+ .map { model -> model.toType() }
+ LinkedHashSet(sliderTypes)
}
- .map { models ->
- val sliderTypes: List<VolumeDialogSliderType> =
- models.map { model -> model.toType() }
+ .runningReduce { sliderTypes, newSliderTypes ->
+ newSliderTypes.apply { addAll(sliderTypes) }
+ }
+ .map { sliderTypes ->
VolumeDialogSlidersModel(
slider = sliderTypes.first(),
floatingSliders = sliderTypes.drop(1),
@@ -84,7 +89,7 @@ constructor(
// Always show the stream for audio sharing if it exists.
if (
- Flags.volumeDialogAudioSharingFix() &&
+ (Flags.volumeDialogAudioSharingFix() || Flags.audioSharingDeveloperOption()) &&
streamModel.stream == VolumeDialogControllerImpl.DYNAMIC_STREAM_BROADCAST
) {
return true
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/shared/model/SliderInputEvent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/shared/model/SliderInputEvent.kt
new file mode 100644
index 000000000000..37dbb4b3a81d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/shared/model/SliderInputEvent.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.shared.model
+
+import android.view.MotionEvent
+
+/** Models input event happened on the Volume Slider */
+sealed interface SliderInputEvent {
+
+ data class Touch(val event: MotionEvent) : SliderInputEvent
+
+ data object Button : SliderInputEvent
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
new file mode 100644
index 000000000000..7fd177d55d76
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.ui
+
+import android.annotation.SuppressLint
+import android.view.View
+import com.android.systemui.lifecycle.WindowLifecycleState
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.lifecycle.viewModel
+import com.android.systemui.res.R
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderTouchesViewModel
+import com.google.android.material.slider.Slider
+import javax.inject.Inject
+
+@VolumeDialogSliderScope
+class VolumeDialogSliderTouchesViewBinder
+@Inject
+constructor(private val viewModelFactory: VolumeDialogSliderTouchesViewModel.Factory) {
+
+ @SuppressLint("ClickableViewAccessibility")
+ fun bind(view: View) {
+ with(view.requireViewById<Slider>(R.id.volume_dialog_slider)) {
+ repeatWhenAttached {
+ viewModel(
+ traceName = "VolumeDialogSliderTouchesViewBinder",
+ minWindowLifecycleState = WindowLifecycleState.ATTACHED,
+ factory = { viewModelFactory.create() },
+ ) { viewModel ->
+ setOnTouchListener { _, event ->
+ viewModel.onTouchEvent(event)
+ false
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
index a17c1e541b5e..1b2b4fff5b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
@@ -26,6 +26,7 @@ import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.viewModel
import com.android.systemui.res.R
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSlidersViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.launchIn
@@ -38,9 +39,10 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory)
fun bind(view: View) {
with(view) {
- val volumeDialog: View = requireViewById(R.id.volume_dialog)
val floatingSlidersContainer: ViewGroup =
requireViewById(R.id.volume_dialog_floating_sliders_container)
+ val mainSliderContainer: View =
+ requireViewById(R.id.volume_dialog_main_slider_container)
repeatWhenAttached {
viewModel(
traceName = "VolumeDialogSlidersViewBinder",
@@ -49,7 +51,7 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory)
) { viewModel ->
viewModel.sliders
.onEach { uiModel ->
- uiModel.sliderComponent.sliderViewBinder().bind(volumeDialog)
+ uiModel.sliderComponent.bindSlider(mainSliderContainer)
val floatingSliderViewBinders = uiModel.floatingSliderComponent
floatingSlidersContainer.ensureChildCount(
@@ -57,9 +59,9 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory)
count = floatingSliderViewBinders.size,
)
floatingSliderViewBinders.fastForEachIndexed { index, sliderComponent ->
- sliderComponent
- .sliderViewBinder()
- .bind(floatingSlidersContainer.getChildAt(index))
+ sliderComponent.bindSlider(
+ floatingSlidersContainer.getChildAt(index)
+ )
}
}
.launchIn(this)
@@ -67,6 +69,11 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory)
}
}
}
+
+ private fun VolumeDialogSliderComponent.bindSlider(sliderContainer: View) {
+ sliderViewBinder().bind(sliderContainer)
+ sliderTouchesViewBinder().bind(sliderContainer)
+ }
}
private fun ViewGroup.ensureChildCount(@LayoutRes viewLayoutId: Int, count: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
new file mode 100644
index 000000000000..144c75da2b2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.ui.viewmodel
+
+import android.view.MotionEvent
+import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInputEventsInteractor
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+class VolumeDialogSliderTouchesViewModel
+@AssistedInject
+constructor(private val interactor: VolumeDialogSliderInputEventsInteractor) {
+
+ fun onTouchEvent(event: MotionEvent) {
+ interactor.onTouchEvent(event)
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): VolumeDialogSliderTouchesViewModel
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index d9a945cfedfd..f6c1743a4bea 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -19,13 +19,11 @@ package com.android.systemui.volume.dialog.ui.binder
import android.app.Dialog
import android.graphics.Rect
import android.graphics.Region
-import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.InternalInsetsInfo
-import android.widget.FrameLayout
-import androidx.annotation.GravityInt
+import androidx.constraintlayout.motion.widget.MotionLayout
import com.android.internal.view.RotationPolicy
import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -41,7 +39,6 @@ import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBind
import com.android.systemui.volume.dialog.ui.VolumeDialogResources
import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
-import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
import com.android.systemui.volume.dialog.utils.VolumeTracer
import javax.inject.Inject
@@ -53,6 +50,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
@@ -63,7 +61,6 @@ class VolumeDialogViewBinder
@Inject
constructor(
private val volumeResources: VolumeDialogResources,
- private val gravityViewModel: VolumeDialogGravityViewModel,
private val dialogViewModelFactory: VolumeDialogViewModel.Factory,
private val jankListenerFactory: JankListenerFactory,
private val tracer: VolumeTracer,
@@ -74,21 +71,23 @@ constructor(
fun bind(dialog: Dialog) {
// Root view of the Volume Dialog.
- val root: ViewGroup = dialog.requireViewById(R.id.volume_dialog_root)
- // Volume Dialog container view that contains the dialog itself without the floating sliders
- val container: View = root.requireViewById(R.id.volume_dialog_container)
- container.alpha = 0f
- container.repeatWhenAttached {
+ val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog_root)
+ root.alpha = 0f
+ root.repeatWhenAttached {
root.viewModel(
traceName = "VolumeDialogViewBinder",
minWindowLifecycleState = WindowLifecycleState.ATTACHED,
factory = { dialogViewModelFactory.create() },
) { viewModel ->
- animateVisibility(container, dialog, viewModel.dialogVisibilityModel)
+ animateVisibility(root, dialog, viewModel.dialogVisibilityModel)
viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this)
- gravityViewModel.dialogGravity
- .onEach { container.setLayoutGravity(it) }
+ viewModel.motionState
+ .scan(0) { acc, motionState ->
+ // don't animate the initial state
+ root.transitionToState(motionState, animate = acc != 0)
+ acc + 1
+ }
.launchIn(this)
launch { root.viewTreeObserver.computeInternalInsetsListener(root) }
@@ -130,15 +129,13 @@ constructor(
.launchIn(this)
}
- private suspend fun calculateTranslationX(view: View): Float? {
+ private fun calculateTranslationX(view: View): Float? {
return if (view.display.rotation == RotationPolicy.NATURAL_ROTATION) {
- val dialogGravity = gravityViewModel.dialogGravity.first()
- val isGravityLeft = (dialogGravity and Gravity.LEFT) == Gravity.LEFT
- if (isGravityLeft) {
+ if (view.isLayoutRtl) {
-1
} else {
1
- } * view.width / 2.0f
+ } * view.width / 2f
} else {
null
}
@@ -211,10 +208,11 @@ constructor(
getBoundsInWindow(boundsRect, false)
}
- private fun View.setLayoutGravity(@GravityInt newGravity: Int) {
- val frameLayoutParams =
- layoutParams as? FrameLayout.LayoutParams
- ?: error("View must be a child of a FrameLayout")
- layoutParams = frameLayoutParams.apply { gravity = newGravity }
+ private fun MotionLayout.transitionToState(newState: Int, animate: Boolean) {
+ if (animate) {
+ transitionToState(newState)
+ } else {
+ jumpToState(newState)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt
deleted file mode 100644
index 112afb1debf5..000000000000
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2024 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.volume.dialog.ui.viewmodel
-
-import android.content.Context
-import android.content.res.Configuration
-import android.view.Gravity
-import androidx.annotation.GravityInt
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.UiBackground
-import com.android.systemui.res.R
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.DevicePostureController
-import com.android.systemui.statusbar.policy.devicePosture
-import com.android.systemui.statusbar.policy.onConfigChanged
-import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
-import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
-import javax.inject.Inject
-import kotlin.coroutines.CoroutineContext
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.withContext
-
-/** Exposes dialog [GravityInt] for use in the UI layer. */
-@VolumeDialogScope
-class VolumeDialogGravityViewModel
-@Inject
-constructor(
- @Application private val context: Context,
- @VolumeDialog private val coroutineScope: CoroutineScope,
- @UiBackground private val uiBackgroundCoroutineContext: CoroutineContext,
- configurationController: ConfigurationController,
- private val devicePostureController: DevicePostureController,
-) {
-
- @GravityInt private var originalGravity: Int = context.getAbsoluteGravity()
-
- val dialogGravity: Flow<Int> =
- combine(
- devicePostureController.devicePosture(),
- configurationController.onConfigChanged.onEach { onConfigurationChanged() },
- ) { devicePosture, configuration ->
- context.calculateGravity(devicePosture, configuration)
- }
- .stateIn(
- scope = coroutineScope,
- started = SharingStarted.Eagerly,
- context.calculateGravity(),
- )
-
- private suspend fun onConfigurationChanged() {
- withContext(uiBackgroundCoroutineContext) { originalGravity = context.getAbsoluteGravity() }
- }
-
- @GravityInt
- private fun Context.calculateGravity(
- devicePosture: Int = devicePostureController.devicePosture,
- config: Configuration = resources.configuration,
- ): Int {
- val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE
- val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED
- val gravity =
- if (isLandscape && isHalfOpen) {
- originalGravity or Gravity.TOP
- } else {
- originalGravity
- }
- return getAbsoluteGravity(gravity)
- }
-}
-
-@GravityInt
-private fun Context.getAbsoluteGravity(
- gravity: Int = resources.getInteger(R.integer.volume_dialog_gravity)
-): Int = with(resources) { Gravity.getAbsoluteGravity(gravity, configuration.layoutDirection) }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
index 869a6a2e87d5..0352799916bc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
@@ -17,7 +17,12 @@
package com.android.systemui.volume.dialog.ui.viewmodel
import android.content.Context
+import android.content.res.Configuration
import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.statusbar.policy.devicePosture
+import com.android.systemui.statusbar.policy.onConfigChanged
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
@@ -32,6 +37,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
/** Provides a state for the Volume Dialog. */
@OptIn(ExperimentalCoroutinesApi::class)
@@ -42,8 +48,23 @@ constructor(
dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
volumeDialogSlidersInteractor: VolumeDialogSlidersInteractor,
volumeDialogStateInteractor: VolumeDialogStateInteractor,
+ devicePostureController: DevicePostureController,
+ configurationController: ConfigurationController,
) {
+ val motionState: Flow<Int> =
+ combine(
+ devicePostureController.devicePosture(),
+ configurationController.onConfigChanged.onStart {
+ emit(context.resources.configuration)
+ },
+ ) { devicePosture, configuration ->
+ if (shouldOffsetVolumeDialog(devicePosture, configuration)) {
+ R.id.volume_dialog_half_folded_constraint_set
+ } else {
+ R.id.volume_dialog_constraint_set
+ }
+ }
val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> =
dialogVisibilityInteractor.dialogVisibility
val dialogTitle: Flow<String> =
@@ -57,6 +78,13 @@ constructor(
}
.filterNotNull()
+ /** @return true when the foldable device screen curve is in the way of the volume dialog */
+ private fun shouldOffsetVolumeDialog(devicePosture: Int, config: Configuration): Boolean {
+ val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE
+ val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED
+ return isLandscape && isHalfOpen
+ }
+
@AssistedFactory
interface Factory {
fun create(): VolumeDialogViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
index 293be94638db..7da041e7ef19 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
@@ -17,8 +17,12 @@
package com.android.systemui.volume.domain.interactor
import android.bluetooth.BluetoothCsipSetCoordinator
+import android.content.Context
import android.media.AudioManager.STREAM_MUSIC
import androidx.annotation.IntRange
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.flags.Flags
import com.android.settingslib.volume.data.repository.AudioSharingRepository
import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MAX
import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MIN
@@ -38,7 +42,6 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
interface AudioSharingInteractor {
@@ -54,6 +57,8 @@ interface AudioSharingInteractor {
/** Audio sharing secondary headset max volume. */
val volumeMax: Int
+ suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean
+
/** Set the volume of the secondary headset in audio sharing. */
fun setStreamVolume(
@IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
@@ -78,7 +83,7 @@ constructor(
@Application private val coroutineScope: CoroutineScope,
@Background private val backgroundCoroutineContext: CoroutineContext,
private val audioVolumeInteractor: AudioVolumeInteractor,
- private val audioSharingRepository: AudioSharingRepository
+ private val audioSharingRepository: AudioSharingRepository,
) : AudioSharingInteractor {
override val isInAudioSharing: Flow<Boolean> = audioSharingRepository.inAudioSharing
@@ -95,6 +100,12 @@ constructor(
override val volumeMax: Int = AUDIO_SHARING_VOLUME_MAX
+ override suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean =
+ withContext(backgroundCoroutineContext) {
+ (Flags.volumeDialogAudioSharingFix() && BluetoothUtils.isAudioSharingEnabled()) ||
+ BluetoothUtils.isAudioSharingPreviewEnabled(context.contentResolver)
+ }
+
override fun setStreamVolume(
@IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
level: Int
@@ -141,6 +152,9 @@ class AudioSharingInteractorEmptyImpl @Inject constructor() : AudioSharingIntera
override val volumeMin: Int = EMPTY_VOLUME
override val volumeMax: Int = EMPTY_VOLUME
+ override suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean =
+ false
+
override fun setStreamVolume(
@IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
level: Int
diff --git a/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt b/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
index d6b159e9b13a..3847df66c7f7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
@@ -41,7 +41,7 @@ class VolumeLogger @Inject constructor(@VolumeLog private val logBuffer: LogBuff
str1 = audioStream.toString()
int1 = volume
},
- { "Set volume: stream=$str1 volume=$int1" }
+ { "Set volume: stream=$str1 volume=$int1" },
)
}
@@ -53,7 +53,7 @@ class VolumeLogger @Inject constructor(@VolumeLog private val logBuffer: LogBuff
str1 = audioStream.toString()
int1 = model.volume
},
- { "Volume update received: stream=$str1 volume=$int1" }
+ { "Volume update received: stream=$str1 volume=$int1" },
)
}
@@ -62,7 +62,7 @@ class VolumeLogger @Inject constructor(@VolumeLog private val logBuffer: LogBuff
TAG,
LogLevel.DEBUG,
{ bool1 = state },
- { "Audio sharing state update: state=$bool1" }
+ { "Audio sharing state update: state=$bool1" },
)
}
@@ -71,7 +71,7 @@ class VolumeLogger @Inject constructor(@VolumeLog private val logBuffer: LogBuff
TAG,
LogLevel.DEBUG,
{ int1 = groupId },
- { "Secondary group id in audio sharing update: groupId=$int1" }
+ { "Secondary group id in audio sharing update: groupId=$int1" },
)
}
@@ -80,11 +80,23 @@ class VolumeLogger @Inject constructor(@VolumeLog private val logBuffer: LogBuff
TAG,
LogLevel.DEBUG,
{ str1 = map.toString() },
- { "Volume map update: map=$str1" }
+ { "Volume map update: map=$str1" },
)
}
override fun onSetDeviceVolumeRequested(volume: Int) {
logBuffer.log(TAG, LogLevel.DEBUG, { int1 = volume }, { "Set device volume: volume=$int1" })
}
+
+ override fun onAudioSharingAvailabilityRequestedError(requestFrom: String, e: String) {
+ logBuffer.log(
+ TAG,
+ LogLevel.WARNING,
+ {
+ str1 = requestFrom
+ str1 = e
+ },
+ { "$str1, fail to check audio sharing availability: e=$str2" },
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 65b62737b692..2aa6e7b18154 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -105,8 +105,7 @@ class ClockEventControllerTest : SysuiTestCase() {
private val mainExecutor = ImmediateExecutor()
private lateinit var repository: FakeKeyguardRepository
- private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG)
- private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer)
+ private val clockBuffers = ClockMessageBuffers(LogcatOnlyMessageBuffer(LogLevel.DEBUG))
private lateinit var underTest: ClockEventController
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 1ceac78af1a2..aa95abb3528f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -168,8 +168,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void showFullscreenModeButton_addViewAndSetImageResource() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
- verify(mSpyImageView).setImageResource(
- getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
+ verify(mSpyImageView).setImageResource(getIconResId());
assertEquals(mSpyImageView, mWindowManager.getAttachedView());
assertShowFadingAnimation(FADE_IN_ALPHA);
assertShowFadingAnimation(FADE_OUT_ALPHA);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
index a940bc9b3e20..4aaa82e4a16d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
@@ -16,10 +16,12 @@ import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationTarget
import android.view.SurfaceControl
import android.view.ViewGroup
+import android.view.WindowManager.TRANSIT_NONE
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.window.RemoteTransition
import android.window.TransitionFilter
+import android.window.WindowAnimationState
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -34,6 +36,10 @@ import junit.framework.Assert.assertTrue
import junit.framework.AssertionFailedError
import kotlin.concurrent.thread
import kotlin.test.assertEquals
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
import org.junit.After
import org.junit.Assert.assertThrows
import org.junit.Before
@@ -258,7 +264,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() {
@DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED)
@Test
fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() {
-
val controller =
object : DelegateTransitionAnimatorController(controller) {
override val transitionCookie =
@@ -273,7 +278,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() {
@EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED)
@Test
fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() {
-
// No TransitionCookie
val controllerWithoutCookie =
object : DelegateTransitionAnimatorController(controller) {
@@ -348,7 +352,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() {
fun doesNotStartIfAnimationIsCancelled() {
val runner = activityTransitionAnimator.createRunner(controller)
runner.onAnimationCancelled()
- runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
+ runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback)
waitForIdleSync()
verify(controller).onTransitionAnimationCancelled()
@@ -361,7 +365,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() {
@Test
fun cancelsIfNoOpeningWindowIsFound() {
val runner = activityTransitionAnimator.createRunner(controller)
- runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
+ runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback)
waitForIdleSync()
verify(controller).onTransitionAnimationCancelled()
@@ -374,7 +378,13 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() {
@Test
fun startsAnimationIfWindowIsOpening() {
val runner = activityTransitionAnimator.createRunner(controller)
- runner.onAnimationStart(0, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback)
+ runner.onAnimationStart(
+ TRANSIT_NONE,
+ arrayOf(fakeWindow()),
+ emptyArray(),
+ emptyArray(),
+ iCallback,
+ )
waitForIdleSync()
verify(listener).onTransitionAnimationStart()
verify(controller).onTransitionAnimationStart(anyBoolean())
@@ -387,6 +397,113 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() {
}
}
+ @DisableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
+ @Test
+ fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() {
+ assertThrows(IllegalStateException::class.java) {
+ activityTransitionAnimator.createRunner(controller, longLived = true)
+ }
+ }
+
+ @EnableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
+ @Test
+ fun runnerCreatesDelegateLazily_whenPostingTimeouts() {
+ val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
+ assertNull(runner.delegate)
+ runner.postTimeouts()
+ assertNotNull(runner.delegate)
+ }
+
+ @EnableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
+ @Test
+ fun runnerCreatesDelegateLazily_onAnimationStart() {
+ val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
+ assertNull(runner.delegate)
+
+ // The delegate is cleaned up after execution (which happens in another thread), so what we
+ // do instead is check if it becomes non-null at any point with a 1 second timeout. This
+ // will tell us that takeOverWithAnimation() triggered the lazy initialization.
+ var delegateInitialized = false
+ runBlocking {
+ val initChecker = launch {
+ withTimeout(1.seconds) {
+ while (runner.delegate == null) continue
+ delegateInitialized = true
+ }
+ }
+ runner.onAnimationStart(
+ TRANSIT_NONE,
+ arrayOf(fakeWindow()),
+ emptyArray(),
+ emptyArray(),
+ iCallback,
+ )
+ initChecker.join()
+ }
+ assertTrue(delegateInitialized)
+ }
+
+ @EnableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
+ @Test
+ fun runnerCreatesDelegateLazily_onAnimationTakeover() {
+ val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
+ assertNull(runner.delegate)
+
+ // The delegate is cleaned up after execution (which happens in another thread), so what we
+ // do instead is check if it becomes non-null at any point with a 1 second timeout. This
+ // will tell us that takeOverWithAnimation() triggered the lazy initialization.
+ var delegateInitialized = false
+ runBlocking {
+ val initChecker = launch {
+ withTimeout(1.seconds) {
+ while (runner.delegate == null) continue
+ delegateInitialized = true
+ }
+ }
+ runner.takeOverAnimation(
+ arrayOf(fakeWindow()),
+ arrayOf(WindowAnimationState()),
+ SurfaceControl.Transaction(),
+ iCallback,
+ )
+ initChecker.join()
+ }
+ assertTrue(delegateInitialized)
+ }
+
+ @DisableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
+ @Test
+ fun animationTakeoverThrows_whenTheFlagsAreDisabled() {
+ val runner = activityTransitionAnimator.createRunner(controller, longLived = false)
+ assertThrows(IllegalStateException::class.java) {
+ runner.takeOverAnimation(
+ arrayOf(fakeWindow()),
+ emptyArray(),
+ SurfaceControl.Transaction(),
+ iCallback,
+ )
+ }
+ }
+
+ @DisableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
@Test
fun disposeRunner_delegateDereferenced() {
val runner = activityTransitionAnimator.createRunner(controller)
@@ -409,7 +526,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() {
false,
Rect(),
Rect(),
- 0,
+ 1,
Point(),
Rect(),
bounds,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
index ec42b7fc4713..97abba7a4bcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
@@ -31,8 +31,8 @@ import org.junit.runner.RunWith
@SmallTest
class FontInterpolatorTest : SysuiTestCase() {
- private val sFont = TextRunShaper.shapeTextRun("A", 0, 1, 0, 1, 0f, 0f, false, Paint())
- .getFont(0)
+ private val sFont =
+ TextRunShaper.shapeTextRun("A", 0, 1, 0, 1, 0f, 0f, false, Paint()).getFont(0)
private fun assertSameAxes(expect: Font, actual: Font) {
val expectAxes = expect.axes?.also { it.sortBy { axis -> axis.tag } }
@@ -42,21 +42,20 @@ class FontInterpolatorTest : SysuiTestCase() {
private fun assertSameAxes(expectVarSettings: String, actual: Font) {
- val expectAxes = FontVariationAxis.fromFontVariationSettings(expectVarSettings)?.also {
- it.sortBy { axis -> axis.tag }
- }
+ val expectAxes =
+ FontVariationAxis.fromFontVariationSettings(expectVarSettings)?.also {
+ it.sortBy { axis -> axis.tag }
+ }
val actualAxes = actual.axes?.also { it.sortBy { axis -> axis.tag } }
assertThat(actualAxes).isEqualTo(expectAxes)
}
@Test
fun textInterpolation() {
- val startFont = Font.Builder(sFont)
- .setFontVariationSettings("'wght' 100, 'ital' 0, 'GRAD' 200")
- .build()
- val endFont = Font.Builder(sFont)
- .setFontVariationSettings("'wght' 900, 'ital' 1, 'GRAD' 700")
- .build()
+ val startFont =
+ Font.Builder(sFont).setFontVariationSettings("'wght' 100, 'ital' 0, 'GRAD' 200").build()
+ val endFont =
+ Font.Builder(sFont).setFontVariationSettings("'wght' 900, 'ital' 1, 'GRAD' 700").build()
val interp = FontInterpolator()
assertSameAxes(startFont, interp.lerp(startFont, endFont, 0f))
@@ -66,12 +65,8 @@ class FontInterpolatorTest : SysuiTestCase() {
@Test
fun textInterpolation_DefaultValue() {
- val startFont = Font.Builder(sFont)
- .setFontVariationSettings("'wght' 100")
- .build()
- val endFont = Font.Builder(sFont)
- .setFontVariationSettings("'ital' 1")
- .build()
+ val startFont = Font.Builder(sFont).setFontVariationSettings("'wght' 100").build()
+ val endFont = Font.Builder(sFont).setFontVariationSettings("'ital' 1").build()
val interp = FontInterpolator()
assertSameAxes("'wght' 250, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
@@ -79,12 +74,8 @@ class FontInterpolatorTest : SysuiTestCase() {
@Test
fun testInterpCache() {
- val startFont = Font.Builder(sFont)
- .setFontVariationSettings("'wght' 100")
- .build()
- val endFont = Font.Builder(sFont)
- .setFontVariationSettings("'ital' 1")
- .build()
+ val startFont = Font.Builder(sFont).setFontVariationSettings("'wght' 100").build()
+ val endFont = Font.Builder(sFont).setFontVariationSettings("'ital' 1").build()
val interp = FontInterpolator()
val resultFont = interp.lerp(startFont, endFont, 0.5f)
@@ -94,12 +85,8 @@ class FontInterpolatorTest : SysuiTestCase() {
@Test
fun testAxesCache() {
- val startFont = Font.Builder(sFont)
- .setFontVariationSettings("'wght' 100")
- .build()
- val endFont = Font.Builder(sFont)
- .setFontVariationSettings("'ital' 1")
- .build()
+ val startFont = Font.Builder(sFont).setFontVariationSettings("'wght' 100").build()
+ val endFont = Font.Builder(sFont).setFontVariationSettings("'ital' 1").build()
val interp = FontInterpolator()
val resultFont = interp.lerp(startFont, endFont, 0.5f)
@@ -111,20 +98,12 @@ class FontInterpolatorTest : SysuiTestCase() {
fun testCacheMaxSize() {
val interp = FontInterpolator()
- val startFont = Font.Builder(sFont)
- .setFontVariationSettings("'wght' 100")
- .build()
- val endFont = Font.Builder(sFont)
- .setFontVariationSettings("'wght' 1")
- .build()
+ val startFont = Font.Builder(sFont).setFontVariationSettings("'wght' 100").build()
+ val endFont = Font.Builder(sFont).setFontVariationSettings("'wght' 1").build()
val resultFont = interp.lerp(startFont, endFont, 0.5f)
- for (i in 0..interp.cacheMaxEntries + 1) {
- val f1 = Font.Builder(sFont)
- .setFontVariationSettings("'wght' ${i * 100}")
- .build()
- val f2 = Font.Builder(sFont)
- .setFontVariationSettings("'wght' $i")
- .build()
+ for (i in 0..(interp.fontCache as FontCacheImpl).cacheMaxEntries + 1) {
+ val f1 = Font.Builder(sFont).setFontVariationSettings("'wght' ${i * 100}").build()
+ val f2 = Font.Builder(sFont).setFontVariationSettings("'wght' $i").build()
interp.lerp(f1, f2, 0.5f)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
index 6ba171525bd1..dcf38800bb01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
@@ -42,6 +42,8 @@ import org.mockito.Mockito.`when`
@SmallTest
class TextAnimatorTest : SysuiTestCase() {
+ private val typeface = Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf")
+
private fun makeLayout(text: String, paint: TextPaint): Layout {
val width = ceil(Layout.getDesiredWidth(text, 0, text.length, paint)).toInt()
return StaticLayout.Builder.obtain(text, 0, text.length, paint, width).build()
@@ -56,7 +58,7 @@ class TextAnimatorTest : SysuiTestCase() {
`when`(textInterpolator.targetPaint).thenReturn(paint)
val textAnimator =
- TextAnimator(layout, null, {}).apply {
+ TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
this.animator = valueAnimator
}
@@ -86,7 +88,7 @@ class TextAnimatorTest : SysuiTestCase() {
`when`(textInterpolator.targetPaint).thenReturn(paint)
val textAnimator =
- TextAnimator(layout, null, {}).apply {
+ TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
this.animator = valueAnimator
}
@@ -114,7 +116,7 @@ class TextAnimatorTest : SysuiTestCase() {
val animationEndCallback = mock(Runnable::class.java)
val textAnimator =
- TextAnimator(layout, null, {}).apply {
+ TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
this.animator = valueAnimator
}
@@ -122,7 +124,7 @@ class TextAnimatorTest : SysuiTestCase() {
textAnimator.setTextStyle(
weight = 400,
animate = true,
- onAnimationEnd = animationEndCallback
+ onAnimationEnd = animationEndCallback,
)
// Verify animationEnd callback has been added.
@@ -140,14 +142,11 @@ class TextAnimatorTest : SysuiTestCase() {
val layout = makeLayout("Hello, World", PAINT)
val valueAnimator = mock(ValueAnimator::class.java)
val textInterpolator = mock(TextInterpolator::class.java)
- val paint =
- TextPaint().apply {
- typeface = Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf")
- }
+ val paint = TextPaint().apply { this.typeface = typeface }
`when`(textInterpolator.targetPaint).thenReturn(paint)
val textAnimator =
- TextAnimator(layout, null, {}).apply {
+ TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
this.animator = valueAnimator
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
index cca5f3525ef6..c6fbe3fcd301 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
@@ -31,11 +31,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import kotlin.math.ceil
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import java.io.File
-import kotlin.math.ceil
private const val TEXT = "Hello, World."
private const val BIDI_TEXT = "abc\u05D0\u05D1\u05D2"
@@ -47,20 +47,23 @@ private const val BMP_HEIGHT = 300
private val VF_FONT = Font.Builder(File("/system/fonts/Roboto-Regular.ttf")).build()
private fun Font.toTypeface() =
- Typeface.CustomFallbackBuilder(FontFamily.Builder(this).build()).build()
+ Typeface.CustomFallbackBuilder(FontFamily.Builder(this).build()).build()
-internal val PAINT = TextPaint().apply {
- typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 400").build().toTypeface()
- textSize = 32f
-}
+internal val PAINT =
+ TextPaint().apply {
+ typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 400").build().toTypeface()
+ textSize = 32f
+ }
-private val START_PAINT = TextPaint(PAINT).apply {
- typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 400").build().toTypeface()
-}
+private val START_PAINT =
+ TextPaint(PAINT).apply {
+ typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 400").build().toTypeface()
+ }
-private val END_PAINT = TextPaint(PAINT).apply {
- typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 700").build().toTypeface()
-}
+private val END_PAINT =
+ TextPaint(PAINT).apply {
+ typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 700").build().toTypeface()
+ }
@RunWith(AndroidJUnit4::class)
@SmallTest
@@ -70,16 +73,17 @@ class TextInterpolatorTest : SysuiTestCase() {
private fun makeLayout(
text: String,
paint: TextPaint,
- dir: TextDirectionHeuristic = TextDirectionHeuristics.LTR
+ dir: TextDirectionHeuristic = TextDirectionHeuristics.LTR,
): Layout {
val width = ceil(Layout.getDesiredWidth(text, 0, text.length, paint)).toInt()
return StaticLayout.Builder.obtain(text, 0, text.length, paint, width)
- .setTextDirection(dir).build()
+ .setTextDirection(dir)
+ .build()
}
@Before
fun setup() {
- typefaceCache = TypefaceVariantCacheImpl(PAINT.typeface)
+ typefaceCache = TypefaceVariantCacheImpl(PAINT.typeface, 10)
}
@Test
@@ -135,10 +139,10 @@ class TextInterpolatorTest : SysuiTestCase() {
// end state.
interp.progress = 0.5f
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- assertThat(actual.sameAs(makeLayout(TEXT, START_PAINT)
- .toBitmap(BMP_WIDTH, BMP_HEIGHT))).isFalse()
- assertThat(actual.sameAs(makeLayout(TEXT, END_PAINT)
- .toBitmap(BMP_WIDTH, BMP_HEIGHT))).isFalse()
+ assertThat(actual.sameAs(makeLayout(TEXT, START_PAINT).toBitmap(BMP_WIDTH, BMP_HEIGHT)))
+ .isFalse()
+ assertThat(actual.sameAs(makeLayout(TEXT, END_PAINT).toBitmap(BMP_WIDTH, BMP_HEIGHT)))
+ .isFalse()
}
@Test
@@ -177,7 +181,8 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
assertThat(interp.progress).isEqualTo(0f)
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.LTR)
+ val expected =
+ makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.LTR)
.toBitmap(BMP_WIDTH, BMP_HEIGHT)
assertThat(expected.sameAs(actual)).isTrue()
@@ -197,7 +202,8 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
assertThat(interp.progress).isEqualTo(0f)
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ val expected =
+ makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
.toBitmap(BMP_WIDTH, BMP_HEIGHT)
assertThat(expected.sameAs(actual)).isTrue()
@@ -207,10 +213,8 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Empty() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout, typefaceCache).apply {
- glyphFilter = { glyph, progress ->
- }
- }
+ val interp =
+ TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> } }
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -219,7 +223,8 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ val expected =
+ makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
.toBitmap(BMP_WIDTH, BMP_HEIGHT)
assertThat(expected.sameAs(actual)).isTrue()
@@ -229,11 +234,10 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Xcoordinate() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout, typefaceCache).apply {
- glyphFilter = { glyph, progress ->
- glyph.x += 30f
+ val interp =
+ TextInterpolator(layout, typefaceCache).apply {
+ glyphFilter = { glyph, progress -> glyph.x += 30f }
}
- }
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -242,7 +246,8 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ val expected =
+ makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
.toBitmap(BMP_WIDTH, BMP_HEIGHT)
// The glyph position was modified by callback, so the bitmap should not be the same.
@@ -254,11 +259,10 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Ycoordinate() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout, typefaceCache).apply {
- glyphFilter = { glyph, progress ->
- glyph.y += 30f
+ val interp =
+ TextInterpolator(layout, typefaceCache).apply {
+ glyphFilter = { glyph, progress -> glyph.y += 30f }
}
- }
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -267,7 +271,8 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ val expected =
+ makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
.toBitmap(BMP_WIDTH, BMP_HEIGHT)
// The glyph position was modified by callback, so the bitmap should not be the same.
@@ -279,11 +284,10 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_TextSize() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout, typefaceCache).apply {
- glyphFilter = { glyph, progress ->
- glyph.textSize += 10f
+ val interp =
+ TextInterpolator(layout, typefaceCache).apply {
+ glyphFilter = { glyph, progress -> glyph.textSize += 10f }
}
- }
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -292,7 +296,8 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ val expected =
+ makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
.toBitmap(BMP_WIDTH, BMP_HEIGHT)
// The glyph position was modified by callback, so the bitmap should not be the same.
@@ -304,11 +309,10 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Color() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout, typefaceCache).apply {
- glyphFilter = { glyph, progress ->
- glyph.color = Color.RED
+ val interp =
+ TextInterpolator(layout, typefaceCache).apply {
+ glyphFilter = { glyph, progress -> glyph.color = Color.RED }
}
- }
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -317,7 +321,8 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ val expected =
+ makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
.toBitmap(BMP_WIDTH, BMP_HEIGHT)
// The glyph position was modified by callback, so the bitmap should not be the same.
@@ -327,7 +332,7 @@ class TextInterpolatorTest : SysuiTestCase() {
}
private fun Layout.toBitmap(width: Int, height: Int) =
- Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }!!
+ Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }!!
private fun TextInterpolator.toBitmap(width: Int, height: Int) =
- Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }
+ Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
index 2ff8cbcf34ae..5bf15137b834 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
@@ -78,8 +78,7 @@ class DeviceItemFactoryTest : SysuiTestCase() {
fun testAvailableMediaDeviceItemFactory_createFromCachedDevice() {
`when`(cachedDevice.name).thenReturn(DEVICE_NAME)
`when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
- `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
- .thenReturn(Pair.create(drawable, ""))
+ `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
val deviceItem = availableMediaDeviceItemFactory.create(context, cachedDevice)
assertDeviceItem(deviceItem, DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
@@ -89,8 +88,7 @@ class DeviceItemFactoryTest : SysuiTestCase() {
fun testConnectedDeviceItemFactory_createFromCachedDevice() {
`when`(cachedDevice.name).thenReturn(DEVICE_NAME)
`when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
- `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
- .thenReturn(Pair.create(drawable, ""))
+ `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
val deviceItem = connectedDeviceItemFactory.create(context, cachedDevice)
assertDeviceItem(deviceItem, DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
@@ -100,8 +98,7 @@ class DeviceItemFactoryTest : SysuiTestCase() {
fun testSavedDeviceItemFactory_createFromCachedDevice() {
`when`(cachedDevice.name).thenReturn(DEVICE_NAME)
`when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
- `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
- .thenReturn(Pair.create(drawable, ""))
+ `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
val deviceItem = savedDeviceItemFactory.create(context, cachedDevice)
assertDeviceItem(deviceItem, DeviceItemType.SAVED_BLUETOOTH_DEVICE)
@@ -111,8 +108,7 @@ class DeviceItemFactoryTest : SysuiTestCase() {
@Test
fun testAvailableAudioSharingMediaDeviceItemFactory_createFromCachedDevice() {
`when`(cachedDevice.name).thenReturn(DEVICE_NAME)
- `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
- .thenReturn(Pair.create(drawable, ""))
+ `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
val deviceItem =
AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
.create(context, cachedDevice)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 2c1718176571..bfbdc50c32b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -24,9 +24,9 @@ import android.os.Handler
import android.os.Looper
import android.os.PatternMatcher
import android.os.UserHandle
-import androidx.test.filters.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.dump.DumpManager
@@ -40,8 +40,9 @@ import java.util.concurrent.Executor
import junit.framework.Assert.assertSame
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -68,39 +69,28 @@ class BroadcastDispatcherTest : SysuiTestCase() {
val DEFAULT_PERMISSION: String? = null
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+
const val TEST_ACTION = "TEST_ACTION"
const val TEST_SCHEME = "TEST_SCHEME"
const val TEST_PATH = "TEST_PATH"
const val TEST_TYPE = "test/type"
}
- @Mock
- private lateinit var mockContext: Context
- @Mock
- private lateinit var mockUBRUser0: UserBroadcastDispatcher
- @Mock
- private lateinit var mockUBRUser1: UserBroadcastDispatcher
- @Mock
- private lateinit var broadcastReceiver: BroadcastReceiver
- @Mock
- private lateinit var broadcastReceiverOther: BroadcastReceiver
- @Mock
- private lateinit var intentFilter: IntentFilter
- @Mock
- private lateinit var intentFilterOther: IntentFilter
- @Mock
- private lateinit var mockHandler: Handler
- @Mock
- private lateinit var logger: BroadcastDispatcherLogger
- @Mock
- private lateinit var userTracker: UserTracker
- @Mock
- private lateinit var removalPendingStore: PendingRemovalStore
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var mockUBRUser0: UserBroadcastDispatcher
+ @Mock private lateinit var mockUBRUser1: UserBroadcastDispatcher
+ @Mock private lateinit var broadcastReceiver: BroadcastReceiver
+ @Mock private lateinit var broadcastReceiverOther: BroadcastReceiver
+ @Mock private lateinit var intentFilter: IntentFilter
+ @Mock private lateinit var intentFilterOther: IntentFilter
+ @Mock private lateinit var mockHandler: Handler
+ @Mock private lateinit var logger: BroadcastDispatcherLogger
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var removalPendingStore: PendingRemovalStore
private lateinit var mainExecutor: Executor
- @Captor
- private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
+ @Captor private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
private lateinit var testableLooper: TestableLooper
private lateinit var broadcastDispatcher: BroadcastDispatcher
@@ -112,7 +102,8 @@ class BroadcastDispatcherTest : SysuiTestCase() {
mainExecutor = FakeExecutor(FakeSystemClock())
`when`(mockContext.mainExecutor).thenReturn(mainExecutor)
- broadcastDispatcher = TestBroadcastDispatcher(
+ broadcastDispatcher =
+ TestBroadcastDispatcher(
mockContext,
mainExecutor,
testableLooper.looper,
@@ -121,7 +112,8 @@ class BroadcastDispatcherTest : SysuiTestCase() {
logger,
userTracker,
removalPendingStore,
- mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
+ mapOf(0 to mockUBRUser0, 1 to mockUBRUser1),
+ )
// These should be valid filters
`when`(intentFilter.countActions()).thenReturn(1)
@@ -131,10 +123,18 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testAddingReceiverToCorrectUBR() {
- broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
- mockHandler, user0)
broadcastDispatcher.registerReceiverWithHandler(
- broadcastReceiverOther, intentFilterOther, mockHandler, user1)
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ user0,
+ )
+ broadcastDispatcher.registerReceiverWithHandler(
+ broadcastReceiverOther,
+ intentFilterOther,
+ mockHandler,
+ user1,
+ )
testableLooper.processAllMessages()
@@ -152,7 +152,11 @@ class BroadcastDispatcherTest : SysuiTestCase() {
fun testAddingReceiverToCorrectUBR_executor() {
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mainExecutor, user0)
broadcastDispatcher.registerReceiver(
- broadcastReceiverOther, intentFilterOther, mainExecutor, user1)
+ broadcastReceiverOther,
+ intentFilterOther,
+ mainExecutor,
+ user1,
+ )
testableLooper.processAllMessages()
@@ -169,7 +173,10 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testAddReceiverDefaultFlag_handler() {
broadcastDispatcher.registerReceiverWithHandler(
- broadcastReceiver, intentFilter, mockHandler)
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ )
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
@@ -183,7 +190,11 @@ class BroadcastDispatcherTest : SysuiTestCase() {
val flag = 3
broadcastDispatcher.registerReceiverWithHandler(
- broadcastReceiver, intentFilter, mockHandler, flags = flag)
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ flags = flag,
+ )
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(flag))
@@ -212,7 +223,7 @@ class BroadcastDispatcherTest : SysuiTestCase() {
broadcastReceiver,
intentFilter,
flags = flag,
- permission = permission
+ permission = permission,
)
testableLooper.processAllMessages()
@@ -250,10 +261,18 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testRemovingReceiversRemovesFromAllUBR() {
- broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
- mockHandler, user0)
- broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
- mockHandler, user1)
+ broadcastDispatcher.registerReceiverWithHandler(
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ user0,
+ )
+ broadcastDispatcher.registerReceiverWithHandler(
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ user1,
+ )
broadcastDispatcher.unregisterReceiver(broadcastReceiver)
@@ -265,10 +284,18 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testRemoveReceiverFromUser() {
- broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
- mockHandler, user0)
- broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
- mockHandler, user1)
+ broadcastDispatcher.registerReceiverWithHandler(
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ user0,
+ )
+ broadcastDispatcher.registerReceiverWithHandler(
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ user1,
+ )
broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user0)
@@ -282,13 +309,17 @@ class BroadcastDispatcherTest : SysuiTestCase() {
fun testRegisterCurrentAsActualUser() {
`when`(userTracker.userId).thenReturn(user1.identifier)
- broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
- mockHandler, UserHandle.CURRENT)
+ broadcastDispatcher.registerReceiverWithHandler(
+ broadcastReceiver,
+ intentFilter,
+ mockHandler,
+ UserHandle.CURRENT,
+ )
testableLooper.processAllMessages()
- verify(mockUBRUser1).registerReceiver(
- capture(argumentCaptor), eq(Context.RECEIVER_EXPORTED))
+ verify(mockUBRUser1)
+ .registerReceiver(capture(argumentCaptor), eq(Context.RECEIVER_EXPORTED))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
}
@@ -300,41 +331,38 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test(expected = IllegalArgumentException::class)
fun testFilterMustNotContainDataScheme() {
- val testFilter = IntentFilter(TEST_ACTION).apply {
- addDataScheme(TEST_SCHEME)
- }
+ val testFilter = IntentFilter(TEST_ACTION).apply { addDataScheme(TEST_SCHEME) }
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
@Test(expected = IllegalArgumentException::class)
fun testFilterMustNotContainDataAuthority() {
- val testFilter = IntentFilter(TEST_ACTION).apply {
- addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java))
- }
+ val testFilter =
+ IntentFilter(TEST_ACTION).apply {
+ addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java))
+ }
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
@Test(expected = IllegalArgumentException::class)
fun testFilterMustNotContainDataPath() {
- val testFilter = IntentFilter(TEST_ACTION).apply {
- addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL)
- }
+ val testFilter =
+ IntentFilter(TEST_ACTION).apply {
+ addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL)
+ }
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
@Test(expected = IllegalArgumentException::class)
fun testFilterMustNotContainDataType() {
- val testFilter = IntentFilter(TEST_ACTION).apply {
- addDataType(TEST_TYPE)
- }
+ val testFilter = IntentFilter(TEST_ACTION).apply { addDataType(TEST_TYPE) }
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
@Test(expected = IllegalArgumentException::class)
fun testFilterMustNotSetPriority() {
- val testFilter = IntentFilter(TEST_ACTION).apply {
- priority = IntentFilter.SYSTEM_HIGH_PRIORITY
- }
+ val testFilter =
+ IntentFilter(TEST_ACTION).apply { priority = IntentFilter.SYSTEM_HIGH_PRIORITY }
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
@@ -366,12 +394,14 @@ class BroadcastDispatcherTest : SysuiTestCase() {
val inOrderUser0 = inOrder(mockUBRUser0, removalPendingStore)
inOrderUser0.verify(mockUBRUser0).unregisterReceiver(broadcastReceiver)
- inOrderUser0.verify(removalPendingStore)
+ inOrderUser0
+ .verify(removalPendingStore)
.clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL)
val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore)
inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
- inOrderUser1.verify(removalPendingStore)
+ inOrderUser1
+ .verify(removalPendingStore)
.clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL)
}
@@ -385,21 +415,21 @@ class BroadcastDispatcherTest : SysuiTestCase() {
val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore)
inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
- inOrderUser1.verify(removalPendingStore)
+ inOrderUser1
+ .verify(removalPendingStore)
.clearPendingRemoval(broadcastReceiver, user1.identifier)
}
@Test
- fun testBroadcastFlow() = runBlockingTest {
- val flow = broadcastDispatcher.broadcastFlow(intentFilter, user1) { intent, receiver ->
- intent to receiver
- }
+ fun testBroadcastFlow() = runTest(UnconfinedTestDispatcher()) {
+ val flow =
+ broadcastDispatcher.broadcastFlow(intentFilter, user1) { intent, receiver ->
+ intent to receiver
+ }
// Collect the values into collectedValues.
val collectedValues = mutableListOf<Pair<Intent, BroadcastReceiver>>()
- val job = launch {
- flow.collect { collectedValues.add(it) }
- }
+ val job = launch { flow.collect { collectedValues.add(it) } }
testableLooper.processAllMessages()
verify(mockUBRUser1).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
@@ -436,17 +466,18 @@ class BroadcastDispatcherTest : SysuiTestCase() {
logger: BroadcastDispatcherLogger,
userTracker: UserTracker,
removalPendingStore: PendingRemovalStore,
- var mockUBRMap: Map<Int, UserBroadcastDispatcher>
- ) : BroadcastDispatcher(
- context,
- mainExecutor,
- backgroundRunningLooper,
- backgroundRunningExecutor,
- dumpManager,
- logger,
- userTracker,
- removalPendingStore
- ) {
+ var mockUBRMap: Map<Int, UserBroadcastDispatcher>,
+ ) :
+ BroadcastDispatcher(
+ context,
+ mainExecutor,
+ backgroundRunningLooper,
+ backgroundRunningExecutor,
+ dumpManager,
+ logger,
+ userTracker,
+ removalPendingStore,
+ ) {
override fun createUBRForUser(userId: Int): UserBroadcastDispatcher {
return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
index 6e9b24f1433e..4ca84c58f6d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
@@ -37,7 +37,6 @@ import com.google.common.truth.Truth.assertThat
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
-import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -63,22 +62,18 @@ class CommunalBackupHelperTest : SysuiTestCase() {
Room.inMemoryDatabaseBuilder(context, CommunalDatabase::class.java)
.allowMainThreadQueries()
.build()
+ onTeardown { database.close() }
CommunalDatabase.setInstance(database)
dao = database.communalWidgetDao()
backupUtils = CommunalBackupUtils(context)
backupDataFile = File(context.cacheDir, "backup_data_file")
+ onTeardown { backupDataFile.delete() }
underTest = CommunalBackupHelper(UserHandle.SYSTEM, backupUtils)
}
- @After
- fun teardown() {
- backupDataFile.delete()
- database.close()
- }
-
@Test
@EnableFlags(Flags.FLAG_COMMUNAL_HUB)
fun backupAndRestoreCommunalHub() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderContentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderContentProviderTest.kt
new file mode 100644
index 000000000000..8d9fa6ad6e08
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderContentProviderTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 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.graphics
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.content.Context
+import android.database.Cursor
+import android.net.Uri
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.rule.provider.ProviderTestRule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+const val AUTHORITY = "exception.provider.authority"
+val TEST_URI = Uri.Builder().scheme("content").authority(AUTHORITY).path("path").build()
+
+@SmallTest
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
+class ImageLoaderContentProviderTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val mockContext = mock<Context>()
+ private lateinit var imageLoader: ImageLoader
+
+ @Rule
+ @JvmField
+ @Suppress("DEPRECATION")
+ public val providerTestRule =
+ ProviderTestRule.Builder(ExceptionThrowingContentProvider::class.java, AUTHORITY).build()
+
+ @Before
+ fun setUp() {
+ whenever(mockContext.contentResolver).thenReturn(providerTestRule.resolver)
+ imageLoader = ImageLoader(mockContext, kosmos.testDispatcher)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadFromTestContentProvider_throwsException() {
+ // This checks if the resolution actually throws the exception from test provider.
+ mockContext.contentResolver.query(TEST_URI, null, null, null)
+ }
+
+ @Test
+ fun loadFromRuntimeExceptionThrowingProvider_returnsNull() =
+ testScope.runTest { assertThat(imageLoader.loadBitmap(ImageLoader.Uri(TEST_URI))).isNull() }
+}
+
+class ExceptionThrowingContentProvider : ContentProvider() {
+ override fun query(
+ uri: Uri,
+ projection: Array<out String>?,
+ selection: String?,
+ selectionArgs: Array<out String>?,
+ sortOrder: String?,
+ ): Cursor? {
+ throw IllegalArgumentException("Test exception")
+ }
+
+ override fun getType(uri: Uri): String? {
+ throw IllegalArgumentException("Test exception")
+ }
+
+ override fun insert(uri: Uri, values: ContentValues?): Uri? {
+ throw IllegalArgumentException("Test exception")
+ }
+
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
+ throw IllegalArgumentException("Test exception")
+ }
+
+ override fun update(
+ uri: Uri,
+ values: ContentValues?,
+ selection: String?,
+ selectionArgs: Array<out String>?,
+ ): Int {
+ throw IllegalArgumentException("Test exception")
+ }
+
+ override fun onCreate(): Boolean = true
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
new file mode 100644
index 000000000000..f706cf6980e1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2024 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.keyboard.shortcut.ui.viewmodel
+
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS
+import android.hardware.input.fakeInputManager
+import android.os.SystemClock
+import android.view.KeyEvent.ACTION_DOWN
+import android.view.KeyEvent.KEYCODE_A
+import android.view.KeyEvent.META_CTRL_ON
+import android.view.KeyEvent.META_META_ON
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
+import com.android.systemui.keyboard.shortcut.shortcutCustomizationViewModelFactory
+import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.userTracker
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShortcutCustomizationViewModelTest : SysuiTestCase() {
+
+ private val mockUserContext: Context = mock()
+ private val kosmos =
+ Kosmos().also {
+ it.testCase = this
+ it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
+ }
+ private val testScope = kosmos.testScope
+ private val inputManager = kosmos.fakeInputManager.inputManager
+ private val helper = kosmos.shortcutHelperTestHelper
+ private val viewModel = kosmos.shortcutCustomizationViewModelFactory.create()
+
+ @Before
+ fun setup() {
+ helper.showFromActivity()
+ whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
+ }
+
+ @Test
+ fun uiState_inactiveByDefault() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+ assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+ }
+ }
+
+ @Test
+ fun uiState_correctlyUpdatedWhenAddShortcutCustomizationIsRequested() {
+ testScope.runTest {
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+ assertThat(uiState).isEqualTo(expectedStandardAddShortcutUiState)
+ }
+ }
+
+ @Test
+ fun uiState_correctlyUpdatedWhenDeleteShortcutCustomizationIsRequested() {
+ testScope.runTest {
+ viewModel.onShortcutCustomizationRequested(standardDeleteShortcutRequest)
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+ assertThat(uiState).isEqualTo(expectedStandardDeleteShortcutUiState)
+ }
+ }
+
+ @Test
+ fun uiState_consumedOnAddDialogShown() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ viewModel.onDialogShown()
+
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).isDialogShowing)
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun uiState_consumedOnDeleteDialogShown() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardDeleteShortcutRequest)
+ viewModel.onDialogShown()
+
+ assertThat(
+ (uiState as ShortcutCustomizationUiState.DeleteShortcutDialog).isDialogShowing
+ )
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun uiState_inactiveAfterDialogIsDismissed() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ viewModel.onDialogShown()
+ viewModel.onDialogDismissed()
+ assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+ }
+ }
+
+ @Test
+ fun uiState_pressedKeys_emptyByDefault() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+ .isEmpty()
+ }
+ }
+
+ @Test
+ fun uiState_becomeInactiveAfterSuccessfullySettingShortcut() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ whenever(inputManager.addCustomInputGesture(any()))
+ .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_SUCCESS)
+
+ openAddShortcutDialogAndSetShortcut()
+
+ assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+ }
+ }
+
+ @Test
+ fun uiState_errorMessage_isEmptyByDefault() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(allAppsShortcutCustomizationRequest)
+ viewModel.onDialogShown()
+
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+ .isEmpty()
+ }
+ }
+
+ @Test
+ fun uiState_errorMessage_isKeyCombinationInUse_whenKeyCombinationAlreadyExists() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ whenever(inputManager.addCustomInputGesture(any()))
+ .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS)
+
+ openAddShortcutDialogAndSetShortcut()
+
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+ .isEqualTo(
+ context.getString(
+ R.string.shortcut_customizer_key_combination_in_use_error_message
+ )
+ )
+ }
+ }
+
+ @Test
+ fun uiState_errorMessage_isKeyCombinationInUse_whenKeyCombinationIsReserved() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ whenever(inputManager.addCustomInputGesture(any()))
+ .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE)
+
+ openAddShortcutDialogAndSetShortcut()
+
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+ .isEqualTo(
+ context.getString(
+ R.string.shortcut_customizer_key_combination_in_use_error_message
+ )
+ )
+ }
+ }
+
+ @Test
+ fun uiState_errorMessage_isGenericError_whenErrorIsUnknown() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ whenever(inputManager.addCustomInputGesture(any()))
+ .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER)
+
+ openAddShortcutDialogAndSetShortcut()
+
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+ .isEqualTo(context.getString(R.string.shortcut_customizer_generic_error_message))
+ }
+ }
+
+ @Test
+ fun onKeyPressed_handlesKeyEvents_whereActionKeyIsAlsoPressed() {
+ testScope.runTest {
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ val isHandled = viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+
+ assertThat(isHandled).isTrue()
+ }
+ }
+
+ @Test
+ fun onKeyPressed_doesNotHandleKeyEvents_whenActionKeyIsNotAlsoPressed() {
+ testScope.runTest {
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ val isHandled = viewModel.onKeyPressed(keyDownEventWithoutActionKeyPressed)
+
+ assertThat(isHandled).isFalse()
+ }
+ }
+
+ @Test
+ fun onKeyPressed_convertsKeyEventsAndUpdatesUiStatesPressedKey() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+ viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
+
+ // Note that Action Key is excluded as it's already displayed on the UI
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+ .containsExactly(ShortcutKey.Text("Ctrl"), ShortcutKey.Text("A"))
+ }
+ }
+
+ @Test
+ fun uiState_pressedKeys_resetsToEmptyListAfterDialogIsDismissedAndReopened() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+ viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
+
+ // Note that Action Key is excluded as it's already displayed on the UI
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+ .containsExactly(ShortcutKey.Text("Ctrl"), ShortcutKey.Text("A"))
+
+ // Close the dialog and show it again
+ viewModel.onDialogDismissed()
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+ .isEmpty()
+ }
+ }
+
+ private suspend fun openAddShortcutDialogAndSetShortcut() {
+ viewModel.onShortcutCustomizationRequested(allAppsShortcutCustomizationRequest)
+ viewModel.onDialogShown()
+
+ viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+ viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
+
+ viewModel.onSetShortcut()
+ }
+
+ private val keyDownEventWithoutActionKeyPressed =
+ KeyEvent(
+ android.view.KeyEvent(
+ /* downTime = */ SystemClock.uptimeMillis(),
+ /* eventTime = */ SystemClock.uptimeMillis(),
+ /* action = */ ACTION_DOWN,
+ /* code = */ KEYCODE_A,
+ /* repeat = */ 0,
+ /* metaState = */ META_CTRL_ON,
+ )
+ )
+
+ private val keyDownEventWithActionKeyPressed =
+ KeyEvent(
+ android.view.KeyEvent(
+ /* downTime = */ SystemClock.uptimeMillis(),
+ /* eventTime = */ SystemClock.uptimeMillis(),
+ /* action = */ ACTION_DOWN,
+ /* code = */ KEYCODE_A,
+ /* repeat = */ 0,
+ /* metaState = */ META_CTRL_ON or META_META_ON,
+ )
+ )
+
+ private val keyUpEventWithActionKeyPressed =
+ KeyEvent(
+ android.view.KeyEvent(
+ /* downTime = */ SystemClock.uptimeMillis(),
+ /* eventTime = */ SystemClock.uptimeMillis(),
+ /* action = */ ACTION_DOWN,
+ /* code = */ KEYCODE_A,
+ /* repeat = */ 0,
+ /* metaState = */ 0,
+ )
+ )
+
+ private val standardAddShortcutRequest =
+ ShortcutCustomizationRequestInfo.Add(
+ label = "Standard shortcut",
+ categoryType = ShortcutCategoryType.System,
+ subCategoryLabel = "Standard subcategory",
+ )
+
+ private val standardDeleteShortcutRequest =
+ ShortcutCustomizationRequestInfo.Delete(
+ label = "Standard shortcut",
+ categoryType = ShortcutCategoryType.System,
+ subCategoryLabel = "Standard subcategory",
+ )
+
+ private val allAppsShortcutCustomizationRequest =
+ ShortcutCustomizationRequestInfo.Add(
+ label = "Open apps list",
+ categoryType = ShortcutCategoryType.System,
+ subCategoryLabel = "System controls",
+ )
+
+ private val expectedStandardAddShortcutUiState =
+ ShortcutCustomizationUiState.AddShortcutDialog(
+ shortcutLabel = "Standard shortcut",
+ defaultCustomShortcutModifierKey =
+ ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
+ isDialogShowing = false,
+ )
+
+ private val expectedStandardDeleteShortcutUiState =
+ ShortcutCustomizationUiState.DeleteShortcutDialog(isDialogShowing = false)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
index 7383faf2fd78..feae901114e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -278,7 +278,11 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
testScope.runTest {
fakeSystemSource.setGroups(
groupWithShortcutLabels("first Foo shortcut1", "first bar shortcut1"),
- groupWithShortcutLabels("second foO shortcut2", "second bar shortcut2"),
+ groupWithShortcutLabels(
+ "second foO shortcut2",
+ "second bar shortcut2",
+ groupLabel = SECOND_SIMPLE_GROUP_LABEL,
+ ),
)
fakeMultiTaskingSource.setGroups(
groupWithShortcutLabels("third FoO shortcut1", "third bar shortcut1")
@@ -298,7 +302,10 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
ShortcutCategory(
System,
subCategoryWithShortcutLabels("first Foo shortcut1"),
- subCategoryWithShortcutLabels("second foO shortcut2"),
+ subCategoryWithShortcutLabels(
+ "second foO shortcut2",
+ subCategoryLabel = SECOND_SIMPLE_GROUP_LABEL,
+ ),
),
),
ShortcutCategoryUi(
@@ -380,16 +387,23 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
assertThat(activeUiState.defaultSelectedCategory).isInstanceOf(CurrentApp::class.java)
}
- private fun groupWithShortcutLabels(vararg shortcutLabels: String) =
- KeyboardShortcutGroup(SIMPLE_GROUP_LABEL, shortcutLabels.map { simpleShortcutInfo(it) })
- .apply { packageName = "test.package.name" }
+ private fun groupWithShortcutLabels(
+ vararg shortcutLabels: String,
+ groupLabel: String = FIRST_SIMPLE_GROUP_LABEL,
+ ) =
+ KeyboardShortcutGroup(groupLabel, shortcutLabels.map { simpleShortcutInfo(it) }).apply {
+ packageName = "test.package.name"
+ }
private fun simpleShortcutInfo(label: String) =
KeyboardShortcutInfo(label, KeyEvent.KEYCODE_A, KeyEvent.META_CTRL_ON)
- private fun subCategoryWithShortcutLabels(vararg shortcutLabels: String) =
+ private fun subCategoryWithShortcutLabels(
+ vararg shortcutLabels: String,
+ subCategoryLabel: String = FIRST_SIMPLE_GROUP_LABEL,
+ ) =
ShortcutSubCategory(
- label = SIMPLE_GROUP_LABEL,
+ label = subCategoryLabel,
shortcuts = shortcutLabels.map { simpleShortcut(it) },
)
@@ -402,6 +416,7 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
}
companion object {
- private const val SIMPLE_GROUP_LABEL = "simple group"
+ private const val FIRST_SIMPLE_GROUP_LABEL = "simple group 1"
+ private const val SECOND_SIMPLE_GROUP_LABEL = "simple group 2"
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index e1845a17a767..7e85dd5d3236 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -213,7 +213,7 @@ class KeyguardBottomAreaViewModelTest(flags: FlagsParameterization) : SysuiTestC
)
val keyguardTouchHandlingInteractor =
KeyguardTouchHandlingInteractor(
- appContext = mContext,
+ context = mContext,
scope = testScope.backgroundScope,
transitionInteractor = kosmos.keyguardTransitionInteractor,
repository = repository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index d7084898a4a4..7849ea5ab7ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -38,6 +38,7 @@ import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
import android.content.pm.ShortcutManager
import android.content.pm.UserInfo
+import android.content.res.Resources
import android.graphics.drawable.Icon
import android.os.UserHandle
import android.os.UserManager
@@ -84,6 +85,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.whenever
@@ -106,6 +108,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
@Mock private lateinit var shortcutManager: ShortcutManager
@Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
+ private lateinit var spiedResources: Resources
private val userTracker = FakeUserTracker()
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -130,7 +133,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(
devicePolicyManager.getKeyguardDisabledFeatures(
/* admin= */ eq(null),
- /* userHandle= */ anyInt()
+ /* userHandle= */ anyInt(),
)
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE)
@@ -139,6 +142,9 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(activityManager.getRunningTasks(anyInt())).thenReturn(emptyList())
whenever(userManager.isManagedProfile(workUserInfo.id)).thenReturn(true)
whenever(context.resources).thenReturn(getContext().resources)
+
+ spiedResources = spy(context.resources)
+ `when`(context.resources).thenReturn(spiedResources)
}
private fun createNoteTaskController(
@@ -161,7 +167,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
noteTaskBubblesController =
FakeNoteTaskBubbleController(context, testDispatcher, Optional.ofNullable(bubbles)),
applicationScope = testScope,
- bgCoroutineContext = testScope.backgroundScope.coroutineContext
+ bgCoroutineContext = testScope.backgroundScope.coroutineContext,
)
// region onBubbleExpandChanged
@@ -225,11 +231,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
@Test
fun onBubbleExpandChanged_notKeyAppBubble_shouldDoNothing() {
- createNoteTaskController()
- .onBubbleExpandChanged(
- isExpanding = true,
- key = "any other key",
- )
+ createNoteTaskController().onBubbleExpandChanged(isExpanding = true, key = "any other key")
verifyNoMoreInteractions(bubbles, keyguardManager, userManager, eventLogger)
}
@@ -251,11 +253,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
fun showNoteTaskAsUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() {
val user10 = UserHandle.of(/* userId= */ 10)
val expectedInfo =
- NOTE_TASK_INFO.copy(
- entryPoint = TAIL_BUTTON,
- isKeyguardLocked = true,
- user = user10,
- )
+ NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true, user = user10)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
@@ -360,7 +358,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
secureSettings.putIntForUser(
/* name= */ Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
/* value= */ 10,
- /* userHandle= */ userTracker.userId
+ /* userHandle= */ userTracker.userId,
)
val user10 = UserHandle.of(/* userId= */ 10)
@@ -373,10 +371,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
- createNoteTaskController()
- .showNoteTask(
- entryPoint = expectedInfo.entryPoint!!,
- )
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
val intentCaptor = argumentCaptor<Intent>()
val userCaptor = argumentCaptor<UserHandle>()
@@ -456,6 +451,85 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
verifyNoMoreInteractions(bubbles)
}
+ @Test
+ fun showNoteTask_stylusModePreferred_keyboardShortcut_shouldStartInDefaultUIMode() {
+ `when`(spiedResources.getInteger(R.integer.config_preferredNotesMode)).thenReturn(1)
+ val expectedInfo =
+ NOTE_TASK_INFO.copy(entryPoint = KEYBOARD_SHORTCUT, isKeyguardLocked = true)
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ assertThat(intentCaptor.value).run {
+ hasAction(ACTION_CREATE_NOTE)
+ hasPackage(NOTE_TASK_PACKAGE_NAME)
+ extras().bool(EXTRA_USE_STYLUS_MODE).isFalse()
+ }
+ }
+
+ @Test
+ fun showNoteTask_stylusModePreferred_quickAffordance_shouldStartInStylusUIMode() {
+ `when`(spiedResources.getInteger(R.integer.config_preferredNotesMode)).thenReturn(1)
+ val expectedInfo =
+ NOTE_TASK_INFO.copy(entryPoint = QUICK_AFFORDANCE, isKeyguardLocked = true)
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ assertThat(intentCaptor.value).run {
+ hasAction(ACTION_CREATE_NOTE)
+ hasPackage(NOTE_TASK_PACKAGE_NAME)
+ extras().bool(EXTRA_USE_STYLUS_MODE).isTrue()
+ }
+ }
+
+ @Test
+ fun showNoteTask_noUIRecommendation_quickAffordance_shouldStartInDefaultUIMode() {
+ `when`(spiedResources.getInteger(R.integer.config_preferredNotesMode)).thenReturn(0)
+ val expectedInfo =
+ NOTE_TASK_INFO.copy(entryPoint = QUICK_AFFORDANCE, isKeyguardLocked = true)
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ assertThat(intentCaptor.value).run {
+ hasAction(ACTION_CREATE_NOTE)
+ hasPackage(NOTE_TASK_PACKAGE_NAME)
+ extras().bool(EXTRA_USE_STYLUS_MODE).isFalse()
+ }
+ }
+
+ @Test
+ fun showNoteTask_noUIRecommendation_tailButton_shouldStartInStylusUIMode() {
+ `when`(spiedResources.getInteger(R.integer.config_preferredNotesMode)).thenReturn(0)
+ val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true)
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ assertThat(intentCaptor.value).run {
+ hasAction(ACTION_CREATE_NOTE)
+ hasPackage(NOTE_TASK_PACKAGE_NAME)
+ extras().bool(EXTRA_USE_STYLUS_MODE).isTrue()
+ }
+ }
+
// endregion
// region setNoteTaskShortcutEnabled
@@ -543,7 +617,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(
devicePolicyManager.getKeyguardDisabledFeatures(
/* admin= */ eq(null),
- /* userHandle= */ anyInt()
+ /* userHandle= */ anyInt(),
)
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)
@@ -559,7 +633,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(
devicePolicyManager.getKeyguardDisabledFeatures(
/* admin= */ eq(null),
- /* userHandle= */ anyInt()
+ /* userHandle= */ anyInt(),
)
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
@@ -575,7 +649,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(
devicePolicyManager.getKeyguardDisabledFeatures(
/* admin= */ eq(null),
- /* userHandle= */ anyInt()
+ /* userHandle= */ anyInt(),
)
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)
@@ -591,7 +665,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(
devicePolicyManager.getKeyguardDisabledFeatures(
/* admin= */ eq(null),
- /* userHandle= */ anyInt()
+ /* userHandle= */ anyInt(),
)
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
@@ -604,8 +678,9 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
// endregion
// region showNoteTask, COPE devices
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun showNoteTask_copeDevices_quickAffordanceEntryPoint_managedProfileNotFound_shouldStartBubbleInTheMainProfile() { // ktlint-disable max-line-length
+ fun showNoteTask_copeDevices_quickAffordanceEntryPoint_managedProfileNotFound_shouldStartBubbleInTheMainProfile() {
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(listOf(mainUserInfo), mainAndWorkProfileUsers.indexOf(mainUserInfo))
@@ -629,7 +704,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
secureSettings.putIntForUser(
/* name= */ Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
/* value= */ mainUserInfo.id,
- /* userHandle= */ userTracker.userId
+ /* userHandle= */ userTracker.userId,
)
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
@@ -836,12 +911,13 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
assertThat(user).isEqualTo(UserHandle.of(workUserInfo.id))
}
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun getUserForHandlingNotesTaking_cope_userSelectedWorkProfile_tailButton_shouldReturnWorkProfileUser() { // ktlint-disable max-line-length
+ fun getUserForHandlingNotesTaking_cope_userSelectedWorkProfile_tailButton_shouldReturnWorkProfileUser() {
secureSettings.putIntForUser(
/* name= */ Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
/* value= */ workUserInfo.id,
- /* userHandle= */ userTracker.userId
+ /* userHandle= */ userTracker.userId,
)
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
@@ -851,12 +927,13 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
assertThat(user).isEqualTo(UserHandle.of(workUserInfo.id))
}
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun getUserForHandlingNotesTaking_cope_userSelectedMainProfile_tailButton_shouldReturnMainProfileUser() { // ktlint-disable max-line-length
+ fun getUserForHandlingNotesTaking_cope_userSelectedMainProfile_tailButton_shouldReturnMainProfileUser() {
secureSettings.putIntForUser(
/* name= */ Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
/* value= */ mainUserInfo.id,
- /* userHandle= */ userTracker.userId
+ /* userHandle= */ userTracker.userId,
)
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
@@ -934,8 +1011,9 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
}
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun startNotesRoleSetting_noManagement_quickAffordance_shouldStartNoteRoleIntentWithCurrentUser() { // ktlint-disable max-line-length
+ fun startNotesRoleSetting_noManagement_quickAffordance_shouldStartNoteRoleIntentWithCurrentUser() {
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
createNoteTaskController().startNotesRoleSetting(context, QUICK_AFFORDANCE)
@@ -947,8 +1025,9 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
}
+ @Suppress("ktlint:standard:max-line-length")
@Test
- fun startNotesRoleSetting_noManagement_nullEntryPoint_shouldStartNoteRoleIntentWithCurrentUser() { // ktlint-disable max-line-length
+ fun startNotesRoleSetting_noManagement_nullEntryPoint_shouldStartNoteRoleIntentWithCurrentUser() {
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
createNoteTaskController().startNotesRoleSetting(context, entryPoint = null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
index 0b9c06f2dbe2..5ada2f3fd63d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
@@ -222,7 +222,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase {
when(SubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(SUB_ID);
SubscriptionInfo info = mock(SubscriptionInfo.class);
when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info);
- when(mToastFactory.createToast(any(), anyString(), anyString(), anyInt(), anyInt()))
+ when(mToastFactory.createToast(any(), any(), anyString(), anyString(), anyInt(), anyInt()))
.thenReturn(mSystemUIToast);
when(mSystemUIToast.getView()).thenReturn(mToastView);
when(mSystemUIToast.getGravity()).thenReturn(GRAVITY_FLAGS);
@@ -275,8 +275,8 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase {
mInternetDialogController.connectCarrierNetwork();
verify(mMergedCarrierEntry).connect(null /* callback */, false /* showToast */);
- verify(mToastFactory).createToast(any(), eq(TOAST_MESSAGE_STRING), anyString(), anyInt(),
- anyInt());
+ verify(mToastFactory).createToast(any(), any(), eq(TOAST_MESSAGE_STRING), anyString(),
+ anyInt(), anyInt());
}
@Test
@@ -288,7 +288,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase {
mInternetDialogController.connectCarrierNetwork();
verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
- verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+ verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(),
anyInt());
}
@@ -302,7 +302,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase {
mInternetDialogController.connectCarrierNetwork();
verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
- verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+ verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(),
anyInt());
}
@@ -321,7 +321,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase {
mInternetDialogController.connectCarrierNetwork();
verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
- verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+ verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(),
anyInt());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt
new file mode 100644
index 000000000000..c8faa81adffa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2024 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.reardisplay
+
+import android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_RDM_V2
+import android.hardware.display.rearDisplay
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.view.Display
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.deviceStateManager
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.rearDisplayInnerDialogDelegateFactory
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import org.junit.Before
+import org.junit.Test
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/** atest SystemUITests:com.android.systemui.reardisplay.RearDisplayCoreStartableTest */
+@SmallTest
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+class RearDisplayCoreStartableTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val mockDelegate: RearDisplayInnerDialogDelegate = mock()
+ private val mockDialog: SystemUIDialog = mock()
+
+ private val fakeRearDisplayStateInteractor = FakeRearDisplayStateInteractor(kosmos)
+ private val impl =
+ RearDisplayCoreStartable(
+ mContext,
+ kosmos.deviceStateManager,
+ fakeRearDisplayStateInteractor,
+ kosmos.rearDisplayInnerDialogDelegateFactory,
+ kosmos.testScope,
+ )
+
+ @Before
+ fun setup() {
+ whenever(kosmos.rearDisplay.flags).thenReturn(Display.FLAG_REAR)
+ whenever(kosmos.rearDisplay.displayAdjustments)
+ .thenReturn(mContext.display.displayAdjustments)
+ whenever(kosmos.rearDisplayInnerDialogDelegateFactory.create(any(), any()))
+ .thenReturn(mockDelegate)
+ whenever(mockDelegate.createDialog()).thenReturn(mockDialog)
+ }
+
+ @Test
+ @DisableFlags(FLAG_DEVICE_STATE_RDM_V2)
+ fun testWhenFlagDisabled() =
+ kosmos.runTest {
+ impl.use {
+ it.start()
+ assertThat(impl.stateChangeListener).isNull()
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_DEVICE_STATE_RDM_V2)
+ fun testShowAndDismissDialog() =
+ kosmos.runTest {
+ impl.use {
+ it.start()
+ fakeRearDisplayStateInteractor.emitRearDisplay()
+ verify(mockDialog).show()
+ verify(mockDialog, never()).dismiss()
+
+ fakeRearDisplayStateInteractor.emitDisabled()
+ verify(mockDialog).dismiss()
+ }
+ }
+
+ private class FakeRearDisplayStateInteractor(private val kosmos: Kosmos) :
+ RearDisplayStateInteractor {
+ private val stateFlow = MutableSharedFlow<RearDisplayStateInteractor.State>()
+
+ suspend fun emitRearDisplay() =
+ stateFlow.emit(RearDisplayStateInteractor.State.Enabled(kosmos.rearDisplay))
+
+ suspend fun emitDisabled() = stateFlow.emit(RearDisplayStateInteractor.State.Disabled)
+
+ override val state: Flow<RearDisplayStateInteractor.State>
+ get() = stateFlow
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt
new file mode 100644
index 000000000000..60588802ffa9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 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.reardisplay
+
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.systemUIDialogDotFactory
+import com.android.systemui.testKosmos
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.mock
+
+/** atest SystemUITests:com.android.systemui.reardisplay.RearDisplayInnerDialogDelegateTest */
+@SmallTest
+@TestableLooper.RunWithLooper
+class RearDisplayInnerDialogDelegateTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ @Test
+ fun testShowAndDismissDialog() {
+ val dialogDelegate =
+ RearDisplayInnerDialogDelegate(kosmos.systemUIDialogDotFactory, mContext) {}
+
+ val dialog = dialogDelegate.createDialog()
+ dialog.show()
+ assertTrue(dialog.isShowing)
+
+ dialog.dismiss()
+ assertFalse(dialog.isShowing)
+ }
+
+ @Test
+ fun testCancel() {
+ val mockCallback = mock<Runnable>()
+ RearDisplayInnerDialogDelegate(kosmos.systemUIDialogDotFactory, mContext) {
+ mockCallback.run()
+ }
+ .createDialog()
+ .apply {
+ show()
+ findViewById<View>(R.id.button_cancel).performClick()
+ verify(mockCallback).run()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
index 8bd8b72e5527..b3a5872a7dec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
@@ -15,11 +15,16 @@
*/
package systemui.shared.clocks.view
+import android.graphics.Typeface
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
+import com.android.systemui.plugins.clocks.ClockSettings
+import com.android.systemui.shared.clocks.ClockContext
import com.android.systemui.shared.clocks.FontTextStyle
import com.android.systemui.shared.clocks.LogUtil
+import com.android.systemui.shared.clocks.TypefaceCache
import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -38,7 +43,23 @@ class SimpleDigitalClockTextViewTest : SysuiTestCase() {
@Before
fun setup() {
- underTest = SimpleDigitalClockTextView(context, messageBuffer)
+ underTest =
+ SimpleDigitalClockTextView(
+ ClockContext(
+ context,
+ context.resources,
+ ClockSettings(),
+ TypefaceCache(messageBuffer, 20) {
+ // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
+ return@TypefaceCache Typeface.create(
+ "google-sans-flex-clock",
+ Typeface.NORMAL,
+ )
+ },
+ ClockMessageBuffers(messageBuffer),
+ messageBuffer,
+ )
+ )
underTest.textStyle = FontTextStyle()
underTest.aodStyle = FontTextStyle()
underTest.text = "0"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index a8618eb544d4..3a46d038f946 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -20,9 +20,8 @@ import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
-import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationTestHelper
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
@@ -31,7 +30,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.statusbar.policy.fakeConfigurationController
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
@@ -144,7 +142,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
context = context,
configurationController = configurationController,
dumpManager = mock(),
- splitShadeStateController = ResourcesSplitShadeStateController()
+ splitShadeStateController = ResourcesSplitShadeStateController(),
),
keyguardTransitionControllerFactory = { notificationPanelController ->
LockscreenShadeKeyguardTransitionController(
@@ -153,7 +151,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
context = context,
configurationController = configurationController,
dumpManager = mock(),
- splitShadeStateController = ResourcesSplitShadeStateController()
+ splitShadeStateController = ResourcesSplitShadeStateController(),
)
},
depthController = depthController,
@@ -171,7 +169,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
splitShadeStateController = ResourcesSplitShadeStateController(),
shadeLockscreenInteractorLazy = { shadeLockscreenInteractor },
naturalScrollingSettingObserver = naturalScrollingSettingObserver,
- lazyQSSceneAdapter = { qsSceneAdapter }
+ lazyQSSceneAdapter = { qsSceneAdapter },
)
transitionController.addCallback(transitionControllerCallback)
@@ -229,7 +227,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
assertFalse(
"Waking to shade locked when not dozing",
- transitionController.isWakingToShadeLocked
+ transitionController.isWakingToShadeLocked,
)
}
@@ -247,9 +245,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
fun testDontGoWhenShadeDisabled() =
testScope.runTest {
disableFlagsRepository.disableFlags.value =
- DisableFlagsModel(
- disable2 = DISABLE2_NOTIFICATION_SHADE,
- )
+ DisableFlagsModel(disable2 = DISABLE2_NOTIFICATION_SHADE)
testScope.runCurrent()
transitionController.goToLockedShade(null)
verify(statusbarStateController, never()).setState(anyInt())
@@ -454,7 +450,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
val distance = 10
context.orCreateTestableResources.addOverride(
R.dimen.lockscreen_shade_scrim_transition_distance,
- distance
+ distance,
)
configurationController.notifyConfigurationChanged()
@@ -463,7 +459,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController)
.transitionToFullShadeProgress(
progress = eq(0.5f),
- lockScreenNotificationsProgress = anyFloat()
+ lockScreenNotificationsProgress = anyFloat(),
)
}
@@ -474,11 +470,11 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
val delay = 10
context.orCreateTestableResources.addOverride(
R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
- distance
+ distance,
)
context.orCreateTestableResources.addOverride(
R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
- delay
+ delay,
)
configurationController.notifyConfigurationChanged()
@@ -487,7 +483,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController)
.transitionToFullShadeProgress(
progress = anyFloat(),
- lockScreenNotificationsProgress = eq(0.1f)
+ lockScreenNotificationsProgress = eq(0.1f),
)
}
@@ -498,11 +494,11 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
val delay = 50
context.orCreateTestableResources.addOverride(
R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
- distance
+ distance,
)
context.orCreateTestableResources.addOverride(
R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
- delay
+ delay,
)
configurationController.notifyConfigurationChanged()
@@ -511,7 +507,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController)
.transitionToFullShadeProgress(
progress = anyFloat(),
- lockScreenNotificationsProgress = eq(0f)
+ lockScreenNotificationsProgress = eq(0f),
)
}
@@ -522,11 +518,11 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
val delay = 50
context.orCreateTestableResources.addOverride(
R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
- distance
+ distance,
)
context.orCreateTestableResources.addOverride(
R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
- delay
+ delay,
)
configurationController.notifyConfigurationChanged()
@@ -535,7 +531,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController)
.transitionToFullShadeProgress(
progress = anyFloat(),
- lockScreenNotificationsProgress = eq(1f)
+ lockScreenNotificationsProgress = eq(1f),
)
}
@@ -627,7 +623,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
*/
private fun ScrimController.transitionToFullShadeProgress(
progress: Float,
- lockScreenNotificationsProgress: Float
+ lockScreenNotificationsProgress: Float,
) {
setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
index e72109d4d8e3..a3c518128b47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
@@ -27,16 +27,15 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
-import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations.initMocks
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -47,14 +46,13 @@ class DataStoreCoordinatorTest : SysuiTestCase() {
private lateinit var entry: NotificationEntry
- @Mock private lateinit var pipeline: NotifPipeline
- @Mock private lateinit var notifLiveDataStoreImpl: NotifLiveDataStoreImpl
- @Mock private lateinit var stackController: NotifStackController
- @Mock private lateinit var section: NotifSection
+ private val pipeline: NotifPipeline = mock()
+ private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl = mock()
+ private val stackController: NotifStackController = mock()
+ private val section: NotifSection = mock()
@Before
fun setUp() {
- initMocks(this)
entry = NotificationEntryBuilder().setSection(section).build()
coordinator = DataStoreCoordinator(notifLiveDataStoreImpl)
coordinator.attach(pipeline)
@@ -76,31 +74,35 @@ class DataStoreCoordinatorTest : SysuiTestCase() {
listOf(
notificationEntry("foo", 1),
notificationEntry("foo", 2),
- GroupEntryBuilder().setSummary(
- notificationEntry("bar", 1)
- ).setChildren(
- listOf(
- notificationEntry("bar", 2),
- notificationEntry("bar", 3),
- notificationEntry("bar", 4)
+ GroupEntryBuilder()
+ .setSummary(notificationEntry("bar", 1))
+ .setChildren(
+ listOf(
+ notificationEntry("bar", 2),
+ notificationEntry("bar", 3),
+ notificationEntry("bar", 4),
+ )
)
- ).setSection(section).build(),
- notificationEntry("baz", 1)
+ .setSection(section)
+ .build(),
+ notificationEntry("baz", 1),
),
- stackController
+ stackController,
)
val list: List<NotificationEntry> = withArgCaptor {
verify(notifLiveDataStoreImpl).setActiveNotifList(capture())
}
- assertThat(list.map { it.key }).containsExactly(
- "0|foo|1|null|0",
- "0|foo|2|null|0",
- "0|bar|1|null|0",
- "0|bar|2|null|0",
- "0|bar|3|null|0",
- "0|bar|4|null|0",
- "0|baz|1|null|0"
- ).inOrder()
+ assertThat(list.map { it.key })
+ .containsExactly(
+ "0|foo|1|null|0",
+ "0|foo|2|null|0",
+ "0|bar|1|null|0",
+ "0|bar|2|null|0",
+ "0|bar|3|null|0",
+ "0|bar|4|null|0",
+ "0|baz|1|null|0",
+ )
+ .inOrder()
verifyNoMoreInteractions(notifLiveDataStoreImpl)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index 56b70bde2cca..2c37f510a45c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -38,41 +38,37 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.withArgCaptor
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.Mockito.`when` as whenever
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWithLooper
class StackCoordinatorTest : SysuiTestCase() {
+ private lateinit var entry: NotificationEntry
private lateinit var coordinator: StackCoordinator
private lateinit var afterRenderListListener: OnAfterRenderListListener
- private lateinit var entry: NotificationEntry
-
- @Mock private lateinit var pipeline: NotifPipeline
- @Mock private lateinit var groupExpansionManagerImpl: GroupExpansionManagerImpl
- @Mock private lateinit var renderListInteractor: RenderNotificationListInteractor
- @Mock private lateinit var activeNotificationsInteractor: ActiveNotificationsInteractor
- @Mock
- private lateinit var sensitiveNotificationProtectionController:
- SensitiveNotificationProtectionController
- @Mock private lateinit var stackController: NotifStackController
- @Mock private lateinit var section: NotifSection
- @Mock private lateinit var row: ExpandableNotificationRow
+ private val pipeline: NotifPipeline = mock()
+ private val groupExpansionManagerImpl: GroupExpansionManagerImpl = mock()
+ private val renderListInteractor: RenderNotificationListInteractor = mock()
+ private val activeNotificationsInteractor: ActiveNotificationsInteractor = mock()
+ private val sensitiveNotificationProtectionController:
+ SensitiveNotificationProtectionController =
+ mock()
+ private val stackController: NotifStackController = mock()
+ private val section: NotifSection = mock()
+ private val row: ExpandableNotificationRow = mock()
@Before
fun setUp() {
- initMocks(this)
-
whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(false)
entry = NotificationEntryBuilder().setSection(section).build()
@@ -86,9 +82,9 @@ class StackCoordinatorTest : SysuiTestCase() {
sensitiveNotificationProtectionController,
)
coordinator.attach(pipeline)
- afterRenderListListener = withArgCaptor {
- verify(pipeline).addOnAfterRenderListListener(capture())
- }
+ val captor = argumentCaptor<OnAfterRenderListListener>()
+ verify(pipeline).addOnAfterRenderListListener(captor.capture())
+ afterRenderListListener = captor.lastValue
}
@Test
@@ -109,7 +105,16 @@ class StackCoordinatorTest : SysuiTestCase() {
fun testSetNotificationStats_clearableAlerting() {
whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
- verify(stackController).setNotifStats(NotifStats(1, false, true, false, false))
+ verify(stackController)
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = false,
+ hasClearableAlertingNotifs = true,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = false,
+ )
+ )
verifyNoMoreInteractions(activeNotificationsInteractor)
}
@@ -120,7 +125,16 @@ class StackCoordinatorTest : SysuiTestCase() {
whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
- verify(stackController).setNotifStats(NotifStats(1, true, false, false, false))
+ verify(stackController)
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = true,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = false,
+ )
+ )
verifyNoMoreInteractions(activeNotificationsInteractor)
}
@@ -129,7 +143,16 @@ class StackCoordinatorTest : SysuiTestCase() {
fun testSetNotificationStats_clearableSilent() {
whenever(section.bucket).thenReturn(BUCKET_SILENT)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
- verify(stackController).setNotifStats(NotifStats(1, false, false, false, true))
+ verify(stackController)
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = false,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = true,
+ )
+ )
verifyNoMoreInteractions(activeNotificationsInteractor)
}
@@ -140,7 +163,16 @@ class StackCoordinatorTest : SysuiTestCase() {
whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
whenever(section.bucket).thenReturn(BUCKET_SILENT)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
- verify(stackController).setNotifStats(NotifStats(1, false, false, true, false))
+ verify(stackController)
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = false,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = true,
+ hasClearableSilentNotifs = false,
+ )
+ )
verifyNoMoreInteractions(activeNotificationsInteractor)
}
@@ -150,7 +182,15 @@ class StackCoordinatorTest : SysuiTestCase() {
whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(activeNotificationsInteractor)
- .setNotifStats(NotifStats(1, false, true, false, false))
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = false,
+ hasClearableAlertingNotifs = true,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = false,
+ )
+ )
verifyNoMoreInteractions(stackController)
}
@@ -158,14 +198,22 @@ class StackCoordinatorTest : SysuiTestCase() {
@EnableFlags(
FooterViewRefactor.FLAG_NAME,
FLAG_SCREENSHARE_NOTIFICATION_HIDING,
- FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX
+ FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX,
)
fun testSetNotificationStats_footerFlagOn_isSensitiveStateActive_nonClearableAlerting() {
whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(activeNotificationsInteractor)
- .setNotifStats(NotifStats(1, true, false, false, false))
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = true,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = false,
+ )
+ )
verifyNoMoreInteractions(stackController)
}
@@ -175,7 +223,15 @@ class StackCoordinatorTest : SysuiTestCase() {
whenever(section.bucket).thenReturn(BUCKET_SILENT)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(activeNotificationsInteractor)
- .setNotifStats(NotifStats(1, false, false, false, true))
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = false,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = true,
+ )
+ )
verifyNoMoreInteractions(stackController)
}
@@ -183,27 +239,41 @@ class StackCoordinatorTest : SysuiTestCase() {
@EnableFlags(
FooterViewRefactor.FLAG_NAME,
FLAG_SCREENSHARE_NOTIFICATION_HIDING,
- FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX
+ FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX,
)
fun testSetNotificationStats_footerFlagOn_isSensitiveStateActive_nonClearableSilent() {
whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
whenever(section.bucket).thenReturn(BUCKET_SILENT)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(activeNotificationsInteractor)
- .setNotifStats(NotifStats(1, false, false, true, false))
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = false,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = true,
+ hasClearableSilentNotifs = false,
+ )
+ )
verifyNoMoreInteractions(stackController)
}
@Test
- @EnableFlags(
- FooterViewRefactor.FLAG_NAME
- )
+ @EnableFlags(FooterViewRefactor.FLAG_NAME)
fun testSetNotificationStats_footerFlagOn_nonClearableRedacted() {
entry.setSensitive(true, true)
whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(activeNotificationsInteractor)
- .setNotifStats(NotifStats(1, hasNonClearableAlertingNotifs = true, false, false, false))
+ .setNotifStats(
+ NotifStats(
+ 1,
+ hasNonClearableAlertingNotifs = true,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = false,
+ )
+ )
verifyNoMoreInteractions(stackController)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index e313a05773ab..d8a23d6bd32e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -45,6 +45,7 @@ import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -551,12 +552,26 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
}
@Test
+ @DisableFlags(com.android.systemui.Flags.FLAG_NOTIFICATION_REENTRANT_DISMISS)
+ public void testCanDismiss_immediately() throws Exception {
+ ExpandableNotificationRow row =
+ mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+ when(mNotificationTestHelper.getDismissibilityProvider().isDismissable(row.getEntry()))
+ .thenReturn(true);
+ row.performDismiss(false);
+ verify(mNotificationTestHelper.getOnUserInteractionCallback())
+ .registerFutureDismissal(any(), anyInt());
+ }
+
+ @Test
+ @EnableFlags(com.android.systemui.Flags.FLAG_NOTIFICATION_REENTRANT_DISMISS)
public void testCanDismiss() throws Exception {
ExpandableNotificationRow row =
mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
when(mNotificationTestHelper.getDismissibilityProvider().isDismissable(row.getEntry()))
.thenReturn(true);
row.performDismiss(false);
+ TestableLooper.get(this).processAllMessages();
verify(mNotificationTestHelper.getOnUserInteractionCallback())
.registerFutureDismissal(any(), anyInt());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index b142fc2deea9..c9f8463d510c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -607,7 +607,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mShadeController,
mWindowRootViewVisibilityInteractor,
mStatusBarKeyguardViewManager,
- () -> mStatusBarLongPressGestureDetector,
mViewMediatorCallback,
mInitController,
new Handler(TestableLooper.get(this).getLooper()),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
index 0c0b5baad821..a2fabf3b9baa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
@@ -34,45 +34,27 @@ import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POST
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
import com.android.systemui.statusbar.policy.devicePostureController
import com.android.systemui.testKosmos
-import com.android.systemui.tuner.TunerService
-import com.android.systemui.tuner.tunerService
-import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableSceneContainer
class KeyguardBypassRepositoryTest : SysuiTestCase() {
- @JvmField @Rule val mockito: MockitoRule = MockitoJUnit.rule()
- private lateinit var tunableCallback: TunerService.Tunable
private lateinit var postureControllerCallback: DevicePostureController.Callback
private val kosmos = testKosmos()
private lateinit var underTest: KeyguardBypassRepository
private val testScope = kosmos.testScope
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- }
-
// overrideFaceBypassSetting overridden to true
// isFaceEnrolledAndEnabled true
// isPostureAllowedForFaceAuth true/false on posture changes
@@ -148,24 +130,25 @@ class KeyguardBypassRepositoryTest : SysuiTestCase() {
val bypassEnabled by collectLastValue(underTest.isBypassAvailable)
runCurrent()
postureControllerCallback = kosmos.devicePostureController.verifyCallback()
- tunableCallback = kosmos.tunerService.captureCallback()
// Update face auth posture to match config
postureControllerCallback.onPostureChanged(DEVICE_POSTURE_CLOSED)
// FACE_UNLOCK_DISMISSES_KEYGUARD setting true
- whenever(kosmos.tunerService.getValue(eq(faceUnlockDismissesKeyguard), anyInt()))
- .thenReturn(1)
- tunableCallback.onTuningChanged(faceUnlockDismissesKeyguard, "")
+ kosmos.userAwareSecureSettingsRepository.setBoolean(
+ Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
+ true,
+ )
runCurrent()
// Assert bypass enabled
assertThat(bypassEnabled).isTrue()
// FACE_UNLOCK_DISMISSES_KEYGUARD setting false
- whenever(kosmos.tunerService.getValue(eq(faceUnlockDismissesKeyguard), anyInt()))
- .thenReturn(0)
- tunableCallback.onTuningChanged(faceUnlockDismissesKeyguard, "")
+ kosmos.userAwareSecureSettingsRepository.setBoolean(
+ Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
+ false,
+ )
runCurrent()
// Assert bypass not enabled
@@ -229,10 +212,3 @@ class KeyguardBypassRepositoryTest : SysuiTestCase() {
private const val FACE_UNLOCK_BYPASS_NEVER = 2
}
}
-
-private const val faceUnlockDismissesKeyguard = Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD
-
-private fun TunerService.captureCallback() =
- withArgCaptor<TunerService.Tunable> {
- verify(this@captureCallback).addTunable(capture(), eq(faceUnlockDismissesKeyguard))
- }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index fc318d56a8d5..aad8b4ba1191 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -49,6 +49,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -2507,17 +2508,54 @@ public class BubblesTest extends SysuiTestCase {
@EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
@Test
- public void testEventLogging_bubbleBar_dragBubbleToDismiss() {
+ public void testEventLogging_bubbleBar_dragSelectedBubbleToDismiss() {
mBubbleProperties.mIsBubbleBarEnabled = true;
mPositioner.setIsLargeScreen(true);
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
mBubbleController.registerBubbleStateListener(bubbleStateListener);
mEntryListener.onEntryAdded(mRow);
- mBubbleController.dragBubbleToDismiss(mRow.getKey(), 1L);
+ mEntryListener.onEntryAdded(mRow2);
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mRow2.getKey(), 0);
+
+ clearInvocations(mBubbleLogger);
+
+ // Dismiss selected bubble
+ mBubbleController.startBubbleDrag(mRow2.getKey());
+ mBubbleController.dragBubbleToDismiss(mRow2.getKey(), System.currentTimeMillis());
+
+ // Log bubble dismissed via drag and new bubble selected
+ verify(mBubbleLogger).log(eqBubbleWithKey(mRow2.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE));
+ verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED));
+
+ verifyNoMoreInteractions(mBubbleLogger);
+ }
+
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void testEventLogging_bubbleBar_dragOtherBubbleToDismiss() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ mEntryListener.onEntryAdded(mRow);
+ mEntryListener.onEntryAdded(mRow2);
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mRow2.getKey(), 0);
+
+ clearInvocations(mBubbleLogger);
+
+ // Dismiss other bubble
+ mBubbleController.startBubbleDrag(mRow.getKey());
+ mBubbleController.dragBubbleToDismiss(mRow.getKey(), System.currentTimeMillis());
+ // Log bubble dismissed via drag, but no switch event
verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE));
+
+ verifyNoMoreInteractions(mBubbleLogger);
}
@EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
@@ -2643,6 +2681,70 @@ public class BubblesTest extends SysuiTestCase {
eq(BubbleLogger.Event.BUBBLE_BAR_EXPANDED));
}
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void testEventLogging_bubbleBar_switchBubble() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ mEntryListener.onEntryAdded(mRow);
+ mEntryListener.onEntryAdded(mRow2);
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mRow.getKey(), 0);
+
+ // First select is expand
+ verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_EXPANDED));
+ verify(mBubbleLogger, never()).log(eqBubbleWithKey(mRow.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED));
+
+ // Second select is switch
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mRow2.getKey(), 0);
+ verify(mBubbleLogger).log(eqBubbleWithKey(mRow2.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED));
+ verify(mBubbleLogger, never()).log(eqBubbleWithKey(mRow2.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_EXPANDED));
+ }
+
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void testEventLogging_bubbleBar_openOverflow() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ mEntryListener.onEntryAdded(mRow);
+
+ clearInvocations(mBubbleLogger);
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(BubbleOverflow.KEY, 0);
+ verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_SELECTED);
+ verifyNoMoreInteractions(mBubbleLogger);
+ }
+
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void testEventLogging_bubbleBar_fromOverflowToBar() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ mEntryListener.onEntryAdded(mRow);
+
+ // Dismiss the bubble so it's in the overflow
+ mBubbleController.removeBubble(
+ mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
+ Bubble overflowBubble = mBubbleData.getOverflowBubbleWithKey(mRow.getKey());
+ assertThat(overflowBubble).isNotNull();
+
+ // Promote overflow bubble and check that it is logged
+ mBubbleController.promoteBubbleFromOverflow(overflowBubble);
+ verify(mBubbleLogger).log(eqBubbleWithKey(overflowBubble.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_REMOVE_BACK_TO_BAR));
+ }
+
/** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/utils/src/android/content/ClipboardManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/content/ClipboardManagerKosmos.kt
new file mode 100644
index 000000000000..379c00842b62
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/android/content/ClipboardManagerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 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.content
+
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+val Kosmos.clipboardManager by Kosmos.Fixture { mock<ClipboardManager>() }
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt
index 796ec9400249..45dcb28b23ee 100644
--- a/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt
@@ -16,7 +16,12 @@
package android.hardware.display
+import android.view.Display
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import org.mockito.kotlin.mock
val Kosmos.displayManager by Kosmos.Fixture { mock<DisplayManager>() }
+
+val Kosmos.defaultDisplay: Display by Kosmos.Fixture { mock<Display>() }
+
+val Kosmos.rearDisplay: Display by Kosmos.Fixture { mock<Display>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt
index 9c55820b797c..b8a095eae23e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui
import android.hardware.devicestate.DeviceState
import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY
+import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED
@@ -44,7 +45,7 @@ val Kosmos.foldedDeviceStateList by
.setSystemProperties(
setOf(
PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
- PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
+ PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP,
)
)
.setPhysicalProperties(
@@ -57,7 +58,7 @@ val Kosmos.foldedDeviceStateList by
.setSystemProperties(
setOf(
PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
- PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
+ PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP,
)
)
.setPhysicalProperties(
@@ -70,14 +71,14 @@ val Kosmos.foldedDeviceStateList by
.setSystemProperties(
setOf(
PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
- PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
+ PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP,
)
)
.setPhysicalProperties(
setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
)
.build()
- )
+ ),
)
}
@@ -88,7 +89,7 @@ val Kosmos.halfFoldedDeviceState by
.setSystemProperties(
setOf(
PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
- PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE
+ PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE,
)
)
.setPhysicalProperties(
@@ -105,7 +106,7 @@ val Kosmos.unfoldedDeviceState by
.setSystemProperties(
setOf(
PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
- PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE
+ PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE,
)
)
.setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN))
@@ -120,7 +121,22 @@ val Kosmos.rearDisplayDeviceState by
.setSystemProperties(
setOf(
PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
- PROPERTY_FEATURE_REAR_DISPLAY
+ PROPERTY_FEATURE_REAR_DISPLAY,
+ )
+ )
+ .build()
+ )
+ }
+
+val Kosmos.rearDisplayOuterDefaultDeviceState by
+ Kosmos.Fixture {
+ DeviceState(
+ DeviceState.Configuration.Builder(5 /* identifier */, "REAR_DISPLAY")
+ .setSystemProperties(
+ setOf(
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
+ PROPERTY_FEATURE_REAR_DISPLAY,
+ PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT,
)
)
.build()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt
new file mode 100644
index 000000000000..6f5985536fe7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.reardisplay.RearDisplayInnerDialogDelegate
+import org.mockito.kotlin.mock
+
+val Kosmos.rearDisplayInnerDialogDelegateFactory by
+ Kosmos.Fixture { mock<RearDisplayInnerDialogDelegate.Factory>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
index 2198e04eaf8a..35e85bb1e68d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
@@ -18,10 +18,11 @@ package com.android.systemui.brightness.ui.viewmodel
import com.android.systemui.brightness.domain.interactor.brightnessPolicyEnforcementInteractor
import com.android.systemui.brightness.domain.interactor.screenBrightnessInteractor
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor
-import com.android.systemui.kosmos.brightnessWarningToast
+import com.android.systemui.settings.brightness.ui.brightnessWarningToast
val Kosmos.brightnessSliderViewModelFactory: BrightnessSliderViewModel.Factory by
Kosmos.Fixture {
@@ -33,6 +34,7 @@ val Kosmos.brightnessSliderViewModelFactory: BrightnessSliderViewModel.Factory b
hapticsViewModelFactory = sliderHapticsViewModelFactory,
brightnessMirrorShowingInteractor = brightnessMirrorShowingInteractor,
supportsMirroring = allowsMirroring,
+ falsingInteractor = falsingInteractor,
brightnessWarningToast = brightnessWarningToast,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryKosmos.kt
new file mode 100644
index 000000000000..3ce119576096
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/development/data/repository/DevelopmentSettingRepositoryKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.development.data.repository
+
+import android.os.userManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.util.settings.fakeGlobalSettings
+
+val Kosmos.developmentSettingRepository by
+ Kosmos.Fixture { DevelopmentSettingRepository(fakeGlobalSettings, userManager, testDispatcher) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt
new file mode 100644
index 000000000000..aa4dd18a6cba
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.development.domain.interactor
+
+import android.content.clipboardManager
+import android.content.res.mainResources
+import com.android.systemui.development.data.repository.developmentSettingRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.user.data.repository.userRepository
+
+val Kosmos.buildNumberInteractor by
+ Kosmos.Fixture {
+ BuildNumberInteractor(
+ developmentSettingRepository,
+ mainResources,
+ userRepository,
+ { clipboardManager },
+ testDispatcher,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModelKosmos.kt
new file mode 100644
index 000000000000..c827311a6ac3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.development.ui.viewmodel
+
+import com.android.systemui.development.domain.interactor.buildNumberInteractor
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.buildNumberViewModelFactory by
+ Kosmos.Fixture {
+ object : BuildNumberViewModel.Factory {
+ override fun create(): BuildNumberViewModel {
+ return BuildNumberViewModel(buildNumberInteractor)
+ }
+ }
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
index 92dc89747db8..7fd927654ca6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
@@ -35,4 +35,9 @@ class FakeDisplayWindowPropertiesRepository : DisplayWindowPropertiesRepository
)
.also { properties.put(displayId, windowType, it) }
}
+
+ /** Sets an instance, just for testing purposes. */
+ fun insert(instance: DisplayWindowProperties) {
+ properties.put(instance.displayId, instance.windowType, instance)
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt
new file mode 100644
index 000000000000..b24b3ad05117
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.ui.viewmodel
+
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+
+val Kosmos.dreamUserActionsViewModel by
+ Kosmos.Fixture {
+ DreamUserActionsViewModel(
+ deviceUnlockedInteractor = deviceUnlockedInteractor,
+ shadeInteractor = shadeInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
index 32469b6cfc30..ad38bbeba1a8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
@@ -23,13 +23,13 @@ import java.io.PrintWriter
class FakeFeatureFlagsClassic : FakeFeatureFlags()
+val FeatureFlagsClassic.fake
+ get() = this as FakeFeatureFlagsClassic
+
@Deprecated(
message = "Use FakeFeatureFlagsClassic instead.",
replaceWith =
- ReplaceWith(
- "FakeFeatureFlagsClassic",
- "com.android.systemui.flags.FakeFeatureFlagsClassic",
- ),
+ ReplaceWith("FakeFeatureFlagsClassic", "com.android.systemui.flags.FakeFeatureFlagsClassic"),
)
open class FakeFeatureFlags : FeatureFlagsClassic {
private val booleanFlags = mutableMapOf<String, Boolean>()
@@ -105,6 +105,7 @@ open class FakeFeatureFlags : FeatureFlagsClassic {
listener.onFlagChanged(
object : FlagListenable.FlagEvent {
override val flagName = flag.name
+
override fun requestNoRestart() {}
}
)
@@ -165,7 +166,7 @@ open class FakeFeatureFlags : FeatureFlagsClassic {
@Module(includes = [FakeFeatureFlagsClassicModule.Bindings::class])
class FakeFeatureFlagsClassicModule(
- @get:Provides val fakeFeatureFlagsClassic: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic(),
+ @get:Provides val fakeFeatureFlagsClassic: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic()
) {
constructor(
@@ -175,7 +176,9 @@ class FakeFeatureFlagsClassicModule(
@Module
interface Bindings {
@Binds fun bindFake(fake: FakeFeatureFlagsClassic): FeatureFlagsClassic
+
@Binds fun bindClassic(classic: FeatureFlagsClassic): FeatureFlags
+
@Binds fun bindFakeClassic(fake: FakeFeatureFlagsClassic): FakeFeatureFlags
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
index f52f039b6758..721c0b8339db 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -24,6 +24,7 @@ import android.view.windowManager
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.InputGestureMaps
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesUtils
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperTestHelper
@@ -101,6 +102,11 @@ val Kosmos.defaultShortcutCategoriesRepository by
)
}
+val Kosmos.inputGestureMaps by
+ Kosmos.Fixture {
+ InputGestureMaps(applicationContext)
+ }
+
val Kosmos.customShortcutCategoriesRepository by
Kosmos.Fixture {
CustomShortcutCategoriesRepository(
@@ -109,6 +115,8 @@ val Kosmos.customShortcutCategoriesRepository by
applicationCoroutineScope,
testDispatcher,
shortcutCategoriesUtils,
+ applicationContext,
+ inputGestureMaps
)
}
@@ -135,7 +143,11 @@ val Kosmos.shortcutHelperStateInteractor by
}
val Kosmos.shortcutHelperCategoriesInteractor by
- Kosmos.Fixture { ShortcutHelperCategoriesInteractor(defaultShortcutCategoriesRepository) }
+ Kosmos.Fixture {
+ ShortcutHelperCategoriesInteractor(defaultShortcutCategoriesRepository) {
+ customShortcutCategoriesRepository
+ }
+ }
val Kosmos.shortcutHelperViewModel by
Kosmos.Fixture {
@@ -161,13 +173,17 @@ val Kosmos.shortcutCustomizationDialogStarterFactory by
}
}
-val Kosmos.shortcutCustomizationInteractor by Kosmos.Fixture { ShortcutCustomizationInteractor() }
+val Kosmos.shortcutCustomizationInteractor by
+ Kosmos.Fixture { ShortcutCustomizationInteractor(customShortcutCategoriesRepository) }
val Kosmos.shortcutCustomizationViewModelFactory by
Kosmos.Fixture {
object : ShortcutCustomizationViewModel.Factory {
override fun create(): ShortcutCustomizationViewModel {
- return ShortcutCustomizationViewModel(shortcutCustomizationInteractor)
+ return ShortcutCustomizationViewModel(
+ applicationContext,
+ shortcutCustomizationInteractor,
+ )
}
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt
index c91823cc2999..0de456be7477 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt
@@ -25,8 +25,8 @@ import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
-import com.android.systemui.tuner.tunerService
import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -37,7 +37,7 @@ val Kosmos.keyguardBypassRepository: KeyguardBypassRepository by Fixture {
biometricSettingsRepository,
devicePostureRepository,
dumpManager,
- tunerService,
+ userAwareSecureSettingsRepository,
testDispatcher,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
index 769612c988ba..255a780a84be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
@@ -30,7 +30,7 @@ import com.android.systemui.shade.pulsingGestureListener
val Kosmos.keyguardTouchHandlingInteractor by
Kosmos.Fixture {
KeyguardTouchHandlingInteractor(
- appContext = applicationContext,
+ context = applicationContext,
scope = applicationCoroutineScope,
transitionInteractor = keyguardTransitionInteractor,
repository = keyguardRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
index b5e6f75c7915..c0b39b1df7d5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.content.applicationContext
import android.content.res.mainResources
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
@@ -28,12 +29,13 @@ import com.android.systemui.statusbar.ui.systemBarUtilsProxy
val Kosmos.keyguardClockViewModel by
Kosmos.Fixture {
KeyguardClockViewModel(
+ context = applicationContext,
keyguardClockInteractor = keyguardClockInteractor,
applicationScope = applicationCoroutineScope,
aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
shadeInteractor = shadeInteractor,
systemBarUtils = systemBarUtilsProxy,
configurationInteractor = configurationInteractor,
- resources = mainResources
+ resources = mainResources,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
index d33d594d9e8a..76e2cc8b7bd0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.keyguard.domain.interactor.keyguardSmartspaceInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.util.mockito.mock
val Kosmos.keyguardSmartspaceViewModel by
@@ -28,5 +29,6 @@ val Kosmos.keyguardSmartspaceViewModel by
smartspaceController = mock(),
keyguardClockViewModel = keyguardClockViewModel,
smartspaceInteractor = keyguardSmartspaceInteractor,
+ shadeInteractor = shadeInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
index a25b29fd18cb..2311c0a23db8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
@@ -20,6 +20,7 @@ import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
val Kosmos.lockscreenUserActionsViewModel by Fixture {
@@ -27,5 +28,6 @@ val Kosmos.lockscreenUserActionsViewModel by Fixture {
deviceEntryInteractor = deviceEntryInteractor,
communalInteractor = communalInteractor,
shadeInteractor = shadeInteractor,
+ occlusionInteractor = sceneContainerOcclusionInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
index f43841b31c2e..1556058d51ba 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
@@ -1,10 +1,11 @@
package com.android.systemui.kosmos
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.FlowValue
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.settings.brightness.ui.BrightnessWarningToast
-
import com.android.systemui.util.mockito.mock
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.flow.Flow
@@ -35,15 +36,15 @@ fun Kosmos.useStandardTestDispatcher() = apply { testDispatcher = StandardTestDi
fun Kosmos.useUnconfinedTestDispatcher() = apply { testDispatcher = UnconfinedTestDispatcher() }
var Kosmos.testScope by Fixture { TestScope(testDispatcher) }
-var Kosmos.applicationCoroutineScope by Fixture { testScope.backgroundScope }
+var Kosmos.backgroundScope by Fixture { testScope.backgroundScope }
+var Kosmos.applicationCoroutineScope by Fixture { backgroundScope }
var Kosmos.testCase: SysuiTestCase by Fixture()
var Kosmos.backgroundCoroutineContext: CoroutineContext by Fixture {
- testScope.backgroundScope.coroutineContext
+ backgroundScope.coroutineContext
}
var Kosmos.mainCoroutineContext: CoroutineContext by Fixture { testScope.coroutineContext }
-var Kosmos.brightnessWarningToast: BrightnessWarningToast by Kosmos.Fixture {
- mock<BrightnessWarningToast>()
-}
+var Kosmos.brightnessWarningToast: BrightnessWarningToast by
+ Kosmos.Fixture { mock<BrightnessWarningToast>() }
/**
* Run this test body with a [Kosmos] as receiver, and using the [testScope] currently installed in
@@ -55,3 +56,5 @@ fun Kosmos.runTest(testBody: suspend Kosmos.() -> Unit) =
fun Kosmos.runCurrent() = testScope.runCurrent()
fun <T> Kosmos.collectLastValue(flow: Flow<T>) = testScope.collectLastValue(flow)
+
+fun <T> Kosmos.collectValues(flow: Flow<T>): FlowValue<List<T>> = testScope.collectValues(flow)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 63e6eb6c0ef5..3d60abf59d62 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -71,14 +71,19 @@ import com.android.systemui.shade.shadeController
import com.android.systemui.shade.ui.viewmodel.notificationShadeWindowModel
import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
+import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
+import com.android.systemui.statusbar.phone.keyguardBypassController
import com.android.systemui.statusbar.phone.scrimController
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.fakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiInteractor
+import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
import com.android.systemui.statusbar.ui.viewmodel.keyguardStatusBarViewModel
@@ -105,6 +110,7 @@ class KosmosJavaAdapter() {
val testScope by lazy { kosmos.testScope }
val fakeExecutor by lazy { kosmos.fakeExecutor }
val fakeExecutorHandler by lazy { kosmos.fakeExecutorHandler }
+ val configurationController by lazy { kosmos.configurationController }
val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
val configurationInteractor by lazy { kosmos.configurationInteractor }
val bouncerRepository by lazy { kosmos.bouncerRepository }
@@ -115,13 +121,14 @@ class KosmosJavaAdapter() {
val seenNotificationsInteractor by lazy { kosmos.seenNotificationsInteractor }
val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
val keyguardBouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository }
+ val keyguardBypassController by lazy { kosmos.keyguardBypassController }
val keyguardInteractor by lazy { kosmos.keyguardInteractor }
val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor }
val keyguardStatusBarViewModel by lazy { kosmos.keyguardStatusBarViewModel }
val powerRepository by lazy { kosmos.fakePowerRepository }
val clock by lazy { kosmos.systemClock }
- val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository }
+ val mobileConnectionsRepository by lazy { kosmos.mobileConnectionsRepository }
val simBouncerInteractor by lazy { kosmos.simBouncerInteractor }
val statusBarStateController by lazy { kosmos.statusBarStateController }
val statusBarModePerDisplayRepository by lazy { kosmos.fakeStatusBarModePerDisplayRepository }
@@ -158,6 +165,7 @@ class KosmosJavaAdapter() {
val shadeRepository by lazy { kosmos.shadeRepository }
val shadeInteractor by lazy { kosmos.shadeInteractor }
val notificationShadeWindowModel by lazy { kosmos.notificationShadeWindowModel }
+ val visualStabilityProvider by lazy { kosmos.visualStabilityProvider }
val wifiInteractor by lazy { kosmos.wifiInteractor }
val fakeWifiRepository by lazy { kosmos.fakeWifiRepository }
val volumeDialogInteractor by lazy { kosmos.volumeDialogInteractor }
@@ -177,4 +185,6 @@ class KosmosJavaAdapter() {
val lockscreenToGlanceableHubTransitionViewModel by lazy {
kosmos.lockscreenToGlanceableHubTransitionViewModel
}
+ val disableFlagsInteractor by lazy { kosmos.disableFlagsInteractor }
+ val fakeDisableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
index d631f926176d..e6256a58a365 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.mediaprojection.data.repository
import android.app.ActivityManager
+import android.media.projection.StopReason
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import kotlinx.coroutines.flow.MutableStateFlow
@@ -28,7 +29,7 @@ class FakeMediaProjectionRepository : MediaProjectionRepository {
var stopProjectingInvoked = false
- override suspend fun stopProjecting() {
+ override suspend fun stopProjecting(@StopReason stopReason: Int) {
stopProjectingInvoked = true
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
index 4ed491233f3c..c574463eb258 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
@@ -18,10 +18,12 @@ package com.android.systemui.qs.composefragment.viewmodel
import android.content.res.mainResources
import androidx.lifecycle.LifecycleCoroutineScope
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.media.controls.ui.view.qqsMediaHost
import com.android.systemui.media.controls.ui.view.qsMediaHost
import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragment
@@ -33,7 +35,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.mediaInRowInLandscapeViewMode
import com.android.systemui.qs.ui.viewmodel.quickSettingsContainerViewModelFactory
import com.android.systemui.shade.largeScreenHeaderHelper
import com.android.systemui.shade.transition.largeScreenShadeInterpolator
-import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
import com.android.systemui.statusbar.sysuiStatusBarStateController
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -51,13 +53,15 @@ val Kosmos.qsFragmentComposeViewModelFactory by
footerActionsController,
sysuiStatusBarStateController,
deviceEntryInteractor,
- disableFlagsRepository,
+ disableFlagsInteractor,
keyguardTransitionInteractor,
largeScreenShadeInterpolator,
configurationInteractor,
largeScreenHeaderHelper,
tileSquishinessInteractor,
+ falsingInteractor,
inFirstPageViewModel,
+ logcatTableLogBuffer(this@Fixture),
mediaInRowInLandscapeViewModelFactory,
qqsMediaHost,
qsMediaHost,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt
new file mode 100644
index 000000000000..b8d3ff425f20
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.viewmodel
+
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.editModeButtonViewModelFactory by
+ Kosmos.Fixture {
+ object : EditModeButtonViewModel.Factory {
+ override fun create(): EditModeButtonViewModel {
+ return EditModeButtonViewModel(editModeViewModel, falsingInteractor)
+ }
+ }
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
index 0e5edb75846d..5c71ba2f8bbd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
@@ -16,6 +16,8 @@
package com.android.systemui.qs.panels.ui.viewmodel
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
+import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.qs.panels.domain.interactor.paginatedGridInteractor
@@ -26,5 +28,8 @@ val Kosmos.paginatedGridViewModel by
qsColumnsViewModelFactory,
paginatedGridInteractor,
inFirstPageViewModel,
+ buildNumberViewModelFactory,
+ editModeButtonViewModelFactory,
+ falsingInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorKosmos.kt
new file mode 100644
index 000000000000..12d4e90dc469
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.scene.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
+
+val Kosmos.disabledContentInteractor by Fixture {
+ DisabledContentInteractor(disableFlagsInteractor = disableFlagsInteractor)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
index f84c3bdfdaf1..eb352baab0e4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
@@ -33,5 +33,6 @@ val Kosmos.sceneInteractor: SceneInteractor by
sceneFamilyResolvers = { sceneFamilyResolvers },
deviceUnlockedInteractor = { deviceUnlockedInteractor },
keyguardEnabledInteractor = { keyguardEnabledInteractor },
+ disabledContentInteractor = disabledContentInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
index 8b124258909a..a4a63ec6ca21 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
@@ -21,6 +21,7 @@ package com.android.systemui.scene.domain.resolver
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.scene.shared.model.SceneFamilies
@@ -34,6 +35,7 @@ val Kosmos.homeSceneFamilyResolver by
HomeSceneFamilyResolver(
applicationScope = applicationCoroutineScope,
deviceEntryInteractor = deviceEntryInteractor,
+ keyguardInteractor = keyguardInteractor,
keyguardEnabledInteractor = keyguardEnabledInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
index 7e6a7271c561..82b5f6332b23 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
@@ -37,6 +37,7 @@ import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.domain.interactor.disabledContentInteractor
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -83,5 +84,6 @@ val Kosmos.sceneContainerStartable by Fixture {
alternateBouncerInteractor = alternateBouncerInteractor,
vibratorHelper = vibratorHelper,
msdlPlayer = msdlPlayer,
+ disabledContentInteractor = disabledContentInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
index aac122c6610c..5d146fbffaca 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
@@ -21,9 +21,9 @@ import com.android.systemui.classifier.falsingManager
import com.android.systemui.haptics.msdl.msdlPlayer
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.brightnessWarningToast
import com.android.systemui.plugins.activityStarter
import com.android.systemui.settings.brightness.BrightnessSliderController
+import com.android.systemui.settings.brightness.ui.brightnessWarningToast
import com.android.systemui.util.time.systemClock
/** This factory creates empty mocks. */
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToastKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToastKosmos.kt
new file mode 100644
index 000000000000..d9acb527522a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToastKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.settings.brightness.ui
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.brightnessWarningToast: BrightnessWarningToast by
+ Kosmos.Fixture { mock<BrightnessWarningToast>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 39f58aea82ef..af6d6249b4a8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -25,7 +25,7 @@ import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.ShadeModule
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
import com.android.systemui.statusbar.phone.dozeParameters
import com.android.systemui.statusbar.policy.data.repository.userSetupRepository
import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
@@ -60,7 +60,7 @@ val Kosmos.shadeInteractorImpl by
ShadeInteractorImpl(
scope = applicationCoroutineScope,
deviceProvisioningInteractor = deviceProvisioningInteractor,
- disableFlagsRepository = disableFlagsRepository,
+ disableFlagsInteractor = disableFlagsInteractor,
dozeParams = dozeParameters,
keyguardRepository = fakeKeyguardRepository,
keyguardTransitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
index 466a3eb83e95..9dbb547a434d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
@@ -15,7 +15,7 @@
package com.android.systemui.statusbar.disableflags.data.repository
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
import dagger.Binds
import dagger.Module
import javax.inject.Inject
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt
new file mode 100644
index 000000000000..7b4b047c130a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.statusbar.disableflags.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
+
+val Kosmos.disableFlagsInteractor by Fixture {
+ DisableFlagsInteractor(repository = disableFlagsRepository)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
index 32c582f79ed7..2ec801620212 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.data.model
import android.app.PendingIntent
import android.graphics.drawable.Icon
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import com.android.systemui.statusbar.notification.shared.CallType
import com.android.systemui.statusbar.notification.stack.BUCKET_UNKNOWN
@@ -46,6 +47,7 @@ fun activeNotificationModel(
contentIntent: PendingIntent? = null,
bucket: Int = BUCKET_UNKNOWN,
callType: CallType = CallType.None,
+ promotedContent: PromotedNotificationContentModel? = null,
) =
ActiveNotificationModel(
key = key,
@@ -69,4 +71,5 @@ fun activeNotificationModel(
isGroupSummary = isGroupSummary,
bucket = bucket,
callType = callType,
+ promotedContent = promotedContent,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt
index 090ce31bd43c..951ae59ebcf1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt
@@ -16,9 +16,36 @@
package com.android.systemui.statusbar.phone
+import android.content.Context
+import android.os.Handler
+import android.view.IWindowManager
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.fakeDisplayWindowPropertiesRepository
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.kosmos.applicationCoroutineScope
+import org.mockito.Mockito.mock
-val Kosmos.mockAutoHideController by Kosmos.Fixture { mock<AutoHideController>() }
+val Kosmos.mockAutoHideController: AutoHideController by
+ Kosmos.Fixture { mock(AutoHideController::class.java) }
var Kosmos.autoHideController by Kosmos.Fixture { mockAutoHideController }
+
+val Kosmos.fakeAutoHideControllerFactory by Kosmos.Fixture { FakeAutoHideControllerFactory() }
+
+val Kosmos.multiDisplayAutoHideControllerStore by
+ Kosmos.Fixture {
+ MultiDisplayAutoHideControllerStore(
+ applicationCoroutineScope,
+ displayRepository,
+ fakeDisplayWindowPropertiesRepository,
+ fakeAutoHideControllerFactory,
+ )
+ }
+
+class FakeAutoHideControllerFactory :
+ AutoHideControllerImpl.Factory(mock(Handler::class.java), mock(IWindowManager::class.java)) {
+
+ override fun create(context: Context): AutoHideControllerImpl {
+ return mock(AutoHideControllerImpl::class.java)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt
index d76defef3c97..99ed4f0db64d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.pipeline.airplane.domain.interactor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
val Kosmos.airplaneModeInteractor: AirplaneModeInteractor by
@@ -26,6 +26,6 @@ val Kosmos.airplaneModeInteractor: AirplaneModeInteractor by
AirplaneModeInteractor(
FakeAirplaneModeRepository(),
FakeConnectivityRepository(),
- fakeMobileConnectionsRepository,
+ mobileConnectionsRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index de73d3397db3..bfd46b664242 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -77,11 +77,7 @@ class FakeMobileConnectionsRepository(
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
return subIdRepos[subId]
- ?: FakeMobileConnectionRepository(
- subId,
- tableLogBuffer,
- )
- .also { subIdRepos[subId] = it }
+ ?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
}
override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())
@@ -135,3 +131,6 @@ class FakeMobileConnectionsRepository(
const val LTE_ADVANCED_PRO = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
}
}
+
+val MobileConnectionsRepository.fake
+ get() = this as FakeMobileConnectionsRepository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt
index cd22f1dd6acc..b952d71b157e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt
@@ -19,12 +19,20 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+
+val Kosmos.mobileMappingsProxy: MobileMappingsProxy by Fixture { FakeMobileMappingsProxy() }
+
+var Kosmos.mobileConnectionsRepositoryLogbufferName by Fixture { "FakeMobileConnectionsRepository" }
val Kosmos.fakeMobileConnectionsRepository by Fixture {
FakeMobileConnectionsRepository(
- tableLogBuffer = logcatTableLogBuffer(this, "FakeMobileConnectionsRepository"),
+ mobileMappings = mobileMappingsProxy,
+ tableLogBuffer = logcatTableLogBuffer(this, mobileConnectionsRepositoryLogbufferName),
)
}
-val Kosmos.mobileConnectionsRepository by
- Fixture<MobileConnectionsRepository> { fakeMobileConnectionsRepository }
+val Kosmos.mobileConnectionsRepository: MobileConnectionsRepository by Fixture {
+ fakeMobileConnectionsRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
index 8e656cf002ce..00bfa994aabd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
@@ -18,7 +18,5 @@ package com.android.systemui.statusbar.pipeline.shared.data.repository
import com.android.systemui.kosmos.Kosmos
-val Kosmos.fakeConnectivityRepository: FakeConnectivityRepository by
- Kosmos.Fixture { FakeConnectivityRepository() }
val Kosmos.connectivityRepository: ConnectivityRepository by
- Kosmos.Fixture { fakeConnectivityRepository }
+ Kosmos.Fixture { FakeConnectivityRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
index 331e2fad19cb..c69d9a29a9b4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
@@ -42,10 +42,7 @@ class FakeConnectivityRepository : ConnectivityRepository {
* validated
*/
@JvmOverloads
- fun setMobileConnected(
- default: Boolean = true,
- validated: Boolean = true,
- ) {
+ fun setMobileConnected(default: Boolean = true, validated: Boolean = true) {
defaultConnections.value =
DefaultConnectionModel(
mobile = DefaultConnectionModel.Mobile(default),
@@ -55,10 +52,7 @@ class FakeConnectivityRepository : ConnectivityRepository {
/** Similar convenience method for ethernet */
@JvmOverloads
- fun setEthernetConnected(
- default: Boolean = true,
- validated: Boolean = true,
- ) {
+ fun setEthernetConnected(default: Boolean = true, validated: Boolean = true) {
defaultConnections.value =
DefaultConnectionModel(
ethernet = DefaultConnectionModel.Ethernet(default),
@@ -67,10 +61,7 @@ class FakeConnectivityRepository : ConnectivityRepository {
}
@JvmOverloads
- fun setWifiConnected(
- default: Boolean = true,
- validated: Boolean = true,
- ) {
+ fun setWifiConnected(default: Boolean = true, validated: Boolean = true) {
defaultConnections.value =
DefaultConnectionModel(
wifi = DefaultConnectionModel.Wifi(default),
@@ -78,3 +69,6 @@ class FakeConnectivityRepository : ConnectivityRepository {
)
}
}
+
+val ConnectivityRepository.fake
+ get() = this as FakeConnectivityRepository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
index 385a813996ff..13fde9608017 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.shared.domain.interactor
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
val Kosmos.collapsedStatusBarInteractor: CollapsedStatusBarInteractor by
- Kosmos.Fixture { CollapsedStatusBarInteractor(fakeDisableFlagsRepository) }
+ Kosmos.Fixture { CollapsedStatusBarInteractor(disableFlagsInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
index 528c9d9ec64d..a110a49ccba8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
@@ -27,6 +27,9 @@ class FakeStatusBarWindowController : StatusBarWindowController {
var isAttached = false
private set
+ var isStopped = false
+ private set
+
override val statusBarHeight: Int = 0
override fun refreshStatusBarHeight() {}
@@ -35,6 +38,10 @@ class FakeStatusBarWindowController : StatusBarWindowController {
isAttached = true
}
+ override fun stop() {
+ isStopped = true
+ }
+
override fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams) {}
override val backgroundView: View
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
index 173e909e3b3f..23f2b4221825 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
@@ -18,7 +18,8 @@ package com.android.systemui.statusbar.window
import android.content.testableContext
import android.view.windowManagerService
-import com.android.app.viewcapture.viewCaptureAwareWindowManager
+import com.android.app.viewcapture.realCaptureAwareWindowManager
+import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.fragments.fragmentService
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.phone.statusBarContentInsetsProvider
@@ -32,12 +33,13 @@ val Kosmos.statusBarWindowControllerImpl by
StatusBarWindowControllerImpl(
testableContext,
statusBarWindowViewInflater,
- viewCaptureAwareWindowManager,
+ realCaptureAwareWindowManager,
statusBarConfigurationController,
windowManagerService,
statusBarContentInsetsProvider,
fragmentService,
Optional.empty(),
+ fakeExecutor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt
new file mode 100644
index 000000000000..4941ceb7991d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 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.statusbar.window
+
+import android.view.WindowManager
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
+import com.android.app.viewcapture.realCaptureAwareWindowManager
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.displayWindowPropertiesRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.data.repository.statusBarConfigurationControllerStore
+import com.android.systemui.statusbar.data.repository.statusBarContentInsetsProviderStore
+import org.mockito.kotlin.mock
+
+val Kosmos.multiDisplayStatusBarWindowControllerStore by
+ Kosmos.Fixture {
+ MultiDisplayStatusBarWindowControllerStore(
+ backgroundApplicationScope = applicationCoroutineScope,
+ controllerFactory = { _, _, _, _ -> mock() },
+ displayWindowPropertiesRepository = displayWindowPropertiesRepository,
+ viewCaptureAwareWindowManagerFactory =
+ object : ViewCaptureAwareWindowManager.Factory {
+ override fun create(
+ windowManager: WindowManager
+ ): ViewCaptureAwareWindowManager {
+ return realCaptureAwareWindowManager
+ }
+ },
+ statusBarConfigurationControllerStore = statusBarConfigurationControllerStore,
+ statusBarContentInsetsProviderStore = statusBarContentInsetsProviderStore,
+ displayRepository = displayRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
index 65f4122f773e..21a910b67dff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
@@ -16,6 +16,8 @@
package com.android.systemui.util.settings;
+import static com.android.systemui.util.settings.JavaAdapter.newCoroutineScope;
+
import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
import android.annotation.NonNull;
@@ -25,6 +27,7 @@ import android.database.ContentObserver;
import android.net.Uri;
import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
import java.util.ArrayList;
import java.util.HashMap;
@@ -34,7 +37,7 @@ import java.util.Map;
public class FakeGlobalSettings implements GlobalSettings {
private final Map<String, String> mValues = new HashMap<>();
private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>();
- private final CoroutineDispatcher mDispatcher;
+ private final CoroutineScope mSettingsScope;
public static final Uri CONTENT_URI = Uri.parse("content://settings/fake_global");
@@ -44,11 +47,15 @@ public class FakeGlobalSettings implements GlobalSettings {
*/
@Deprecated
public FakeGlobalSettings() {
- mDispatcher = StandardTestDispatcher(/* scheduler = */ null, /* name = */ null);
+ CoroutineDispatcher dispatcher = StandardTestDispatcher(
+ /* scheduler = */ null,
+ /* name = */ null
+ );
+ mSettingsScope = newCoroutineScope(dispatcher);
}
public FakeGlobalSettings(CoroutineDispatcher dispatcher) {
- mDispatcher = dispatcher;
+ mSettingsScope = newCoroutineScope(dispatcher);
}
@NonNull
@@ -61,8 +68,8 @@ public class FakeGlobalSettings implements GlobalSettings {
@NonNull
@Override
- public CoroutineDispatcher getBackgroundDispatcher() {
- return mDispatcher;
+ public CoroutineScope getSettingsScope() {
+ return mSettingsScope;
}
@Override
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
index 35fa2af7639f..78b78ca86a8d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
@@ -19,5 +19,14 @@ package com.android.systemui.util.settings
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testDispatcher
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
val Kosmos.fakeGlobalSettings: FakeGlobalSettings by Fixture { FakeGlobalSettings(testDispatcher) }
+
+object JavaAdapter {
+ @JvmStatic
+ fun newCoroutineScope(context: CoroutineContext): CoroutineScope {
+ return CoroutineScope(context)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
index e5d113be7ca2..a3572754ab19 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
@@ -24,6 +24,7 @@ import android.util.Pair
import androidx.annotation.VisibleForTesting
import com.android.systemui.util.settings.SettingsProxy.CurrentUserIdProvider
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
@@ -33,7 +34,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
private val contentObservers = mutableMapOf<SettingsKey, MutableList<ContentObserver>>()
private val contentObserversAllUsers = mutableMapOf<String, MutableList<ContentObserver>>()
- override val backgroundDispatcher: CoroutineDispatcher
+ override val settingsScope: CoroutineScope
@UserIdInt override var userId = UserHandle.USER_CURRENT
override val currentUserProvider: CurrentUserIdProvider
@@ -43,17 +44,17 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
by main test scope."""
)
constructor() {
- backgroundDispatcher = StandardTestDispatcher(scheduler = null, name = null)
+ settingsScope = CoroutineScope(StandardTestDispatcher(scheduler = null, name = null))
currentUserProvider = CurrentUserIdProvider { userId }
}
constructor(dispatcher: CoroutineDispatcher) {
- backgroundDispatcher = dispatcher
+ settingsScope = CoroutineScope(dispatcher)
currentUserProvider = CurrentUserIdProvider { userId }
}
constructor(dispatcher: CoroutineDispatcher, currentUserProvider: CurrentUserIdProvider) {
- backgroundDispatcher = dispatcher
+ settingsScope = CoroutineScope(dispatcher)
this.currentUserProvider = currentUserProvider
}
@@ -77,7 +78,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
uri: Uri,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) {
if (userHandle == UserHandle.USER_ALL) {
contentObserversAllUsers
@@ -107,31 +108,31 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
override suspend fun registerContentObserver(
uri: Uri,
notifyForDescendants: Boolean,
- settingsObserver: ContentObserver
+ settingsObserver: ContentObserver,
) = suspendAdvanceDispatcher {
super<UserSettingsProxy>.registerContentObserver(
uri,
notifyForDescendants,
- settingsObserver
+ settingsObserver,
)
}
override fun registerContentObserverAsync(
uri: Uri,
notifyForDescendants: Boolean,
- settingsObserver: ContentObserver
+ settingsObserver: ContentObserver,
): Job = advanceDispatcher {
super<UserSettingsProxy>.registerContentObserverAsync(
uri,
notifyForDescendants,
- settingsObserver
+ settingsObserver,
)
}
override suspend fun registerContentObserverForUser(
name: String,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) = suspendAdvanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUser(name, settingsObserver, userHandle)
}
@@ -139,12 +140,12 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
override fun registerContentObserverForUserAsync(
name: String,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
): Job = advanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUserAsync(
name,
settingsObserver,
- userHandle
+ userHandle,
)
}
@@ -156,7 +157,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
override suspend fun registerContentObserverForUser(
uri: Uri,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) = suspendAdvanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUser(uri, settingsObserver, userHandle)
}
@@ -164,12 +165,12 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
override fun registerContentObserverForUserAsync(
uri: Uri,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
): Job = advanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUserAsync(
uri,
settingsObserver,
- userHandle
+ userHandle,
)
}
@@ -177,13 +178,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
uri: Uri,
settingsObserver: ContentObserver,
userHandle: Int,
- registered: Runnable
+ registered: Runnable,
): Job = advanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUserAsync(
uri,
settingsObserver,
userHandle,
- registered
+ registered,
)
}
@@ -191,13 +192,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
name: String,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) = suspendAdvanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUser(
name,
notifyForDescendants,
settingsObserver,
- userHandle
+ userHandle,
)
}
@@ -205,13 +206,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
name: String,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
) = advanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUserAsync(
name,
notifyForDescendants,
settingsObserver,
- userHandle
+ userHandle,
)
}
@@ -219,13 +220,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
uri: Uri,
notifyForDescendants: Boolean,
settingsObserver: ContentObserver,
- userHandle: Int
+ userHandle: Int,
): Job = advanceDispatcher {
super<UserSettingsProxy>.registerContentObserverForUserAsync(
uri,
notifyForDescendants,
settingsObserver,
- userHandle
+ userHandle,
)
}
@@ -259,7 +260,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
tag: String?,
makeDefault: Boolean,
userHandle: Int,
- overrideableByRestore: Boolean
+ overrideableByRestore: Boolean,
): Boolean {
val key = SettingsKey(userHandle, getUriFor(name).toString())
values[key] = value
@@ -275,7 +276,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
name: String,
value: String?,
tag: String?,
- makeDefault: Boolean
+ makeDefault: Boolean,
): Boolean {
return putString(name, value)
}
@@ -293,8 +294,9 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy {
return result
}
+ @OptIn(ExperimentalStdlibApi::class)
private fun testDispatcherRunCurrent() {
- val testDispatcher = backgroundDispatcher as? TestDispatcher
+ val testDispatcher = settingsScope.coroutineContext[CoroutineDispatcher] as? TestDispatcher
testDispatcher?.scheduler?.runCurrent()
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepositoryKosmos.kt
new file mode 100644
index 000000000000..1e8dfa1c9767
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepositoryKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.volumeDialogSliderTouchEventsRepository by
+ Kosmos.Fixture { VolumeDialogSliderTouchEventsRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorKosmo.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorKosmo.kt
new file mode 100644
index 000000000000..39ae5aa3ce1f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInputEventsInteractorKosmo.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.volume.dialog.sliders.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogCallbacksInteractor
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.sliders.data.repository.volumeDialogSliderTouchEventsRepository
+
+val Kosmos.volumeDialogSliderInputEventsInteractor: VolumeDialogSliderInputEventsInteractor by
+ Kosmos.Fixture {
+ VolumeDialogSliderInputEventsInteractor(
+ applicationCoroutineScope,
+ volumeDialogCallbacksInteractor,
+ volumeDialogVisibilityInteractor,
+ volumeDialogSliderTouchEventsRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt
new file mode 100644
index 000000000000..1fb5e77a3210
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.volume.domain.interactor
+
+import android.content.Context
+import androidx.annotation.IntRange
+import com.android.dream.lowlight.dagger.qualifiers.Application
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeAudioSharingInteractor : AudioSharingInteractor {
+ private val mutableInAudioSharing: MutableStateFlow<Boolean> = MutableStateFlow(false)
+ private val mutableVolume: MutableStateFlow<Int?> = MutableStateFlow(null)
+ private var audioSharingVolumeBarAvailable = false
+
+ override val isInAudioSharing: Flow<Boolean> = mutableInAudioSharing
+ override val volume: Flow<Int?> = mutableVolume
+ override val volumeMin: Int = AUDIO_SHARING_VOLUME_MIN
+ override val volumeMax: Int = AUDIO_SHARING_VOLUME_MAX
+
+ override suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean =
+ audioSharingVolumeBarAvailable
+
+ override fun setStreamVolume(
+ @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
+ level: Int
+ ) {}
+
+ override fun handlePrimaryGroupChange() {}
+
+ fun setInAudioSharing(state: Boolean) {
+ mutableInAudioSharing.value = state
+ }
+
+ fun setVolume(volume: Int?) {
+ mutableVolume.value = volume
+ }
+
+ fun setAudioSharingVolumeBarAvailable(available: Boolean) {
+ audioSharingVolumeBarAvailable = available
+ }
+
+ companion object {
+ const val AUDIO_SHARING_VOLUME_MIN = 0
+ const val AUDIO_SHARING_VOLUME_MAX = 255
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 869d854f7b23..9b71f8050c80 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -30,6 +30,8 @@ import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.Runner;
@@ -229,7 +231,9 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase
s.evaluate();
onAfter(description, scope, order, null);
} catch (Throwable t) {
- if (onAfter(description, scope, order, t)) {
+ var shouldReportFailure = RavenwoodCommonUtils.runIgnoringException(
+ () -> onAfter(description, scope, order, t));
+ if (shouldReportFailure == null || shouldReportFailure) {
throw t;
}
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 678a97be60a2..979076eaabfd 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -22,6 +22,8 @@ import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_R
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.parseNullableInt;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
@@ -39,6 +41,7 @@ import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Looper;
@@ -64,6 +67,7 @@ import com.android.ravenwood.common.SneakyThrow;
import com.android.server.LocalServices;
import com.android.server.compat.PlatformCompat;
+import org.junit.internal.management.ManagementFactory;
import org.junit.runner.Description;
import java.io.File;
@@ -154,6 +158,13 @@ public class RavenwoodRuntimeEnvironmentController {
private static RavenwoodAwareTestRunner sRunner;
private static RavenwoodSystemProperties sProps;
+ private static final int DEFAULT_TARGET_SDK_LEVEL = VERSION_CODES.CUR_DEVELOPMENT;
+ private static final String DEFAULT_PACKAGE_NAME = "com.android.ravenwoodtests.defaultname";
+
+ private static int sTargetSdkLevel;
+ private static String sTestPackageName;
+ private static String sTargetPackageName;
+
/**
* Initialize the global environment.
*/
@@ -194,6 +205,8 @@ public class RavenwoodRuntimeEnvironmentController {
// Some process-wide initialization. (maybe redirect stdout/stderr)
RavenwoodCommonUtils.loadJniLibrary(LIBRAVENWOOD_INITIALIZER_NAME);
+ dumpCommandLineArgs();
+
// We haven't initialized liblog yet, so directly write to System.out here.
RavenwoodCommonUtils.log(TAG, "globalInitInner()");
@@ -235,9 +248,22 @@ public class RavenwoodRuntimeEnvironmentController {
System.setProperty("android.junit.runner",
"androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner");
+ loadRavenwoodProperties();
+
assertMockitoVersion();
}
+ private static void loadRavenwoodProperties() {
+ var props = RavenwoodSystemProperties.readProperties("ravenwood.properties");
+
+ sTargetSdkLevel = withDefault(
+ parseNullableInt(props.get("targetSdkVersionInt")), DEFAULT_TARGET_SDK_LEVEL);
+ sTargetPackageName = withDefault(props.get("packageName"), DEFAULT_PACKAGE_NAME);
+ sTestPackageName = withDefault(props.get("instPackageName"), sTargetPackageName);
+
+ // TODO(b/377765941) Read them from the manifest too?
+ }
+
/**
* Initialize the environment.
*/
@@ -256,7 +282,9 @@ public class RavenwoodRuntimeEnvironmentController {
initInner(runner.mState.getConfig());
} catch (Exception th) {
Log.e(TAG, "init() failed", th);
- reset();
+
+ RavenwoodCommonUtils.runIgnoringException(()-> reset());
+
SneakyThrow.sneakyThrow(th);
}
}
@@ -267,6 +295,14 @@ public class RavenwoodRuntimeEnvironmentController {
Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
}
+ config.mTargetPackageName = sTargetPackageName;
+ config.mTestPackageName = sTestPackageName;
+ config.mTargetSdkLevel = sTargetSdkLevel;
+
+ Log.i(TAG, "TargetPackageName=" + sTargetPackageName);
+ Log.i(TAG, "TestPackageName=" + sTestPackageName);
+ Log.i(TAG, "TargetSdkLevel=" + sTargetSdkLevel);
+
RavenwoodRuntimeState.sUid = config.mUid;
RavenwoodRuntimeState.sPid = config.mPid;
RavenwoodRuntimeState.sTargetSdkLevel = config.mTargetSdkLevel;
@@ -349,8 +385,11 @@ public class RavenwoodRuntimeEnvironmentController {
* Partially re-initialize after each test method invocation
*/
public static void reinit() {
- var config = sRunner.mState.getConfig();
- Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid));
+ // sRunner could be null, if there was a failure in the initialization.
+ if (sRunner != null) {
+ var config = sRunner.mState.getConfig();
+ Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid));
+ }
}
private static void initializeCompatIds(RavenwoodConfig config) {
@@ -380,6 +419,9 @@ public class RavenwoodRuntimeEnvironmentController {
/**
* De-initialize.
+ *
+ * Note, we call this method when init() fails too, so this method should deal with
+ * any partially-initialized states.
*/
public static void reset() {
if (RAVENWOOD_VERBOSE_LOGGING) {
@@ -411,7 +453,9 @@ public class RavenwoodRuntimeEnvironmentController {
config.mState.mSystemServerContext.cleanUp();
}
- Looper.getMainLooper().quit();
+ if (Looper.getMainLooper() != null) {
+ Looper.getMainLooper().quit();
+ }
Looper.clearMainLooperForTest();
ActivityManager.reset$ravenwood();
@@ -547,4 +591,18 @@ public class RavenwoodRuntimeEnvironmentController {
+ " access to system property '" + key + "' denied via RavenwoodConfig");
}
}
+
+ private static void dumpCommandLineArgs() {
+ Log.i(TAG, "JVM arguments:");
+
+ // Note, we use the wrapper in JUnit4, not the actual class (
+ // java.lang.management.ManagementFactory), because we can't see the later at the build
+ // because this source file is compiled for the device target, where ManagementFactory
+ // doesn't exist.
+ var args = ManagementFactory.getRuntimeMXBean().getInputArguments();
+
+ for (var arg : args) {
+ Log.i(TAG, " " + arg);
+ }
+ }
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 3ed8b0a748e1..7ca9239d2062 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -22,7 +22,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Instrumentation;
import android.content.Context;
-import android.os.Build;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -30,16 +29,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
- * Represents how to configure the ravenwood environment for a test class.
- *
- * If a ravenwood test class has a public static field with the {@link Config} annotation,
- * Ravenwood will extract the config from it and initializes the environment. The type of the
- * field must be of {@link RavenwoodConfig}.
+ * @deprecated This class will be removed. Reach out to g/ravenwood if you need any features in it.
*/
+@Deprecated
public final class RavenwoodConfig {
/**
* Use this to mark a field as the configuration.
@@ -66,7 +61,7 @@ public final class RavenwoodConfig {
String mTestPackageName;
String mTargetPackageName;
- int mTargetSdkLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
+ int mTargetSdkLevel;
final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties();
@@ -91,12 +86,6 @@ public final class RavenwoodConfig {
return RavenwoodRule.isOnRavenwood();
}
- private void setDefaults() {
- if (mTargetPackageName == null) {
- mTargetPackageName = mTestPackageName;
- }
- }
-
public static class Builder {
private final RavenwoodConfig mConfig = new RavenwoodConfig();
@@ -120,28 +109,27 @@ public final class RavenwoodConfig {
}
/**
- * Configure the package name of the test, which corresponds to
- * {@link Instrumentation#getContext()}.
+ * @deprecated no longer used. Package name is set in the build file. (for now)
*/
+ @Deprecated
public Builder setPackageName(@NonNull String packageName) {
- mConfig.mTestPackageName = Objects.requireNonNull(packageName);
return this;
}
/**
- * Configure the package name of the target app, which corresponds to
- * {@link Instrumentation#getTargetContext()}. Defaults to {@link #setPackageName}.
+ * @deprecated no longer used. Package name is set in the build file. (for now)
*/
+ @Deprecated
public Builder setTargetPackageName(@NonNull String packageName) {
- mConfig.mTargetPackageName = Objects.requireNonNull(packageName);
return this;
}
+
/**
- * Configure the target SDK level of the test.
+ * @deprecated no longer used. Target SDK level is set in the build file. (for now)
*/
+ @Deprecated
public Builder setTargetSdkLevel(int sdkLevel) {
- mConfig.mTargetSdkLevel = sdkLevel;
return this;
}
@@ -154,34 +142,32 @@ public final class RavenwoodConfig {
}
/**
- * Configure the given system property as immutable for the duration of the test.
- * Read access to the key is allowed, and write access will fail. When {@code value} is
- * {@code null}, the value is left as undefined.
- *
- * All properties in the {@code debug.*} namespace are automatically mutable, with no
- * developer action required.
- *
- * Has no effect on non-Ravenwood environments.
+ * @deprecated Use {@link RavenwoodRule.Builder#setSystemPropertyImmutable(String, Object)}
*/
+ @Deprecated
public Builder setSystemPropertyImmutable(@NonNull String key,
@Nullable Object value) {
- mConfig.mSystemProperties.setValue(key, value);
- mConfig.mSystemProperties.setAccessReadOnly(key);
return this;
}
/**
- * Configure the given system property as mutable for the duration of the test.
- * Both read and write access to the key is allowed, and its value will be reset between
- * each test. When {@code value} is {@code null}, the value is left as undefined.
- *
- * All properties in the {@code debug.*} namespace are automatically mutable, with no
- * developer action required.
- *
- * Has no effect on non-Ravenwood environments.
+ * @deprecated Use {@link RavenwoodRule.Builder#setSystemPropertyMutable(String, Object)}
*/
+ @Deprecated
public Builder setSystemPropertyMutable(@NonNull String key,
@Nullable Object value) {
+ return this;
+ }
+
+ Builder setSystemPropertyImmutableReal(@NonNull String key,
+ @Nullable Object value) {
+ mConfig.mSystemProperties.setValue(key, value);
+ mConfig.mSystemProperties.setAccessReadOnly(key);
+ return this;
+ }
+
+ Builder setSystemPropertyMutableReal(@NonNull String key,
+ @Nullable Object value) {
mConfig.mSystemProperties.setValue(key, value);
mConfig.mSystemProperties.setAccessReadWrite(key);
return this;
@@ -205,7 +191,6 @@ public final class RavenwoodConfig {
}
public RavenwoodConfig build() {
- mConfig.setDefaults();
return mConfig;
}
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index bfa3802ce583..5681a9040f63 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -36,10 +36,8 @@ import java.util.Objects;
import java.util.regex.Pattern;
/**
- * @deprecated Use {@link RavenwoodConfig} to configure the ravenwood environment instead.
- * A {@link RavenwoodRule} is no longer needed for {@link DisabledOnRavenwood}. To get the
- * {@link Context} and {@link Instrumentation}, use
- * {@link androidx.test.platform.app.InstrumentationRegistry} instead.
+ * @deprecated This class is undergoing a major change. Reach out to g/ravenwood if you need
+ * any featues in it.
*/
@Deprecated
public final class RavenwoodRule implements TestRule {
@@ -128,11 +126,10 @@ public final class RavenwoodRule implements TestRule {
}
/**
- * Configure the identity of this process to be the given package name for the duration
- * of the test. Has no effect on non-Ravenwood environments.
+ * @deprecated no longer used.
*/
+ @Deprecated
public Builder setPackageName(@NonNull String packageName) {
- mBuilder.setPackageName(packageName);
return this;
}
@@ -155,7 +152,7 @@ public final class RavenwoodRule implements TestRule {
* Has no effect on non-Ravenwood environments.
*/
public Builder setSystemPropertyImmutable(@NonNull String key, @Nullable Object value) {
- mBuilder.setSystemPropertyImmutable(key, value);
+ mBuilder.setSystemPropertyImmutableReal(key, value);
return this;
}
@@ -170,7 +167,7 @@ public final class RavenwoodRule implements TestRule {
* Has no effect on non-Ravenwood environments.
*/
public Builder setSystemPropertyMutable(@NonNull String key, @Nullable Object value) {
- mBuilder.setSystemPropertyMutable(key, value);
+ mBuilder.setSystemPropertyMutableReal(key, value);
return this;
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
index 3e4619f55c6d..9bd376a76f77 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
@@ -52,7 +52,7 @@ public class RavenwoodSystemProperties {
"vendor_dlkm",
};
- private static Map<String, String> readProperties(String propFile) {
+ static Map<String, String> readProperties(String propFile) {
// Use an ordered map just for cleaner dump log.
final Map<String, String> ret = new LinkedHashMap<>();
try {
@@ -60,7 +60,7 @@ public class RavenwoodSystemProperties {
.map(String::trim)
.filter(s -> !s.startsWith("#"))
.map(s -> s.split("\\s*=\\s*", 2))
- .filter(a -> a.length == 2)
+ .filter(a -> a.length == 2 && a[1].length() > 0)
.forEach(a -> ret.put(a[0], a[1]));
} catch (IOException e) {
throw new RuntimeException(e);
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
index 520f050f0655..2a04d4469ef4 100644
--- a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
@@ -30,6 +30,7 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
+import java.util.function.Supplier;
public class RavenwoodCommonUtils {
private static final String TAG = "RavenwoodCommonUtils";
@@ -277,11 +278,55 @@ public class RavenwoodCommonUtils {
(isStatic ? "static" : "")));
}
+ /**
+ * Run a supplier and swallow the exception, if any.
+ *
+ * It's a dangerous function. Only use it in an exception handler where we don't want to crash.
+ */
+ @Nullable
+ public static <T> T runIgnoringException(@NonNull Supplier<T> s) {
+ try {
+ return s.get();
+ } catch (Throwable th) {
+ log(TAG, "Warning: Exception detected! " + getStackTraceString(th));
+ }
+ return null;
+ }
+
+ /**
+ * Run a runnable and swallow the exception, if any.
+ *
+ * It's a dangerous function. Only use it in an exception handler where we don't want to crash.
+ */
+ public static void runIgnoringException(@NonNull Runnable r) {
+ runIgnoringException(() -> {
+ r.run();
+ return null;
+ });
+ }
+
@NonNull
- public static String getStackTraceString(@Nullable Throwable th) {
+ public static String getStackTraceString(@NonNull Throwable th) {
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
th.printStackTrace(writer);
return stringWriter.toString();
}
+
+ /** Same as {@link Integer#parseInt(String)} but accepts null and returns null. */
+ @Nullable
+ public static Integer parseNullableInt(@Nullable String value) {
+ if (value == null) {
+ return null;
+ }
+ return Integer.parseInt(value);
+ }
+
+ /**
+ * @return {@code value} if it's non-null. Otherwise, returns {@code def}.
+ */
+ @Nullable
+ public static <T> T withDefault(@Nullable T value, @Nullable T def) {
+ return value != null ? value : def;
+ }
}
diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
index fe2269a8dc38..27c5ea1bd0d7 100755
--- a/ravenwood/scripts/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/run-ravenwood-tests.sh
@@ -33,7 +33,7 @@ include_re=""
exclude_re=""
smoke_exclude_re=""
dry_run=""
-while getopts "sx:f:dt" opt; do
+while getopts "sx:f:dtb" opt; do
case "$opt" in
s)
# Remove slow tests.
@@ -52,8 +52,13 @@ case "$opt" in
dry_run="echo"
;;
t)
+ # Redirect log to terminal
export RAVENWOOD_LOG_OUT=$(tty)
;;
+ b)
+ # Build only
+ ATEST=m
+ ;;
'?')
exit 1
;;
@@ -99,11 +104,16 @@ done
# Calculate the removed tests.
-diff="$(diff <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') )"
+diff="$(diff <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') | grep -v [0-9] )"
if [[ "$diff" != "" ]]; then
echo "Excluded tests:"
echo "$diff"
fi
-$dry_run ${ATEST:-atest} "${targets[@]}"
+run() {
+ echo "Running: ${@}"
+ "${@}"
+}
+
+run $dry_run ${ATEST:-atest} "${targets[@]}"
diff --git a/ravenwood/tests/bivalentinst/Android.bp b/ravenwood/tests/bivalentinst/Android.bp
index 41e45e5a6d95..31e3bcc3634f 100644
--- a/ravenwood/tests/bivalentinst/Android.bp
+++ b/ravenwood/tests/bivalentinst/Android.bp
@@ -27,6 +27,9 @@ android_ravenwood_test {
"junit",
"truth",
],
+
+ package_name: "com.android.ravenwood.bivalentinsttest_self_inst",
+
resource_apk: "RavenwoodBivalentInstTest_self_inst_device",
auto_gen_config: true,
}
@@ -53,6 +56,10 @@ android_ravenwood_test {
"truth",
],
resource_apk: "RavenwoodBivalentInstTestTarget",
+
+ package_name: "com.android.ravenwood.bivalentinst_target_app",
+ inst_package_name: "com.android.ravenwood.bivalentinsttest_nonself_inst",
+
inst_resource_apk: "RavenwoodBivalentInstTest_nonself_inst_device",
auto_gen_config: true,
}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
index 92d43d714e14..db252d87c784 100644
--- a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
@@ -19,8 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.Instrumentation;
import android.content.Context;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodConfig.Config;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -39,11 +37,6 @@ public class RavenwoodInstrumentationTest_nonself {
private static final String TEST_PACKAGE_NAME =
"com.android.ravenwood.bivalentinsttest_nonself_inst";
- @Config
- public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
- .setPackageName(TEST_PACKAGE_NAME)
- .setTargetPackageName(TARGET_PACKAGE_NAME)
- .build();
private static Instrumentation sInstrumentation;
private static Context sTestContext;
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
index 2f35923dead2..94b18619efcd 100644
--- a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
@@ -19,8 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.Instrumentation;
import android.content.Context;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodConfig.Config;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -40,13 +38,6 @@ public class RavenwoodInstrumentationTest_self {
private static final String TEST_PACKAGE_NAME =
"com.android.ravenwood.bivalentinsttest_self_inst";
- @Config
- public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
- .setPackageName(TEST_PACKAGE_NAME)
- .setTargetPackageName(TARGET_PACKAGE_NAME)
- .build();
-
-
private static Instrumentation sInstrumentation;
private static Context sTestContext;
private static Context sTargetContext;
diff --git a/ravenwood/tests/bivalenttest/Android.bp b/ravenwood/tests/bivalenttest/Android.bp
index 40e6672a3c63..ac545dfb06cc 100644
--- a/ravenwood/tests/bivalenttest/Android.bp
+++ b/ravenwood/tests/bivalenttest/Android.bp
@@ -84,6 +84,8 @@ java_defaults {
android_ravenwood_test {
name: "RavenwoodBivalentTest",
defaults: ["ravenwood-bivalent-defaults"],
+ target_sdk_version: "34",
+ package_name: "com.android.ravenwoodtest.bivalenttest",
auto_gen_config: true,
}
diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java
index a5a16c14600b..306c2b39c70d 100644
--- a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java
+++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java
@@ -20,8 +20,6 @@ import static android.platform.test.ravenwood.RavenwoodConfig.isOnRavenwood;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-import android.platform.test.ravenwood.RavenwoodConfig;
-
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -33,13 +31,7 @@ import org.junit.runner.RunWith;
*/
@RunWith(AndroidJUnit4.class)
public class RavenwoodConfigTest {
- private static final String PACKAGE_NAME = "com.test";
-
- @RavenwoodConfig.Config
- public static RavenwoodConfig sConfig =
- new RavenwoodConfig.Builder()
- .setPackageName(PACKAGE_NAME)
- .build();
+ private static final String PACKAGE_NAME = "com.android.ravenwoodtest.bivalenttest";
@Test
public void testConfig() {
diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
index a95760db1a61..882c91c43ee9 100644
--- a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
+++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
@@ -16,8 +16,6 @@
package com.android.ravenwoodtest.bivalenttest.compat
import android.app.compat.CompatChanges
-import android.os.Build
-import android.platform.test.ravenwood.RavenwoodConfig
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.internal.ravenwood.RavenwoodEnvironment.CompatIdsForTest
import org.junit.Assert
@@ -26,14 +24,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class RavenwoodCompatFrameworkTest {
- companion object {
- @JvmField // Expose as a raw field, not as a property.
- @RavenwoodConfig.Config
- val config = RavenwoodConfig.Builder()
- .setTargetSdkLevel(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
- .build()
- }
-
@Test
fun testEnabled() {
Assert.assertTrue(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_1))
@@ -53,4 +43,4 @@ class RavenwoodCompatFrameworkTest {
fun testEnabledAfterUForUApps() {
Assert.assertFalse(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_4))
}
-} \ No newline at end of file
+}
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
index 02d10732245d..f94b98bc1fb8 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
@@ -24,6 +24,7 @@ import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -32,6 +33,10 @@ import org.junit.runner.RunWith;
/**
* Test for @Config field extraction and validation.
+ *
+ * TODO(b/377765941) Most of the tests here will be obsolete and deleted with b/377765941, but
+ * some of the tests may need to be re-implemented one way or another. (e.g. the package name
+ * test.) Until that happens, we'll keep all tests here but add an {@code @Ignore} instead.
*/
@NoRavenizer // This class shouldn't be executed with RavenwoodAwareTestRunner.
public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase {
@@ -59,6 +64,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
testRunFinished: 1,0,0,0
""")
// CHECKSTYLE:ON
+ @Ignore // Package name is no longer set via config.
public static class ConfigInBaseClassTest extends ConfigInBaseClass {
@Test
public void test() {
@@ -83,6 +89,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
testRunFinished: 1,0,0,0
""")
// CHECKSTYLE:ON
+ @Ignore // Package name is no longer set via config.
public static class ConfigOverridingTest extends ConfigInBaseClass {
static String PACKAGE_NAME_OVERRIDE = "com.ConfigOverridingTest";
@@ -376,6 +383,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
testRunFinished: 1,0,0,0
""")
// CHECKSTYLE:ON
+ @Ignore // Package name is no longer set via config.
public static class RuleInBaseClassSuccessTest extends RuleInBaseClass {
@Test
@@ -437,6 +445,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
testRunFinished: 1,1,0,0
""")
// CHECKSTYLE:ON
+ @Ignore // Package name is no longer set via config.
public static class RuleWithDifferentTypeInBaseClassSuccessTest extends RuleWithDifferentTypeInBaseClass {
@Test
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java
index f7a2198a9bc4..0e3d053e90b1 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java
@@ -25,6 +25,8 @@ import android.util.Log;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
+
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
@@ -103,6 +105,7 @@ public abstract class RavenwoodRunnerTestBase {
var thisClass = this.getClass();
var ret = Arrays.stream(thisClass.getNestMembers())
.filter((c) -> c.getAnnotation(Expected.class) != null)
+ .filter((c) -> c.getAnnotation(Ignore.class) == null)
.toArray(Class[]::new);
assertThat(ret.length).isGreaterThan(0);
diff --git a/ravenwood/tests/runtime-test/Android.bp b/ravenwood/tests/runtime-test/Android.bp
index 0c0df1f993aa..c3520031ea7d 100644
--- a/ravenwood/tests/runtime-test/Android.bp
+++ b/ravenwood/tests/runtime-test/Android.bp
@@ -9,7 +9,7 @@ package {
android_ravenwood_test {
name: "RavenwoodRuntimeTest",
-
+ target_sdk_version: "34",
libs: [
"ravenwood-helper-runtime",
],
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp b/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
index 1570549ec27d..483c4be7633b 100644
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
@@ -156,6 +156,7 @@ python_test_host {
],
data: [
"golden-output/*.txt",
+ "golden-output.RELEASE_TARGET_JAVA_21/*.txt",
],
java_data: [
"hoststubgen-test-tiny-framework-orig-dump",
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt
new file mode 100644
index 000000000000..5e5ca62b49f0
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -0,0 +1,3697 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+ Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ public abstract java.lang.String value();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestIgnore.class
+ Compiled from "HostSideTestIgnore.java"
+public interface android.hosttest.annotation.HostSideTestIgnore extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestIgnore
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestIgnore.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+ Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+ Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+ Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ public abstract java.lang.String value();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestRedirectionClass.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+ Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRemove
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestStaticInitializerKeep.class
+ Compiled from "HostSideTestStaticInitializerKeep.java"
+public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestStaticInitializerKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+ Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestSubstitute
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ public abstract java.lang.String suffix();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+ Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestThrow
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+ Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/tests/HostSideTestSuppress.class
+ Compiled from "HostSideTestSuppress.java"
+public interface android.hosttest.annotation.tests.HostSideTestSuppress extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/tests/HostSideTestSuppress
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestSuppress.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD]
+ )
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+}
+SourceFile: "IPretendingAidl.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+}
+SourceFile: "IPretendingAidl.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 3
+}
+SourceFile: "IPretendingAidl.java"
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 3
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_1
+ x: newarray int
+ x: dup
+ x: iconst_0
+ x: iconst_1
+ x: iastore
+ x: putstatic #x // Field ARRAY:[I
+ x: return
+ LineNumberTable:
+}
+SourceFile: "R.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R;
+}
+SourceFile: "R.java"
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 9, attributes: 2
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int remove;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 4 1 value I
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public void toBeRemoved(java.lang.String);
+ descriptor: (Ljava/lang/String;)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 8 1 foo Ljava/lang/String;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRemove
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 10 1 value I
+ RuntimeInvisibleAnnotations:
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestSubstitute(
+ suffix="_host"
+ )
+
+ public int addTwo_host(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 4 1 value I
+
+ public static native int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestSubstitute(
+ suffix="_host"
+ )
+
+ private static int nativeAddThree_host(int);
+ descriptor: (I)I
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 value I
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public int toBeIgnored();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestIgnore
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+ Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 3, attributes: 2
+ public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+ descriptor: Ljava/util/Set;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>;
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+ descriptor: ()V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+
+ public static void onClassLoaded(java.lang.Class<?>);
+ descriptor: (Ljava/lang/Class;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: getstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: aload_0
+ x: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+ x: pop
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 clazz Ljava/lang/Class;
+ LocalVariableTypeTable:
+ Start Length Slot Name Signature
+ 0 11 0 clazz Ljava/lang/Class<*>;
+ Signature: #x // (Ljava/lang/Class<*>;)V
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class java/util/HashSet
+ x: dup
+ x: invokespecial #x // Method java/util/HashSet."<init>":()V
+ x: putstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 6, attributes: 2
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public int remove;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRemove
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 10 1 value I
+ RuntimeInvisibleAnnotations:
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestSubstitute(
+ suffix="_host"
+ )
+
+ public int addTwo_host(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+
+ public void toBeRemoved(java.lang.String);
+ descriptor: (Ljava/lang/String;)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 8 1 foo Ljava/lang/String;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRemove
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 2, attributes: 2
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault;
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: iconst_1
+ x: putstatic #x // Field sInitialized:Z
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 2, attributes: 2
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub;
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: iconst_1
+ x: putstatic #x // Field sInitialized:Z
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
+RuntimeInvisibleAnnotations:
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 65
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 6, methods: 7, attributes: 3
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mLongName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mShortName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> mandated
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=5, args_size=5
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: aload_0
+ x: aload_3
+ x: putfield #x // Field mLongName:Ljava/lang/String;
+ x: aload_0
+ x: aload 4
+ x: putfield #x // Field mShortName:Ljava/lang/String;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ 0 18 3 longName Ljava/lang/String;
+ 0 18 4 shortName Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mLongName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mShortName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_3
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_2
+ x: getstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=6, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String RED
+ x: iconst_0
+ x: ldc #x // String Red
+ x: ldc #x // String R
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String GREEN
+ x: iconst_1
+ x: ldc #x // String Green
+ x: ldc #x // String G
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String BLUE
+ x: iconst_2
+ x: ldc #x // String Blue
+ x: ldc #x // String B
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 65
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 3
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> mandated
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=3, args_size=3
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ Signature: #x // ()V
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_2
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String CAT
+ x: iconst_0
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String DOG
+ x: iconst_1
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+ Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 2
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+
+ public static int testException();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=0
+ x: new #x // class java/lang/IllegalStateException
+ x: dup
+ x: ldc #x // String Inner exception
+ x: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ x: astore_0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Outer exception
+ x: aload_0
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+ x: athrow
+ Exception table:
+ from to target type
+ 0 10 10 Class java/lang/Exception
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 e Ljava/lang/Exception;
+ StackMapTable: number_of_entries = 1
+ frame_type = 74 /* same_locals_1_stack_item */
+ stack = [ class java/lang/Exception ]
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+ Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 17, attributes: 1
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public int remove;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 0 4 1 value I
+
+ public void toBeRemoved(java.lang.String);
+ descriptor: (Ljava/lang/String;)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 0 8 1 foo Ljava/lang/String;
+
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 0 10 1 value I
+
+ public int addTwo_host(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 0 4 1 value I
+
+ public static native int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+ public static int addThree_host(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 value I
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class
+ Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 5
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static java.lang.Integer lambda$getSupplier_static$3();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: bipush 8
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ private static java.lang.Integer lambda$getSupplier$2();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ private static java.lang.Integer lambda$static$1();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: bipush 6
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ private static java.lang.Integer lambda$new$0();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_5
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$new$0:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier$2:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$static$1:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.class
+ Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 5
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static java.lang.Integer lambda$getSupplier_static$3();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ private static java.lang.Integer lambda$getSupplier$2();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ private static java.lang.Integer lambda$static$1();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ private static java.lang.Integer lambda$new$0();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$new$0:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier$2:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$static$1:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: iconst_1
+ x: invokevirtual #x // Method java/lang/Thread.setDaemon:(Z)V
+ x: aload_0
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 thread Ljava/lang/Thread;
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+ 0 4 1 b I
+}
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 5, attributes: 5
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=2, args_size=0
+ x: new #x // class java/util/concurrent/atomic/AtomicBoolean
+ x: dup
+ x: iconst_0
+ x: invokespecial #x // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+ x: astore_0
+ x: new #x // class java/lang/Thread
+ x: dup
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+ x: invokespecial #x // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+ x: astore_1
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.join:()V
+ x: aload_0
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 9 27 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ 23 13 1 th Ljava/lang/Thread;
+ Exceptions:
+ throws java.lang.Exception
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: iconst_1
+ x: iconst_2
+ x: invokestatic #x // Method originalAdd:(II)I
+ x: ireturn
+ LineNumberTable:
+
+ private static int originalAdd(int, int);
+ descriptor: (II)I
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: iconst_1
+ x: isub
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 a I
+ 0 6 1 b I
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+ x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+}
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()V
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ #x ()V
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+ Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 14, attributes: 2
+ int value;
+ descriptor: I
+ flags: (0x0000)
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+ public static native int nativeAddTwo(int);
+ descriptor: (I)I
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static int nativeAddTwo_should_be_like_this(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 arg I
+
+ public static native long nativeLongPlus(long, long);
+ descriptor: (JJ)J
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static long nativeLongPlus_should_be_like_this(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 arg1 J
+ 0 6 2 arg2 J
+
+ public void setValue(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 0 6 1 v I
+
+ public native int nativeNonStaticAddToValue(int);
+ descriptor: (I)I
+ flags: (0x0101) ACC_PUBLIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public int nativeNonStaticAddToValue_should_be_like_this(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 0 6 1 arg I
+
+ public static native void nativeStillNotSupported();
+ descriptor: ()V
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public static native void nativeStillKeep();
+ descriptor: ()V
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+ public static void nativeStillNotSupported_should_be_like_this();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+
+ public static native byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public void notNativeRedirected();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestRedirectionClass(
+ value="TinyFrameworkNative_host"
+ )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+ Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 7, attributes: 2
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+
+ public static int nativeAddTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 arg I
+
+ public static long nativeLongPlus(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: lload_0
+ x: lload_2
+ x: ladd
+ x: lreturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 arg1 J
+ 0 4 2 arg2 J
+
+ public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: getfield #x // Field com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.value:I
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 7 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 0 7 1 arg I
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: i2b
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 arg1 B
+ 0 5 1 arg2 B
+
+ public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=1, args_size=1
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 1 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=0, args_size=0
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 5
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+ 0 5 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+}
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 5
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+}
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 5
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+ 0 5 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+}
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 5
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+}
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 3
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+ 0 10 1 x I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 3
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_5
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+ 0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 5
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+}
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 3
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 8
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 3
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 6
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ interfaces: 0, fields: 0, methods: 1, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+ 0 6 1 x I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 4, attributes: 4
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 17 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 9 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 2
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class com/unsupported/UnsupportedClass
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method com/unsupported/UnsupportedClass."<init>":(I)V
+ x: invokevirtual #x // Method com/unsupported/UnsupportedClass.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 12 0 value I
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class
+ Compiled from "TinyFrameworkRenamedClassCaller.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 2
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller;
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V
+ x: invokevirtual #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 12 0 value I
+}
+SourceFile: "TinyFrameworkRenamedClassCaller.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class
+ Compiled from "TinyFrameworkToBeRenamed.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 2
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+ 0 10 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+}
+SourceFile: "TinyFrameworkToBeRenamed.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
+ Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.A
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.packagetest.A();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/A;
+}
+SourceFile: "A.java"
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/B.class
+ Compiled from "B.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.B
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/B
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.packagetest.B();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/B;
+}
+SourceFile: "B.java"
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
+ Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.packagetest.sub.A();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/A;
+}
+SourceFile: "A.java"
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/B.class
+ Compiled from "B.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/B
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.packagetest.sub.B();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/B;
+}
+SourceFile: "B.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
+ Compiled from "C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.C1();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/C1;
+}
+SourceFile: "C1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C2.class
+ Compiled from "C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.C2();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/C1."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/C2;
+}
+SourceFile: "C2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C3.class
+ Compiled from "C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.C3();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/C2."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/C3;
+}
+SourceFile: "C3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CA.class
+ Compiled from "CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.CA();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/CA;
+}
+SourceFile: "CA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CB.class
+ Compiled from "CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.CB();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/CB;
+}
+SourceFile: "CB.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.class
+ Compiled from "Class_C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/C1."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_C1;
+}
+SourceFile: "Class_C1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.class
+ Compiled from "Class_C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/C2."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_C2;
+}
+SourceFile: "Class_C2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.class
+ Compiled from "Class_C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C3
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/C3."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_C3;
+}
+SourceFile: "Class_C3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA.class
+ Compiled from "Class_CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA extends com.android.hoststubgen.test.tinyframework.subclasstest.CA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/CA."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_CA;
+}
+SourceFile: "Class_CA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB.class
+ Compiled from "Class_CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB extends com.android.hoststubgen.test.tinyframework.subclasstest.CB
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/CB."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_CB;
+}
+SourceFile: "Class_CB.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA.class
+ Compiled from "Class_CB_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA extends com.android.hoststubgen.test.tinyframework.subclasstest.CB implements com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+ interfaces: 1, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/subclasstest/CB."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA;
+}
+SourceFile: "Class_CB_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.class
+ Compiled from "Class_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I1;
+}
+SourceFile: "Class_I1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.class
+ Compiled from "Class_I1_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I1,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+ super_class: #x // java/lang/Object
+ interfaces: 2, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA;
+}
+SourceFile: "Class_I1_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.class
+ Compiled from "Class_I2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 implements com.android.hoststubgen.test.tinyframework.subclasstest.I2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I2;
+}
+SourceFile: "Class_I2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.class
+ Compiled from "Class_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.I3
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I3;
+}
+SourceFile: "Class_I3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA.class
+ Compiled from "Class_I3_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I3,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA
+ super_class: #x // java/lang/Object
+ interfaces: 2, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA;
+}
+SourceFile: "Class_I3_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA.class
+ Compiled from "Class_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IA;
+}
+SourceFile: "Class_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1.class
+ Compiled from "Class_IA_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.IA,com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1
+ super_class: #x // java/lang/Object
+ interfaces: 2, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1;
+}
+SourceFile: "Class_IA_I1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3.class
+ Compiled from "Class_IA_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.IA,com.android.hoststubgen.test.tinyframework.subclasstest.I3
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3
+ super_class: #x // java/lang/Object
+ interfaces: 2, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3;
+}
+SourceFile: "Class_IA_I3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB.class
+ Compiled from "Class_IB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB implements com.android.hoststubgen.test.tinyframework.subclasstest.IB
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IB;
+}
+SourceFile: "Class_IB.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA.class
+ Compiled from "Class_IB_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.IB,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA
+ super_class: #x // java/lang/Object
+ interfaces: 2, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA;
+}
+SourceFile: "Class_IB_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_None.class
+ Compiled from "Class_None.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_None
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_None
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 1
+ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_None();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_None;
+}
+SourceFile: "Class_None.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I1.class
+ Compiled from "I1.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "I1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class
+ Compiled from "I2.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 extends com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "I2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class
+ Compiled from "I3.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 extends com.android.hoststubgen.test.tinyframework.subclasstest.I2
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "I3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class
+ Compiled from "IA.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class
+ Compiled from "IB.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "IB.java"
+## Class: com/supported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/supported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 2
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ public com.supported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/supported/UnsupportedClass;
+ 0 10 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/supported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 2
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/unsupported/UnsupportedClass;
+ 0 14 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/unsupported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt
new file mode 100644
index 000000000000..84a8373008d7
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt
@@ -0,0 +1,3727 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+ Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ public abstract java.lang.String value();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+ Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+ Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+ Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ public abstract java.lang.String value();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestRedirectionClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+ Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRemove
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestStaticInitializerKeep.class
+ Compiled from "HostSideTestStaticInitializerKeep.java"
+public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestStaticInitializerKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+ Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestSubstitute
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ public abstract java.lang.String suffix();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+ Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestThrow
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+ Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 4
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_1
+ x: newarray int
+ x: dup
+ x: iconst_0
+ x: iconst_1
+ x: iastore
+ x: putstatic #x // Field ARRAY:[I
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 7, attributes: 3
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public int toBeIgnored();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestIgnore
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+ Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 3, attributes: 3
+ public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+ descriptor: Ljava/util/Set;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+ descriptor: ()V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void onClassLoaded(java.lang.Class<?>);
+ descriptor: (Ljava/lang/Class;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: getstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: aload_0
+ x: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+ x: pop
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 clazz Ljava/lang/Class;
+ LocalVariableTypeTable:
+ Start Length Slot Name Signature
+ 0 11 0 clazz Ljava/lang/Class<*>;
+ Signature: #x // (Ljava/lang/Class<*>;)V
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class java/util/HashSet
+ x: dup
+ x: invokespecial #x // Method java/util/HashSet."<init>":()V
+ x: putstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 4, attributes: 3
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 0, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 1, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: iconst_1
+ x: putstatic #x // Field sInitialized:Z
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 65
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 6, methods: 7, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mLongName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mShortName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> mandated
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=5, args_size=5
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: aload_0
+ x: aload_3
+ x: putfield #x // Field mLongName:Ljava/lang/String;
+ x: aload_0
+ x: aload 4
+ x: putfield #x // Field mShortName:Ljava/lang/String;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ 0 18 3 longName Ljava/lang/String;
+ 0 18 4 shortName Ljava/lang/String;
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mLongName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mShortName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_3
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_2
+ x: getstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=6, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String RED
+ x: iconst_0
+ x: ldc #x // String Red
+ x: ldc #x // String R
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String GREEN
+ x: iconst_1
+ x: ldc #x // String Green
+ x: ldc #x // String G
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String BLUE
+ x: iconst_2
+ x: ldc #x // String Blue
+ x: ldc #x // String B
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 65
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> mandated
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=3, args_size=3
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ Signature: #x // ()V
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_2
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String CAT
+ x: iconst_0
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String DOG
+ x: iconst_1
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+ Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int testException();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=0
+ x: new #x // class java/lang/IllegalStateException
+ x: dup
+ x: ldc #x // String Inner exception
+ x: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ x: astore_0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Outer exception
+ x: aload_0
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+ x: athrow
+ Exception table:
+ from to target type
+ 0 10 10 Class java/lang/Exception
+ StackMapTable: number_of_entries = 1
+ frame_type = 74 /* same_locals_1_stack_item */
+ stack = [ class java/lang/Exception ]
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 e Ljava/lang/Exception;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+ Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 15, attributes: 2
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aconst_null
+ x: areturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=0, locals=1, args_size=1
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: fconst_0
+ x: freturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: dconst_0
+ x: dreturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class
+ Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 6
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static java.lang.Integer lambda$getSupplier_static$3();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: bipush 8
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$getSupplier$2();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$static$1();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: bipush 6
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$new$0();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_5
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$new$0:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier$2:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$static$1:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.class
+ Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 6
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static java.lang.Integer lambda$getSupplier_static$3();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$getSupplier$2();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$static$1();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$new$0();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$new$0:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier$2:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$static$1:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: iconst_1
+ x: invokevirtual #x // Method java/lang/Thread.setDaemon:(Z)V
+ x: aload_0
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 thread Ljava/lang/Thread;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+ 0 4 1 b I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 4, attributes: 6
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=2, args_size=0
+ x: new #x // class java/util/concurrent/atomic/AtomicBoolean
+ x: dup
+ x: iconst_0
+ x: invokespecial #x // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+ x: astore_0
+ x: new #x // class java/lang/Thread
+ x: dup
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+ x: invokespecial #x // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+ x: astore_1
+ x: aload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.startThread:(Ljava/lang/Thread;)V
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.join:()V
+ x: aload_0
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 9 27 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ 23 13 1 th Ljava/lang/Thread;
+ Exceptions:
+ throws java.lang.Exception
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: iconst_1
+ x: iconst_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.add:(II)I
+ x: ireturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+ x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()V
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ #x ()V
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+ Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 14, attributes: 3
+ int value;
+ descriptor: I
+ flags: (0x0000)
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static int nativeAddTwo_should_be_like_this(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static long nativeLongPlus(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static long nativeLongPlus_should_be_like_this(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 arg1 J
+ 0 6 2 arg2 J
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public void setValue(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 0 6 1 v I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int nativeNonStaticAddToValue(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public int nativeNonStaticAddToValue_should_be_like_this(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 0 6 1 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void nativeStillNotSupported();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public static native void nativeStillKeep();
+ descriptor: ()V
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void nativeStillNotSupported_should_be_like_this();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public void notNativeRedirected();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeRedirected:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=0, args_size=0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeStaticRedirected:()V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestRedirectionClass(
+ value="TinyFrameworkNative_host"
+ )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+ Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 7, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static long nativeLongPlus(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: lload_0
+ x: lload_2
+ x: ladd
+ x: lreturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 arg1 J
+ 0 4 2 arg2 J
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: getfield #x // Field com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.value:I
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 7 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 0 7 1 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: i2b
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 arg1 B
+ 0 5 1 arg2 B
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=1, args_size=1
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 1 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=0, args_size=0
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 6
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+ 0 5 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 6
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 6
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+ 0 5 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 6
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+ 0 10 1 x I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_5
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+ 0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+}
+InnerClasses:
+ public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 3, attributes: 6
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 8
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 6
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ interfaces: 0, fields: 0, methods: 1, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+ 0 6 1 x I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 4, attributes: 5
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 17 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 9 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class com/supported/UnsupportedClass
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method com/supported/UnsupportedClass."<init>":(I)V
+ x: invokevirtual #x // Method com/supported/UnsupportedClass.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 12 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class
+ Compiled from "TinyFrameworkRenamedClassCaller.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V
+ x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 12 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkRenamedClassCaller.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
+ Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.A
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
+ Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
+ Compiled from "C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "C1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C2.class
+ Compiled from "C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "C2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C3.class
+ Compiled from "C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "C3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CA.class
+ Compiled from "CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "CA.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CB.class
+ Compiled from "CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "CB.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.class
+ Compiled from "Class_C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_C1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.class
+ Compiled from "Class_C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_C2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.class
+ Compiled from "Class_C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C3
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_C3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.class
+ Compiled from "Class_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.class
+ Compiled from "Class_I1_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I1,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+ super_class: #x // java/lang/Object
+ interfaces: 2, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I1_IA.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.class
+ Compiled from "Class_I2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 implements com.android.hoststubgen.test.tinyframework.subclasstest.I2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.class
+ Compiled from "Class_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.I3
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I1.class
+ Compiled from "I1.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "I1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class
+ Compiled from "I2.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 extends com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "I2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class
+ Compiled from "I3.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 extends com.android.hoststubgen.test.tinyframework.subclasstest.I2
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "I3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class
+ Compiled from "IA.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "IA.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class
+ Compiled from "IB.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "IB.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/supported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/supported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 3
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.supported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/supported/UnsupportedClass;
+ 0 10 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/supported/UnsupportedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/unsupported/UnsupportedClass;
+ 0 14 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/unsupported/UnsupportedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class
+ Compiled from "TinyFrameworkToBeRenamed.java"
+public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 3
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+ 0 10 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkToBeRenamed.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
new file mode 100644
index 000000000000..49769e648bbf
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -0,0 +1,4896 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+ Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 2, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public abstract java.lang.String value();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+ Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestKeep
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+ Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+ Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 2, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public abstract java.lang.String value();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestRedirectionClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+ Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRemove
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestRemove
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestStaticInitializerKeep.class
+ Compiled from "HostSideTestStaticInitializerKeep.java"
+public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestStaticInitializerKeep
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "HostSideTestStaticInitializerKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+ Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestSubstitute
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 2, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public abstract java.lang.String suffix();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+ Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestThrow
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestThrow
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+ Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 65
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+ x: ldc #x // String addTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 a I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ x: ldc #x // String addOne
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 a I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: iconst_1
+ x: newarray int
+ x: dup
+ x: iconst_0
+ x: iconst_1
+ x: iastore
+ x: putstatic #x // Field ARRAY:[I
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 7, attributes: 3
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String addOne
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String addTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String nativeAddThree
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public int toBeIgnored();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String toBeIgnored
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestIgnore
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+ Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 3, attributes: 3
+ public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+ descriptor: Ljava/util/Set;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+ descriptor: ()V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void onClassLoaded(java.lang.Class<?>);
+ descriptor: (Ljava/lang/Class;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+ x: ldc #x // String onClassLoaded
+ x: ldc #x // String (Ljava/lang/Class;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: getstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: aload_0
+ x: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+ x: pop
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 clazz Ljava/lang/Class;
+ LocalVariableTypeTable:
+ Start Length Slot Name Signature
+ 11 11 0 clazz Ljava/lang/Class<*>;
+ Signature: #x // (Ljava/lang/Class<*>;)V
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: new #x // class java/util/HashSet
+ x: dup
+ x: invokespecial #x // Method java/util/HashSet."<init>":()V
+ x: putstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 5, attributes: 3
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String addOne
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String addTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 0, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 1, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: iconst_1
+ x: putstatic #x // Field sInitialized:Z
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 65
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 6, methods: 7, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mLongName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mShortName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String valueOf
+ x: ldc #x // String (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 name Ljava/lang/String;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> mandated
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=4, locals=5, args_size=5
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String <init>
+ x: ldc #x // String (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: aload_0
+ x: aload_3
+ x: putfield #x // Field mLongName:Ljava/lang/String;
+ x: aload_0
+ x: aload 4
+ x: putfield #x // Field mShortName:Ljava/lang/String;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ 11 18 3 longName Ljava/lang/String;
+ 11 18 4 shortName Ljava/lang/String;
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String getLongName
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: getfield #x // Field mLongName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String getShortName
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: getfield #x // Field mShortName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String $values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_3
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_2
+ x: getstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=6, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String RED
+ x: iconst_0
+ x: ldc #x // String Red
+ x: ldc #x // String R
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String GREEN
+ x: iconst_1
+ x: ldc #x // String Green
+ x: ldc #x // String G
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String BLUE
+ x: iconst_2
+ x: ldc #x // String Blue
+ x: ldc #x // String B
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 65
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String valueOf
+ x: ldc #x // String (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 name Ljava/lang/String;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> mandated
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=4, locals=3, args_size=3
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String <init>
+ x: ldc #x // String (Ljava/lang/String;I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ Signature: #x // ()V
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String $values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_2
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String CAT
+ x: iconst_0
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String DOG
+ x: iconst_1
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+ Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int testException();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+ x: ldc #x // String testException
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class java/lang/IllegalStateException
+ x: dup
+ x: ldc #x // String Inner exception
+ x: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ x: astore_0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Outer exception
+ x: aload_0
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+ x: athrow
+ Exception table:
+ from to target type
+ 11 21 21 Class java/lang/Exception
+ StackMapTable: number_of_entries = 1
+ frame_type = 85 /* same_locals_1_stack_item */
+ stack = [ class java/lang/Exception ]
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 22 11 0 e Ljava/lang/Exception;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+ Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 15, attributes: 2
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String addOne
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredObj
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aconst_null
+ x: areturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredV
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredZ
+ x: ldc #x // String ()Z
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredB
+ x: ldc #x // String ()B
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredC
+ x: ldc #x // String ()C
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredS
+ x: ldc #x // String ()S
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredI
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredF
+ x: ldc #x // String ()F
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: fconst_0
+ x: freturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredD
+ x: ldc #x // String ()D
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: dconst_0
+ x: dreturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String addTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String nativeAddThree
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class
+ Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 6
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String getSupplier
+ x: ldc #x // String ()Ljava/util/function/Supplier;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String getSupplier_static
+ x: ldc #x // String ()Ljava/util/function/Supplier;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static java.lang.Integer lambda$getSupplier_static$3();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String lambda$getSupplier_static$3
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: bipush 8
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$getSupplier$2();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String lambda$getSupplier$2
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$static$1();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String lambda$static$1
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: bipush 6
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$new$0();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String lambda$new$0
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_5
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$new$0:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier$2:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$static$1:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.class
+ Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 6
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String getSupplier
+ x: ldc #x // String ()Ljava/util/function/Supplier;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String getSupplier_static
+ x: ldc #x // String ()Ljava/util/function/Supplier;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static java.lang.Integer lambda$getSupplier_static$3();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String lambda$getSupplier_static$3
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$getSupplier$2();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String lambda$getSupplier$2
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$static$1();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String lambda$static$1
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static java.lang.Integer lambda$new$0();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String lambda$new$0
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: invokedynamic #x, 0 // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$new$0:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier$2:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()Ljava/lang/Object;
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$static$1:()Ljava/lang/Integer;
+ #x ()Ljava/lang/Integer;
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 4, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String startThread
+ x: ldc #x // String (Ljava/lang/Thread;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: iconst_1
+ x: invokevirtual #x // Method java/lang/Thread.setDaemon:(Z)V
+ x: aload_0
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 thread Ljava/lang/Thread;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String add
+ x: ldc #x // String (II)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 a I
+ 11 4 1 b I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 5, attributes: 6
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String nonStaticMethodCallReplaceTester
+ x: ldc #x // String ()Z
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class java/util/concurrent/atomic/AtomicBoolean
+ x: dup
+ x: iconst_0
+ x: invokespecial #x // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+ x: astore_0
+ x: new #x // class java/lang/Thread
+ x: dup
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+ x: invokespecial #x // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+ x: astore_1
+ x: aload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.startThread:(Ljava/lang/Thread;)V
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.join:()V
+ x: aload_0
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 20 27 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ 34 13 1 th Ljava/lang/Thread;
+ Exceptions:
+ throws java.lang.Exception
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String staticMethodCallReplaceTester
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_1
+ x: iconst_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.add:(II)I
+ x: ireturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String lambda$nonStaticMethodCallReplaceTester$0
+ x: ldc #x // String (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+ x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()V
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ #x ()V
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+ Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 15, attributes: 3
+ int value;
+ descriptor: I
+ flags: (0x0000)
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeAddTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static int nativeAddTwo_should_be_like_this(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeAddTwo_should_be_like_this
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static long nativeLongPlus(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeLongPlus
+ x: ldc #x // String (JJ)J
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static long nativeLongPlus_should_be_like_this(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeLongPlus_should_be_like_this
+ x: ldc #x // String (JJ)J
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 arg1 J
+ 11 6 2 arg2 J
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public void setValue(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String setValue
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 11 6 1 v I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int nativeNonStaticAddToValue(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeNonStaticAddToValue
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public int nativeNonStaticAddToValue_should_be_like_this(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeNonStaticAddToValue_should_be_like_this
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 11 6 1 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void nativeStillNotSupported();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeStillNotSupported
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public static native void nativeStillKeep();
+ descriptor: ()V
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void nativeStillNotSupported_should_be_like_this();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeStillNotSupported_should_be_like_this
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeBytePlus
+ x: ldc #x // String (BB)B
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public void notNativeRedirected();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String notNativeRedirected
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeRedirected:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String notNativeStaticRedirected
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeStaticRedirected:()V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestRedirectionClass(
+ value="TinyFrameworkNative_host"
+ )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+ Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 8, attributes: 3
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeAddTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeAddTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static long nativeLongPlus(long, long);
+ descriptor: (JJ)J
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=4, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeLongPlus
+ x: ldc #x // String (JJ)J
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: lload_0
+ x: lload_2
+ x: ladd
+ x: lreturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 arg1 J
+ 11 4 2 arg2 J
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeNonStaticAddToValue
+ x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: getfield #x // Field com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.value:I
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 7 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ 11 7 1 arg I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeBytePlus
+ x: ldc #x // String (BB)B
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: i2b
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 arg1 B
+ 11 5 1 arg2 B
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String notNativeRedirected
+ x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 1 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String notNativeStaticRedirected
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 4, attributes: 6
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0000)
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: ldc #x // String <init>
+ x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+ 11 5 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 4, attributes: 6
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 4, attributes: 6
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0000)
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: ldc #x // String <init>
+ x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+ 11 5 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 4, attributes: 6
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+ 11 10 1 x I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_5
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+ 11 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
+}
+InnerClasses:
+ public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+ minor version: 0
+ major version: 65
+ flags: (0x0020) ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 4, attributes: 6
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+ descriptor: ()V
+ flags: (0x0000)
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Integer get();
+ descriptor: ()Ljava/lang/Integer;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.lang.Object get();
+ descriptor: ()Ljava/lang/Object;
+ flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 8
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 3, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 6
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ x: ldc #x // String getSupplier_static
+ x: ldc #x // String ()Ljava/util/function/Supplier;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: iload_1
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+ 11 6 1 x I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 4, attributes: 5
+ public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+ descriptor: Ljava/util/function/Supplier;
+ flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+ Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 17 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public java.util.function.Supplier<java.lang.Integer> getSupplier();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ x: ldc #x // String getSupplier
+ x: ldc #x // String ()Ljava/util/function/Supplier;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 9 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+ descriptor: ()Ljava/util/function/Supplier;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ x: ldc #x // String getSupplier_static
+ x: ldc #x // String ()Ljava/util/function/Supplier;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+ x: areturn
+ LineNumberTable:
+ Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ x: ldc #x // String foo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class com/supported/UnsupportedClass
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method com/supported/UnsupportedClass."<init>":(I)V
+ x: invokevirtual #x // Method com/supported/UnsupportedClass.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 12 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class
+ Compiled from "TinyFrameworkRenamedClassCaller.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+ x: ldc #x // String foo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V
+ x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 12 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkRenamedClassCaller.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
+ Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.A
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/packagetest/A
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
+ Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
+ Compiled from "C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "C1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C2.class
+ Compiled from "C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "C2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C3.class
+ Compiled from "C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/C3
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "C3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CA.class
+ Compiled from "CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/CA
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "CA.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CB.class
+ Compiled from "CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/CB
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "CB.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.class
+ Compiled from "Class_C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "Class_C1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.class
+ Compiled from "Class_C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "Class_C2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.class
+ Compiled from "Class_C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C3
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+ super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "Class_C3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.class
+ Compiled from "Class_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "Class_I1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.class
+ Compiled from "Class_I1_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I1,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+ super_class: #x // java/lang/Object
+ interfaces: 2, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "Class_I1_IA.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.class
+ Compiled from "Class_I2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 implements com.android.hoststubgen.test.tinyframework.subclasstest.I2
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "Class_I2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.class
+ Compiled from "Class_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.I3
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "Class_I3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I1.class
+ Compiled from "I1.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/I1
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "I1.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class
+ Compiled from "I2.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 extends com.android.hoststubgen.test.tinyframework.subclasstest.I1
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/I2
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "I2.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class
+ Compiled from "I3.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 extends com.android.hoststubgen.test.tinyframework.subclasstest.I2
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/I3
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "I3.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class
+ Compiled from "IA.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/IA
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "IA.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class
+ Compiled from "IB.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
+ minor version: 0
+ major version: 65
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/subclasstest/IB
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "IB.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/supported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/supported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 3, attributes: 3
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/supported/UnsupportedClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.supported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/supported/UnsupportedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/supported/UnsupportedClass;
+ 11 10 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/supported/UnsupportedClass
+ x: ldc #x // String getValue
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/supported/UnsupportedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/unsupported/UnsupportedClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/unsupported/UnsupportedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 14 0 this Lcom/unsupported/UnsupportedClass;
+ 11 14 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/unsupported/UnsupportedClass
+ x: ldc #x // String getValue
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/unsupported/UnsupportedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class
+ Compiled from "TinyFrameworkToBeRenamed.java"
+public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed
+ minor version: 0
+ major version: 65
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 3, attributes: 3
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+ 11 10 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+ x: ldc #x // String getValue
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkToBeRenamed.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
index 7a7de3553829..88fa492addb8 100755
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
@@ -20,18 +20,23 @@ import os
import unittest
import subprocess
-GOLDEN_DIR = 'golden-output'
+GOLDEN_DIRS = [
+ 'golden-output',
+ 'golden-output.RELEASE_TARGET_JAVA_21',
+]
+
# Run diff.
def run_diff(file1, file2):
- command = ['diff', '-u', '--ignore-blank-lines', '--ignore-space-change', file1, file2]
+ command = ['diff', '-u', '--ignore-blank-lines',
+ '--ignore-space-change', file1, file2]
print(' '.join(command))
- result = subprocess.run(command, stderr = sys.stdout)
+ result = subprocess.run(command, stderr=sys.stdout)
success = result.returncode == 0
if success:
- print(f'No diff found.')
+ print('No diff found.')
else:
print(f'Fail: {file1} and {file2} are different.')
@@ -39,27 +44,42 @@ def run_diff(file1, file2):
# Check one golden file.
-def check_one_file(filename):
+def check_one_file(golden_dir, filename):
print(f'= Checking file: {filename}')
- return run_diff(os.path.join(GOLDEN_DIR, filename), filename)
+ return run_diff(os.path.join(golden_dir, filename), filename)
+
class TestWithGoldenOutput(unittest.TestCase):
# Test to check the generated jar files to the golden output.
+ # Depending on build flags, the golden output may differ in expected ways.
+ # So only expect the files to match one of the possible golden outputs.
def test_compare_to_golden(self):
- self.skipTest("test cannot handle multiple images (see b/378470825)")
- files = os.listdir(GOLDEN_DIR)
+ success = False
+
+ for golden_dir in GOLDEN_DIRS:
+ if self.matches_golden(golden_dir):
+ success = True
+ print(f"Test passes for dir: {golden_dir}")
+ break
+
+ if not success:
+ self.fail('Some files are different. ' +
+ 'See stdout log for more details.')
+
+ def matches_golden(self, golden_dir):
+ files = os.listdir(golden_dir)
files.sort()
- print(f"Golden files: {files}")
- success = True
+ print(f"Golden files for {golden_dir}: {files}")
+ match_success = True
for file in files:
- if not check_one_file(file):
- success = False
+ if not check_one_file(golden_dir, file):
+ match_success = False
+
+ return match_success
- if not success:
- self.fail('Some files are different. See stdout log for more details.')
if __name__ == "__main__":
unittest.main(verbosity=2)
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt
index 8ec0932d89dd..61e254b225c3 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt
@@ -43,7 +43,7 @@ fun checkClass(cn: ClassNode, classes: ClassNodes): Boolean {
}
var allOk = true
- log.i("Checking ${cn.name.toHumanReadableClassName()}")
+ log.v("Checking ${cn.name.toHumanReadableClassName()}")
// See if there's any class that extends a legacy base class.
// But ignore the base classes in android.test.
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 2808056f72c9..a0b989b44f4f 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -55,16 +55,6 @@ flag {
}
flag {
- name: "compute_window_changes_on_a11y_v2"
- namespace: "accessibility"
- description: "Computes accessibility window changes in accessibility instead of wm package."
- bug: "322444245"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "deprecate_package_list_observer"
namespace: "accessibility"
description: "Stops using the deprecated PackageListObserver."
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d4af7b765254..c210e726fc12 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -4503,13 +4503,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
if (shortcutType == HARDWARE) {
skipVolumeShortcutDialogTimeoutRestriction(userId);
- if (com.android.server.accessibility.Flags.enableHardwareShortcutDisablesWarning()) {
- persistIntToSetting(
- userId,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
- AccessibilityShortcutController.DialogStatus.SHOWN
- );
- }
+ persistIntToSetting(
+ userId,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN
+ );
} else if (shortcutType == SOFTWARE) {
// Update the A11y FAB size to large when the Magnification shortcut is
// enabled and the user hasn't changed the floating button size
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9a81aa6cc506..5cbe0c4fe4d2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -433,22 +433,10 @@ public class AccessibilityWindowManager {
return Collections.emptyList();
}
- /**
- * Callbacks from window manager when there's an accessibility change in windows.
- *
- * @param forceSend Send the windows for accessibility even if they haven't changed.
- * @param topFocusedDisplayId The display Id which has the top focused window.
- * @param topFocusedWindowToken The window token of top focused window.
- * @param windows The windows for accessibility.
- */
- @Override
- public void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
+ private void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows) {
+ // TODO(b/322444245): no longer need to get a lock.
synchronized (mLock) {
- if (!Flags.computeWindowChangesOnA11yV2()) {
- // If the flag is enabled, it's already done in #createWindowInfoListLocked.
- updateWindowsByWindowAttributesLocked(windows);
- }
if (DEBUG) {
Slogf.i(LOG_TAG, "mDisplayId=%d, topFocusedDisplayId=%d, currentUserId=%d, "
+ "visibleBgUsers=%s", mDisplayId, topFocusedDisplayId,
@@ -490,9 +478,7 @@ public class AccessibilityWindowManager {
}
/**
- * Called when the windows for accessibility changed. This is called if
- * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
- * true.
+ * Called when the windows for accessibility changed.
*
* @param forceSend Send the windows for accessibility even if they haven't
* changed.
@@ -655,16 +641,6 @@ public class AccessibilityWindowManager {
return true;
}
- private void updateWindowsByWindowAttributesLocked(List<WindowInfo> windows) {
- for (int i = windows.size() - 1; i >= 0; i--) {
- final WindowInfo windowInfo = windows.get(i);
- final IBinder token = windowInfo.token;
- final int windowId = findWindowIdLocked(
- mAccessibilityUserManager.getCurrentUserIdLocked(), token);
- updateWindowWithWindowAttributes(windowInfo, mWindowAttributes.get(windowId));
- }
- }
-
private void updateWindowWithWindowAttributes(@NonNull WindowInfo windowInfo,
@Nullable AccessibilityWindowAttributes attributes) {
if (attributes == null) {
@@ -990,19 +966,6 @@ public class AccessibilityWindowManager {
private AccessibilityWindowInfo populateReportedWindowLocked(int userId,
WindowInfo window, SparseArray<AccessibilityWindowInfo> oldWindowsById) {
final int windowId = findWindowIdLocked(userId, window.token);
-
- // With the flag enabled, createWindowInfoListLocked() already removes invalid windows.
- if (!Flags.computeWindowChangesOnA11yV2()) {
- if (windowId < 0) {
- return null;
- }
-
- // Don't need to add the embedded hierarchy windows into the a11y windows list.
- if (isEmbeddedHierarchyWindowsLocked(windowId)) {
- return null;
- }
- }
-
final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
reportedWindow.setId(windowId);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index c6a966f47952..d11ae0a6ad97 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -58,8 +58,6 @@ import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
-import android.view.MotionEvent.PointerCoords;
-import android.view.MotionEvent.PointerProperties;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.VelocityTracker;
@@ -155,9 +153,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
@VisibleForTesting State mCurrentState;
@VisibleForTesting State mPreviousState;
- private PointerCoords[] mTempPointerCoords;
- private PointerProperties[] mTempPointerProperties;
-
@VisibleForTesting static final int OVERSCROLL_NONE = 0;
@VisibleForTesting static final int OVERSCROLL_LEFT_EDGE = 1;
@VisibleForTesting static final int OVERSCROLL_RIGHT_EDGE = 2;
@@ -430,38 +425,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
mPanningScalingState.clear();
}
- private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
- final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
- if (oldSize < size) {
- PointerCoords[] oldTempPointerCoords = mTempPointerCoords;
- mTempPointerCoords = new PointerCoords[size];
- if (oldTempPointerCoords != null) {
- System.arraycopy(oldTempPointerCoords, 0, mTempPointerCoords, 0, oldSize);
- }
- }
- for (int i = oldSize; i < size; i++) {
- mTempPointerCoords[i] = new PointerCoords();
- }
- return mTempPointerCoords;
- }
-
- private PointerProperties[] getTempPointerPropertiesWithMinSize(int size) {
- final int oldSize = (mTempPointerProperties != null) ? mTempPointerProperties.length
- : 0;
- if (oldSize < size) {
- PointerProperties[] oldTempPointerProperties = mTempPointerProperties;
- mTempPointerProperties = new PointerProperties[size];
- if (oldTempPointerProperties != null) {
- System.arraycopy(oldTempPointerProperties, 0, mTempPointerProperties, 0,
- oldSize);
- }
- }
- for (int i = oldSize; i < size; i++) {
- mTempPointerProperties[i] = new PointerProperties();
- }
- return mTempPointerProperties;
- }
-
@VisibleForTesting
void transitionTo(State state) {
if (DEBUG_STATE_TRANSITIONS) {
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
index 44ae1d1fbbbf..81e83b563945 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
@@ -16,7 +16,6 @@
package com.android.server.appfunctions;
-import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -24,15 +23,21 @@ import java.util.concurrent.TimeUnit;
/** Executors for App function operations. */
public final class AppFunctionExecutors {
+ static final int sConcurrency = Runtime.getRuntime().availableProcessors();
+
/** Executor for operations that do not need to block. */
- public static final Executor THREAD_POOL_EXECUTOR =
+ public static final ThreadPoolExecutor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(
- /* corePoolSize= */ Runtime.getRuntime().availableProcessors(),
- /* maxConcurrency= */ Runtime.getRuntime().availableProcessors(),
- /* keepAliveTime= */ 0L,
+ /* corePoolSize= */ sConcurrency,
+ /* maxConcurrency= */ sConcurrency,
+ /* keepAliveTime= */ 1L,
/* unit= */ TimeUnit.SECONDS,
/* workQueue= */ new LinkedBlockingQueue<>(),
new NamedThreadFactory("AppFunctionExecutors"));
+ static {
+ THREAD_POOL_EXECUTOR.allowCoreThreadTimeOut(true);
+ }
+
private AppFunctionExecutors() {}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 0bd879b7568d..762665c00e05 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.appwidget;
+import static android.appwidget.flags.Flags.checkRemoteViewsUriPermission;
import static android.appwidget.flags.Flags.remoteAdapterConversion;
import static android.appwidget.flags.Flags.remoteViewsProto;
import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
@@ -62,6 +63,7 @@ import android.appwidget.AppWidgetProviderInfo;
import android.appwidget.PendingHostUpdate;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.Intent.FilterComparison;
@@ -150,6 +152,8 @@ import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.WidgetBackupProvider;
+import com.android.server.uri.GrantUri;
+import com.android.server.uri.UriGrantsManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -607,7 +611,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// ... and see if these are hosts we've been awaiting.
// NOTE: We are backing up and restoring only the owner.
// TODO: http://b/22388012
- if (newPackageAdded && userId == mUserManager.getMainUser().getIdentifier()) {
+ UserHandle mainUser = mUserManager.getMainUser();
+ if (newPackageAdded && mainUser != null && userId == mainUser.getIdentifier()) {
final int uid = getUidForPackage(pkgName, userId);
if (uid >= 0 ) {
resolveHostUidLocked(pkgName, uid);
@@ -2547,6 +2552,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// Make sure the package runs under the caller uid.
mSecurityPolicy.enforceCallFromPackage(callingPackage);
+ // Make sure RemoteViews do not contain URIs that the caller cannot access.
+ if (checkRemoteViewsUriPermission()) {
+ checkRemoteViewsUris(views);
+ }
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
@@ -2567,6 +2576,39 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
/**
+ * Checks that all of the Uris in the given RemoteViews are accessible to the caller.
+ */
+ private void checkRemoteViewsUris(RemoteViews views) {
+ UriGrantsManagerInternal uriGrantsManager = LocalServices.getService(
+ UriGrantsManagerInternal.class);
+ int callingUid = Binder.getCallingUid();
+ int callingUser = UserHandle.getCallingUserId();
+ views.visitUris(uri -> {
+ switch (uri.getScheme()) {
+ // Check that content:// URIs are accessible to the caller.
+ case ContentResolver.SCHEME_CONTENT:
+ boolean canAccessUri = uriGrantsManager.checkUriPermission(
+ GrantUri.resolve(callingUser, uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION), callingUid,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ /* isFullAccessForContentUri= */ true);
+ if (!canAccessUri) {
+ throw new SecurityException(
+ "Provider uid " + callingUid + " cannot access URI " + uri);
+ }
+ break;
+ // android.resource:// URIs are always allowed.
+ case ContentResolver.SCHEME_ANDROID_RESOURCE:
+ break;
+ // file:// and any other schemes are disallowed.
+ case ContentResolver.SCHEME_FILE:
+ default:
+ throw new SecurityException("Disallowed URI " + uri + " in RemoteViews.");
+ }
+ });
+ }
+
+ /**
* Increment the counter of widget ids and return the new id.
*
* Typically called by {@link #allocateAppWidgetId} when a instance of widget is created,
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index 1803424ae7d7..5d2ef770b96b 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -44,6 +44,16 @@ flag {
}
flag {
+ name: "test_flag"
+ namespace: "autofill"
+ description: "Test flag "
+ bug: "377868687"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "add_session_id_to_client_state"
namespace: "autofill"
description: "Include the session id into the FillEventHistory events as part of ClientState"
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index 1dc3b73d2bd3..b3fe5f234bc2 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -2,6 +2,13 @@ package: "android.service.autofill"
container: "system"
flag {
+ name: "autofill_w_metrics"
+ namespace: "autofill"
+ description: "Guards against new metrics definitions introduced in W"
+ bug: "342676602"
+}
+
+flag {
name: "autofill_credman_integration"
namespace: "autofill"
description: "Guards Autofill Framework against Autofill-Credman integration"
@@ -22,3 +29,11 @@ flag {
description: "Guards against Autofill-Credman Phase1 developer integration via new APIs"
bug: "320730001"
}
+
+flag {
+ name: "fill_dialog_improvements"
+ is_exported: true
+ namespace: "autofill"
+ description: "Improvements for Fill Dialog, including deprecation of pre-trigger API's"
+ bug: "336223371"
+}
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index cd2a535aa2c5..4f632c9e28a1 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -28,8 +28,11 @@ import android.app.ActivityManager;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.WindowNode;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
import android.content.ComponentName;
import android.content.Context;
+import android.graphics.drawable.Icon;
import android.hardware.display.DisplayManager;
import android.metrics.LogMaker;
import android.os.UserHandle;
@@ -97,11 +100,12 @@ public final class Helper {
@UserIdInt int userId, @NonNull RemoteViews rView) {
final AtomicBoolean permissionsOk = new AtomicBoolean(true);
- rView.visitUris(uri -> {
- int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
- boolean allowed = uriOwnerId == userId;
- permissionsOk.set(allowed & permissionsOk.get());
- });
+ rView.visitUris(
+ uri -> {
+ int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri, userId);
+ boolean allowed = uriOwnerId == userId;
+ permissionsOk.set(allowed & permissionsOk.get());
+ });
return permissionsOk.get();
}
@@ -150,6 +154,47 @@ public final class Helper {
return (ok ? rView : null);
}
+ /**
+ * Checks the URI permissions of the icon in the slice, to see if the current userId is able to
+ * access it.
+ *
+ * <p>Returns null if slice contains user inaccessible icons
+ *
+ * <p>TODO: instead of returning a null Slice when the current userId cannot access an icon,
+ * return a reconstructed Slice without the icons. This is currently non-trivial since there are
+ * no public methods to generically add SliceItems to Slices
+ */
+ public static @Nullable Slice sanitizeSlice(Slice slice) {
+ if (slice == null) {
+ return null;
+ }
+
+ int userId = ActivityManager.getCurrentUser();
+
+ // Recontruct the Slice, filtering out bad icons
+ for (SliceItem sliceItem : slice.getItems()) {
+ if (!sliceItem.getFormat().equals(SliceItem.FORMAT_IMAGE)) {
+ // Not an image slice
+ continue;
+ }
+
+ Icon icon = sliceItem.getIcon();
+ if (icon.getType() != Icon.TYPE_URI
+ && icon.getType() != Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ // No URIs to sanitize
+ continue;
+ }
+
+ int iconUriId = android.content.ContentProvider.getUserIdFromUri(icon.getUri(), userId);
+
+ if (iconUriId != userId) {
+ Slog.w(TAG, "sanitizeSlice() user: " + userId + " cannot access icons in Slice");
+ return null;
+ }
+ }
+
+ return slice;
+ }
@Nullable
static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
@@ -308,7 +353,10 @@ public final class Helper {
private static void addAutofillableIds(@NonNull ViewNode node,
@NonNull ArrayList<AutofillId> ids, boolean autofillableOnly) {
if (!autofillableOnly || node.getAutofillType() != View.AUTOFILL_TYPE_NONE) {
- ids.add(node.getAutofillId());
+ AutofillId id = node.getAutofillId();
+ if (id != null) {
+ ids.add(id);
+ }
}
final int size = node.getChildCount();
for (int i = 0; i < size; i++) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
index 38a412fa063d..50a26b355537 100644
--- a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
+++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
@@ -27,6 +27,7 @@ import android.service.autofill.InlinePresentation;
import android.util.Slog;
import com.android.server.LocalServices;
+import com.android.server.autofill.Helper;
import com.android.server.autofill.RemoteInlineSuggestionRenderService;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -83,6 +84,10 @@ final class RemoteInlineSuggestionViewConnector {
*/
public boolean renderSuggestion(int width, int height,
@NonNull IInlineSuggestionUiCallback callback) {
+ if (Helper.sanitizeSlice(mInlinePresentation.getSlice()) == null) {
+ if (sDebug) Slog.d(TAG, "Skipped rendering inline suggestion.");
+ return false;
+ }
if (mRemoteRenderService != null) {
if (sDebug) Slog.d(TAG, "Request to recreate the UI");
mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig
index d53f949753d8..fcb7934f7ca0 100644
--- a/services/backup/flags.aconfig
+++ b/services/backup/flags.aconfig
@@ -60,3 +60,12 @@ flag {
bug: "331749778"
is_fixed_read_only: true
}
+
+flag {
+ name: "enable_restricted_mode_changes"
+ namespace: "onboarding"
+ description: "Enables the new framework behavior of not putting apps in restricted mode for "
+ "B&R operations in certain cases."
+ bug: "376661510"
+ is_fixed_read_only: true
+}
diff --git a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
new file mode 100644
index 000000000000..5e4bab15952d
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
+import static com.android.server.backup.BackupManagerService.TAG;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ApplicationThreadConstants;
+import android.app.IActivityManager;
+import android.app.IBackupAgent;
+import android.app.backup.BackupAnnotations;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.backup.internal.LifecycleOperationStorage;
+
+import java.util.Set;
+
+/**
+ * Handles the lifecycle of {@link IBackupAgent}s that the {@link UserBackupManagerService}
+ * communicates with.
+ *
+ * <p>There can only be one agent that's connected to at a time.
+ *
+ * <p>There should be only one instance of this class per {@link UserBackupManagerService}.
+ */
+public class BackupAgentConnectionManager {
+
+ /**
+ * Enables the OS making a decision on whether backup restricted mode should be used for apps
+ * that haven't explicitly opted in or out. See
+ * {@link android.content.pm.PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE} for details.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA)
+ public static final long OS_DECIDES_BACKUP_RESTRICTED_MODE = 376661510;
+
+ // The thread performing the sequence of queued backups binds to each app's agent
+ // in succession. Bind notifications are asynchronously delivered through the
+ // Activity Manager; use this lock object to signal when a requested binding has
+ // completed.
+ private final Object mAgentConnectLock = new Object();
+ private IBackupAgent mConnectedAgent;
+ private volatile boolean mConnecting;
+ private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>();
+ private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>();
+
+ private final IActivityManager mActivityManager;
+ private final ActivityManagerInternal mActivityManagerInternal;
+ private final LifecycleOperationStorage mOperationStorage;
+ private final PackageManager mPackageManager;
+ private final UserBackupManagerService mUserBackupManagerService;
+ private final int mUserId;
+ private final String mUserIdMsg;
+
+ BackupAgentConnectionManager(LifecycleOperationStorage operationStorage,
+ PackageManager packageManager, UserBackupManagerService userBackupManagerService,
+ int userId) {
+ mActivityManager = ActivityManager.getService();
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mOperationStorage = operationStorage;
+ mPackageManager = packageManager;
+ mUserBackupManagerService = userBackupManagerService;
+ mUserId = userId;
+ mUserIdMsg = "[UserID:" + userId + "] ";
+ }
+
+ /**
+ * Fires off a backup agent, blocking until it attaches (and ActivityManager will call
+ * {@link #agentConnected(String, IBinder)}) or until this operation times out.
+ *
+ * @param mode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}.
+ */
+ @Nullable
+ public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
+ @BackupAnnotations.BackupDestination int backupDestination) {
+ IBackupAgent agent = null;
+ synchronized (mAgentConnectLock) {
+ mConnecting = true;
+ mConnectedAgent = null;
+ boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode,
+ app.packageName);
+ try {
+ if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
+ backupDestination, useRestrictedMode)) {
+ Slog.d(TAG, mUserIdMsg + "awaiting agent for " + app);
+
+ // success; wait for the agent to arrive
+ // only wait 10 seconds for the bind to happen
+ long timeoutMark = System.currentTimeMillis() + 10 * 1000;
+ while (mConnecting && mConnectedAgent == null && (System.currentTimeMillis()
+ < timeoutMark)) {
+ try {
+ mAgentConnectLock.wait(5000);
+ } catch (InterruptedException e) {
+ // just bail
+ Slog.w(TAG, mUserIdMsg + "Interrupted: " + e);
+ mConnecting = false;
+ mConnectedAgent = null;
+ }
+ }
+
+ // if we timed out with no connect, abort and move on
+ if (mConnecting) {
+ Slog.w(TAG, mUserIdMsg + "Timeout waiting for agent " + app);
+ mConnectedAgent = null;
+ }
+ Slog.i(TAG, mUserIdMsg + "got agent " + mConnectedAgent);
+ agent = mConnectedAgent;
+ }
+ } catch (RemoteException e) {
+ // can't happen - ActivityManager is local
+ }
+ }
+ if (agent == null) {
+ mActivityManagerInternal.clearPendingBackup(mUserId);
+ }
+ return agent;
+ }
+
+ /**
+ * Tell the ActivityManager that we are done with the {@link IBackupAgent} of this {@code app}.
+ * It will tell the app to destroy the agent.
+ */
+ public void unbindAgent(ApplicationInfo app) {
+ try {
+ mActivityManager.unbindBackupAgent(app);
+ } catch (RemoteException e) {
+ // Can't happen - activity manager is local
+ }
+ }
+
+ /**
+ * Callback: a requested backup agent has been instantiated. This should only be called from
+ * the
+ * {@link ActivityManager} when it's telling us that an agent is ready after a call to
+ * {@link #bindToAgentSynchronous(ApplicationInfo, int, int)}.
+ */
+ public void agentConnected(String packageName, IBinder agentBinder) {
+ synchronized (mAgentConnectLock) {
+ if (getCallingUid() == android.os.Process.SYSTEM_UID) {
+ Slog.d(TAG,
+ mUserIdMsg + "agentConnected pkg=" + packageName + " agent=" + agentBinder);
+ mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder);
+ mConnecting = false;
+ } else {
+ Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid()
+ + " claiming agent connected");
+ }
+ mAgentConnectLock.notifyAll();
+ }
+ }
+
+ /**
+ * Callback: a backup agent has failed to come up, or has unexpectedly quit. If the agent failed
+ * to come up in the first place, the agentBinder argument will be {@code null}. This should
+ * only be called from the {@link ActivityManager}.
+ */
+ public void agentDisconnected(String packageName) {
+ synchronized (mAgentConnectLock) {
+ if (getCallingUid() == Process.SYSTEM_UID) {
+ mConnectedAgent = null;
+ mConnecting = false;
+ } else {
+ Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid()
+ + " claiming agent disconnected");
+ }
+ Slog.w(TAG, mUserIdMsg + "agentDisconnected: the backup agent for " + packageName
+ + " died: cancel current operations");
+
+ // Offload operation cancellation off the main thread as the cancellation callbacks
+ // might call out to BackupTransport. Other operations started on the same package
+ // before the cancellation callback has executed will also be cancelled by the callback.
+ Runnable cancellationRunnable = () -> {
+ // handleCancel() causes the PerformFullTransportBackupTask to go on to
+ // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
+ // that the package being backed up doesn't get stuck in restricted mode until the
+ // backup time-out elapses.
+ for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
+ if (MORE_DEBUG) {
+ Slog.d(TAG,
+ mUserIdMsg + "agentDisconnected: will handleCancel(all) for token:"
+ + Integer.toHexString(token));
+ }
+ mUserBackupManagerService.handleCancel(token, true /* cancelAll */);
+ }
+ };
+ getThreadForCancellation(cancellationRunnable).start();
+
+ mAgentConnectLock.notifyAll();
+ }
+ }
+
+ /**
+ * Marks the given set of packages as packages that should not be put into restricted mode if
+ * they are started for the given {@link BackupAnnotations.OperationType}.
+ */
+ public void setNoRestrictedModePackages(Set<String> packageNames,
+ @BackupAnnotations.OperationType int opType) {
+ if (opType == BackupAnnotations.OperationType.BACKUP) {
+ mBackupNoRestrictedModePackages.clear();
+ mBackupNoRestrictedModePackages.addAll(packageNames);
+ } else if (opType == BackupAnnotations.OperationType.RESTORE) {
+ mRestoreNoRestrictedModePackages.clear();
+ mRestoreNoRestrictedModePackages.addAll(packageNames);
+ } else {
+ throw new IllegalArgumentException("opType must be BACKUP or RESTORE");
+ }
+ }
+
+ /**
+ * Clears the list of packages that should not be put into restricted mode for either backup or
+ * restore.
+ */
+ public void clearNoRestrictedModePackages() {
+ mBackupNoRestrictedModePackages.clear();
+ mRestoreNoRestrictedModePackages.clear();
+ }
+
+ /**
+ * If the app has specified {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE}, then
+ * its value is returned. If it hasn't and it targets an SDK below
+ * {@link Build.VERSION_CODES#BAKLAVA} then returns true. If it targets a newer SDK, then
+ * returns the decision made by the {@link android.app.backup.BackupTransport}.
+ *
+ * <p>When this method is called, we should have already asked the transport and cached its
+ * response in {@link #mBackupNoRestrictedModePackages} or
+ * {@link #mRestoreNoRestrictedModePackages} so this method will immediately return without
+ * any IPC to the transport.
+ */
+ private boolean shouldUseRestrictedBackupModeForPackage(
+ @BackupAnnotations.OperationType int mode, String packageName) {
+ if (!Flags.enableRestrictedModeChanges()) {
+ return true;
+ }
+
+ // Key/Value apps are never put in restricted mode.
+ if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
+ || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) {
+ return false;
+ }
+
+ try {
+ PackageManager.Property property = mPackageManager.getPropertyAsUser(
+ PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE,
+ packageName, /* className= */ null, mUserId);
+ if (property.isBoolean()) {
+ // If the package has explicitly specified, we won't ask the transport.
+ return property.getBoolean();
+ } else {
+ Slog.w(TAG,
+ PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE + "must be a boolean.");
+ }
+ } catch (NameNotFoundException e) {
+ // This is expected when the package has not defined the property in its manifest.
+ }
+
+ // The package has not specified the property. The behavior depends on the package's
+ // targetSdk.
+ // <36 gets the old behavior of always using restricted mode.
+ if (!CompatChanges.isChangeEnabled(OS_DECIDES_BACKUP_RESTRICTED_MODE, packageName,
+ UserHandle.of(mUserId))) {
+ return true;
+ }
+
+ // Apps targeting >=36 get the behavior decided by the transport.
+ // By this point, we should have asked the transport and cached its decision.
+ if ((mode == ApplicationThreadConstants.BACKUP_MODE_FULL
+ && mBackupNoRestrictedModePackages.contains(packageName)) || (
+ mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL
+ && mRestoreNoRestrictedModePackages.contains(packageName))) {
+ Slog.d(TAG, "Transport requested no restricted mode for: " + packageName);
+ return false;
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ Thread getThreadForCancellation(Runnable operation) {
+ return new Thread(operation, /* operationName */ "agent-disconnected");
+ }
+
+ @VisibleForTesting
+ int getCallingUid() {
+ return Binder.getCallingUid();
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 5f0071d47c89..3f6ede95eaf9 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -658,7 +658,8 @@ public class BackupManagerService extends IBackupManager.Stub {
getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
if (userBackupManagerService != null) {
- userBackupManagerService.agentConnected(packageName, agentBinder);
+ userBackupManagerService.getBackupAgentConnectionManager().agentConnected(packageName,
+ agentBinder);
}
}
@@ -683,7 +684,8 @@ public class BackupManagerService extends IBackupManager.Stub {
getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
if (userBackupManagerService != null) {
- userBackupManagerService.agentDisconnected(packageName);
+ userBackupManagerService.getBackupAgentConnectionManager().agentDisconnected(
+ packageName);
}
}
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index f5d68362c70a..136bacdd6399 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -146,7 +146,8 @@ public class KeyValueAdbBackupEngine {
private IBackupAgent bindToAgent(ApplicationInfo targetApp) {
try {
- return mBackupManagerService.bindToAgentSynchronous(targetApp,
+ return mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
+ targetApp,
ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL,
BackupAnnotations.BackupDestination.CLOUD);
} catch (SecurityException e) {
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 466d477992b3..e085f6e63067 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -44,7 +44,6 @@ import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
-import android.app.IBackupAgent;
import android.app.PendingIntent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupAnnotations;
@@ -79,7 +78,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
@@ -302,8 +300,6 @@ public class UserBackupManagerService {
// CPU on bring-up and increase time-to-UI.
private static final long INITIALIZATION_DELAY_MILLIS = 3000;
- // Timeout interval for deciding that a bind has taken too long.
- private static final long BIND_TIMEOUT_INTERVAL = 10 * 1000;
// Timeout interval for deciding that a clear-data has taken too long.
private static final long CLEAR_DATA_TIMEOUT_INTERVAL = 30 * 1000;
@@ -354,17 +350,7 @@ public class UserBackupManagerService {
// locking around the pending-backup management
private final Object mQueueLock = new Object();
-
private final UserBackupPreferences mBackupPreferences;
-
- // The thread performing the sequence of queued backups binds to each app's agent
- // in succession. Bind notifications are asynchronously delivered through the
- // Activity Manager; use this lock object to signal when a requested binding has
- // completed.
- private final Object mAgentConnectLock = new Object();
- private IBackupAgent mConnectedAgent;
- private volatile boolean mConnecting;
-
private volatile boolean mBackupRunning;
private volatile long mLastBackupPass;
@@ -394,6 +380,7 @@ public class UserBackupManagerService {
private ActiveRestoreSession mActiveRestoreSession;
+ private final BackupAgentConnectionManager mBackupAgentConnectionManager;
private final LifecycleOperationStorage mOperationStorage;
private final Random mTokenGenerator = new Random();
@@ -523,17 +510,22 @@ public class UserBackupManagerService {
@VisibleForTesting
UserBackupManagerService(Context context, PackageManager packageManager,
LifecycleOperationStorage operationStorage, TransportManager transportManager,
- BackupHandler backupHandler, BackupManagerConstants backupManagerConstants) {
+ BackupHandler backupHandler, BackupManagerConstants backupManagerConstants,
+ IActivityManager activityManager, ActivityManagerInternal activityManagerInternal) {
mContext = context;
mUserId = 0;
mRegisterTransportsRequestedTime = 0;
mPackageManager = packageManager;
mOperationStorage = operationStorage;
+ mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage,
+ mPackageManager, this, mUserId);
mTransportManager = transportManager;
mFullBackupQueue = new ArrayList<>();
mBackupHandler = backupHandler;
mConstants = backupManagerConstants;
+ mActivityManager = activityManager;
+ mActivityManagerInternal = activityManagerInternal;
mBaseStateDir = null;
mDataDir = null;
@@ -543,13 +535,11 @@ public class UserBackupManagerService {
mRunInitReceiver = null;
mRunInitIntent = null;
mAgentTimeoutParameters = null;
- mActivityManagerInternal = null;
mAlarmManager = null;
mWakelock = null;
mBackupPreferences = null;
mBackupPasswordManager = null;
mPackageManagerBinder = null;
- mActivityManager = null;
mBackupManagerBinder = null;
mScheduledBackupEligibility = null;
}
@@ -582,6 +572,8 @@ public class UserBackupManagerService {
mAgentTimeoutParameters.start();
mOperationStorage = new LifecycleOperationStorage(mUserId);
+ mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage,
+ mPackageManager, this, mUserId);
Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null");
mBackupHandler = new BackupHandler(this, mOperationStorage, userBackupThread);
@@ -1643,65 +1635,6 @@ public class UserBackupManagerService {
}
}
- /** Fires off a backup agent, blocking until it attaches or times out. */
- @Nullable
- public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
- @BackupDestination int backupDestination) {
- IBackupAgent agent = null;
- synchronized (mAgentConnectLock) {
- mConnecting = true;
- mConnectedAgent = null;
- try {
- if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
- backupDestination)) {
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app));
-
- // success; wait for the agent to arrive
- // only wait 10 seconds for the bind to happen
- long timeoutMark = System.currentTimeMillis() + BIND_TIMEOUT_INTERVAL;
- while (mConnecting && mConnectedAgent == null
- && (System.currentTimeMillis() < timeoutMark)) {
- try {
- mAgentConnectLock.wait(5000);
- } catch (InterruptedException e) {
- // just bail
- Slog.w(TAG, addUserIdToLogMessage(mUserId, "Interrupted: " + e));
- mConnecting = false;
- mConnectedAgent = null;
- }
- }
-
- // if we timed out with no connect, abort and move on
- if (mConnecting) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(mUserId, "Timeout waiting for agent " + app));
- mConnectedAgent = null;
- }
- if (DEBUG) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "got agent " + mConnectedAgent));
- }
- agent = mConnectedAgent;
- }
- } catch (RemoteException e) {
- // can't happen - ActivityManager is local
- }
- }
- if (agent == null) {
- mActivityManagerInternal.clearPendingBackup(mUserId);
- }
- return agent;
- }
-
- /** Unbind from a backup agent. */
- public void unbindAgent(ApplicationInfo app) {
- try {
- mActivityManager.unbindBackupAgent(app);
- } catch (RemoteException e) {
- // Can't happen - activity manager is local
- }
- }
-
/**
* Clear an application's data after a failed restore, blocking until the operation completes or
* times out.
@@ -2474,10 +2407,6 @@ public class UserBackupManagerService {
AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId);
}
- // *****************************
- // NEW UNIFIED RESTORE IMPLEMENTATION
- // *****************************
-
/** Schedule a backup pass for {@code packageName}. */
public void dataChangedImpl(String packageName) {
HashSet<String> targets = dataChangedTargets(packageName);
@@ -3794,83 +3723,6 @@ public class UserBackupManagerService {
}
/**
- * Callback: a requested backup agent has been instantiated. This should only be called from the
- * {@link ActivityManager}.
- */
- public void agentConnected(String packageName, IBinder agentBinder) {
- synchronized (mAgentConnectLock) {
- if (Binder.getCallingUid() == Process.SYSTEM_UID) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "agentConnected pkg=" + packageName + " agent=" + agentBinder));
- mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder);
- mConnecting = false;
- } else {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "Non-system process uid="
- + Binder.getCallingUid()
- + " claiming agent connected"));
- }
- mAgentConnectLock.notifyAll();
- }
- }
-
- /**
- * Callback: a backup agent has failed to come up, or has unexpectedly quit. If the agent failed
- * to come up in the first place, the agentBinder argument will be {@code null}. This should
- * only be called from the {@link ActivityManager}.
- */
- public void agentDisconnected(String packageName) {
- synchronized (mAgentConnectLock) {
- if (Binder.getCallingUid() == Process.SYSTEM_UID) {
- mConnectedAgent = null;
- mConnecting = false;
- } else {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "Non-system process uid="
- + Binder.getCallingUid()
- + " claiming agent disconnected"));
- }
- Slog.w(TAG, "agentDisconnected: the backup agent for " + packageName
- + " died: cancel current operations");
-
- // Offload operation cancellation off the main thread as the cancellation callbacks
- // might call out to BackupTransport. Other operations started on the same package
- // before the cancellation callback has executed will also be cancelled by the callback.
- Runnable cancellationRunnable = () -> {
- // handleCancel() causes the PerformFullTransportBackupTask to go on to
- // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
- // that the package being backed up doesn't get stuck in restricted mode until the
- // backup time-out elapses.
- for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "agentDisconnected: will handleCancel(all) for token:"
- + Integer.toHexString(token));
- }
- handleCancel(token, true /* cancelAll */);
- }
- };
- getThreadForAsyncOperation(/* operationName */ "agent-disconnected",
- cancellationRunnable).start();
-
- mAgentConnectLock.notifyAll();
- }
- }
-
- @VisibleForTesting
- Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
- return new Thread(operation, operationName);
- }
-
- /**
* An application being installed will need a restore pass, then the {@link PackageManager} will
* need to be told when the restore is finished.
*/
@@ -4417,4 +4269,8 @@ public class UserBackupManagerService {
public IBackupManager getBackupManagerBinder() {
return mBackupManagerBinder;
}
+
+ public BackupAgentConnectionManager getBackupAgentConnectionManager() {
+ return mBackupAgentConnectionManager;
+ }
}
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 12712063e344..b98cb1086680 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -314,7 +314,7 @@ public class FullBackupEngine {
Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName);
}
mAgent =
- backupManagerService.bindToAgentSynchronous(
+ backupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL,
mBackupEligibilityRules.getBackupDestination());
}
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index cca166b0939c..65730c9591a8 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -16,6 +16,8 @@
package com.android.server.backup.fullbackup;
+import static android.app.backup.BackupAnnotations.OperationType.BACKUP;
+
import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
@@ -34,6 +36,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -388,6 +391,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
}
}
+ // We ask the transport which packages should not be put in restricted mode and cache
+ // the result in UBMS to be used later when the apps are started for backup.
+ setNoRestrictedModePackages(transport, mPackages);
+
// Set up to send data to the transport
final int N = mPackages.size();
int chunkSizeInBytes = 8 * 1024; // 8KB
@@ -694,6 +701,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
mUserBackupManagerService.scheduleNextFullBackupJob(backoff);
}
+ // Clear this to avoid using the memory until reboot.
+ mUserBackupManagerService
+ .getBackupAgentConnectionManager().clearNoRestrictedModePackages();
+
Slog.i(TAG, "Full data backup pass finished.");
mUserBackupManagerService.getWakelock().release();
}
@@ -722,6 +733,22 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
}
}
+ private void setNoRestrictedModePackages(BackupTransportClient transport,
+ List<PackageInfo> packages) {
+ try {
+ Set<String> packageNames = new ArraySet<>();
+ for (int i = 0; i < packages.size(); i++) {
+ packageNames.add(packages.get(i).packageName);
+ }
+ packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames,
+ BACKUP);
+ mUserBackupManagerService.getBackupAgentConnectionManager().setNoRestrictedModePackages(
+ packageNames, BACKUP);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to retrieve no restricted mode packages from transport");
+ }
+ }
+
// Run the backup and pipe it back to the given socket -- expects to run on
// a standalone thread. The runner owns this half of the pipe, and closes
// it to indicate EOD to the other end.
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 3a6e1cafa505..82232a653858 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -741,7 +741,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
final IBackupAgent agent;
try {
agent =
- mBackupManagerService.bindToAgentSynchronous(
+ mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL,
mBackupEligibilityRules.getBackupDestination());
if (agent == null) {
@@ -1302,7 +1302,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
// For PM metadata (for which applicationInfo is null) there is no agent-bound state.
if (mCurrentPackage.applicationInfo != null) {
- mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo);
+ mBackupManagerService.getBackupAgentConnectionManager().unbindAgent(
+ mCurrentPackage.applicationInfo);
}
mAgent = null;
}
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 2d99c96452da..b59e860f81fe 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -410,11 +410,7 @@ public class FullRestoreEngine extends RestoreEngine {
// All set; now set up the IPC and launch the agent
setUpPipes();
- mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp,
- FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
- ? ApplicationThreadConstants.BACKUP_MODE_RESTORE
- : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL,
- mBackupEligibilityRules.getBackupDestination());
+ mAgent = bindToAgent(info);
mAgentPackage = pkg;
} catch (IOException | NameNotFoundException e) {
// fall through to error handling
@@ -805,15 +801,12 @@ public class FullRestoreEngine extends RestoreEngine {
return packages.contains(packageName);
}
- void sendOnRestorePackage(String name) {
- if (mObserver != null) {
- try {
- // TODO: use a more user-friendly name string
- mObserver.onRestorePackage(name);
- } catch (RemoteException e) {
- Slog.w(TAG, "full restore observer went away: restorePackage");
- mObserver = null;
- }
- }
+ private IBackupAgent bindToAgent(FileMetadata info) {
+ return mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
+ mTargetApp,
+ FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
+ ? ApplicationThreadConstants.BACKUP_MODE_RESTORE
+ : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL,
+ mBackupEligibilityRules.getBackupDestination());
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index e536876f6cc3..e5c7e5cce757 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -53,6 +53,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.Slog;
@@ -482,6 +483,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
return;
}
+ // We ask the transport which packages should not be put in restricted mode and cache
+ // the result in UBMS to be used later when the apps are started for restore.
+ setNoRestrictedModePackages(transport, packages);
+
RestoreDescription desc = transport.nextRestorePackage();
if (desc == null) {
Slog.e(TAG, "No restore metadata available; halting");
@@ -809,7 +814,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Good to go! Set up and bind the agent...
mAgent =
- backupManagerService.bindToAgentSynchronous(
+ backupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
mCurrentPackage.applicationInfo,
ApplicationThreadConstants.BACKUP_MODE_RESTORE,
mBackupEligibilityRules.getBackupDestination());
@@ -1358,6 +1363,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Clear any ongoing session timeout.
backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
+ // Clear this to avoid using the memory until reboot.
+ backupManagerService.getBackupAgentConnectionManager().clearNoRestrictedModePackages();
+
// If we have a PM token, we must under all circumstances be sure to
// handshake when we've finished.
if (mPmToken > 0) {
@@ -1819,4 +1827,21 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
return packageInfo;
}
+
+ @VisibleForTesting
+ void setNoRestrictedModePackages(BackupTransportClient transport,
+ PackageInfo[] packages) {
+ try {
+ Set<String> packageNames = new ArraySet<>();
+ for (int i = 0; i < packages.length; i++) {
+ packageNames.add(packages[i].packageName);
+ }
+ packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames,
+ RESTORE);
+ backupManagerService.getBackupAgentConnectionManager().setNoRestrictedModePackages(
+ packageNames, RESTORE);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to retrieve restricted mode packages from transport");
+ }
+ }
}
diff --git a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
index daf3415229ea..373811fef802 100644
--- a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
@@ -17,6 +17,7 @@
package com.android.server.backup.transport;
import android.annotation.Nullable;
+import android.app.backup.BackupAnnotations;
import android.app.backup.BackupTransport;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.RestoreDescription;
@@ -26,6 +27,7 @@ import android.content.pm.PackageInfo;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.backup.IBackupTransport;
@@ -375,6 +377,26 @@ public class BackupTransportClient {
}
/**
+ * See
+ * {@link IBackupTransport#getPackagesThatShouldNotUseRestrictedMode(List, int, AndroidFuture)}.
+ */
+ public Set<String> getPackagesThatShouldNotUseRestrictedMode(Set<String> packageNames,
+ @BackupAnnotations.OperationType
+ int operationType) throws RemoteException {
+ AndroidFuture<List<String>> resultFuture = mTransportFutures.newFuture();
+ mTransportBinder.getPackagesThatShouldNotUseRestrictedMode(List.copyOf(packageNames),
+ operationType,
+ resultFuture);
+ List<String> resultList = getFutureResult(resultFuture);
+ Set<String> set = new ArraySet<>();
+ if (resultList == null) {
+ return set;
+ }
+ set.addAll(resultList);
+ return set;
+ }
+
+ /**
* Allows the {@link TransportConnection} to notify this client
* if the underlying transport has become unusable. If that happens
* we want to cancel all active futures or callbacks.
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index dbeca82ade89..2d3782fb3181 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -16,6 +16,8 @@
package com.android.server.companion.securechannel;
+import static android.security.attestationverification.AttestationVerificationManager.FLAG_FAILURE_UNKNOWN;
+
import android.annotation.NonNull;
import android.content.Context;
import android.os.Build;
@@ -67,7 +69,7 @@ public class SecureChannel {
private D2DConnectionContextV1 mConnectionContext;
private String mAlias;
- private int mVerificationResult;
+ private int mVerificationResult = FLAG_FAILURE_UNKNOWN;
private boolean mPskVerified;
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 8b5b93e96494..d4beb019e049 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -44,7 +44,6 @@ import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.app.compat.CompatChanges;
import android.companion.AssociationInfo;
-import android.companion.AssociationRequest;
import android.companion.virtual.ActivityPolicyExemption;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
@@ -156,9 +155,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private static final String PERSISTENT_ID_PREFIX_CDM_ASSOCIATION = "companion:";
- private static final List<String> DEVICE_PROFILES_ALLOWING_MIRROR_DISPLAYS = List.of(
- AssociationRequest.DEVICE_PROFILE_APP_STREAMING);
-
/**
* Timeout until {@link #launchPendingIntent} stops waiting for an activity to be launched.
*/
@@ -1352,11 +1348,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return hasCustomAudioInputSupportInternal();
}
- @Override
- public boolean canCreateMirrorDisplays() {
- return DEVICE_PROFILES_ALLOWING_MIRROR_DISPLAYS.contains(getDeviceProfile());
- }
-
private boolean hasCustomAudioInputSupportInternal() {
if (!Flags.vdmPublicApis()) {
return false;
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 485bf31dfb64..aabbd3bf49ae 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -65,6 +65,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -347,7 +348,8 @@ public class BinaryTransparencyService extends SystemService {
+ " packages after considering preloads");
}
- if (CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
+ if (!android.app.Flags.backgroundInstallControlCallbackApi()
+ && CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
// lastly measure all newly installed MBAs
List<IBinaryTransparencyService.AppInfo> allMbaInfo =
collectAllSilentInstalledMbaInfo(packagesMeasured);
@@ -1158,6 +1160,49 @@ public class BinaryTransparencyService extends SystemService {
}
/**
+ * Receive callbacks from BIC to write silently installed apps to log
+ *
+ * TODO: Add a host test for testing registration and callback of BicCallbackHandler
+ * b/380002484
+ */
+ static class BicCallbackHandler extends IRemoteCallback.Stub {
+ private static final String BIC_CALLBACK_HANDLER_TAG =
+ "BTS.BicCallbackHandler";
+ private final BinaryTransparencyServiceImpl mServiceImpl;
+ static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
+
+ BicCallbackHandler(BinaryTransparencyServiceImpl impl) {
+ mServiceImpl = impl;
+ }
+
+ @Override
+ public void sendResult(Bundle data) {
+ String packageName = data.getString(FLAGGED_PACKAGE_NAME_KEY);
+ if (packageName == null) return;
+ if (DEBUG) {
+ Slog.d(BIC_CALLBACK_HANDLER_TAG, "background install event detected for "
+ + packageName);
+ }
+
+ PackageState packageState = LocalServices.getService(PackageManagerInternal.class)
+ .getPackageStateInternal(packageName);
+ if (packageState == null) {
+ Slog.w(TAG, "Package state is unavailable, ignoring the package "
+ + packageName);
+ return;
+ }
+ if (packageState.isUpdatedSystemApp()) {
+ return;
+ }
+ List<IBinaryTransparencyService.AppInfo> mbaInfo = mServiceImpl.collectAppInfo(
+ packageState, MBA_STATUS_NEW_INSTALL);
+ for (IBinaryTransparencyService.AppInfo appInfo : mbaInfo) {
+ mServiceImpl.writeAppInfoToLog(appInfo);
+ }
+ }
+ };
+
+ /**
* Called when the system service should publish a binder service using
* {@link #publishBinderService(String, IBinder).}
*/
@@ -1534,6 +1579,19 @@ public class BinaryTransparencyService extends SystemService {
}
}
+ private void registerBicCallback() {
+ IBackgroundInstallControlService iBics =
+ IBackgroundInstallControlService.Stub.asInterface(
+ ServiceManager.getService(
+ Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
+ try {
+ iBics.registerBackgroundInstallCallback(
+ new BicCallbackHandler(mServiceImpl));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register BackgroundInstallControl callback.");
+ }
+ }
+
private boolean isPackagePreloaded(String packageName) {
PackageManager pm = mContext.getPackageManager();
try {
@@ -1596,6 +1654,10 @@ public class BinaryTransparencyService extends SystemService {
private void registerAllPackageUpdateObservers() {
registerApkAndNonStagedApexUpdateListener();
registerStagedApexUpdateObserver();
+ if (android.app.Flags.backgroundInstallControlCallbackApi()
+ && CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
+ registerBicCallback();
+ }
}
private String translateContentDigestAlgorithmIdToString(int algorithmId) {
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 99772c39bef1..03d6c8b695a0 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -1318,6 +1318,7 @@ public class SystemConfig {
}
XmlUtils.skipCurrentTag(parser);
} break;
+ case "disabled-in-sku":
case "disabled-until-used-preinstalled-carrier-app": {
if (allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
@@ -1334,6 +1335,24 @@ public class SystemConfig {
}
XmlUtils.skipCurrentTag(parser);
} break;
+ case "enabled-in-sku-override": {
+ if (allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG,
+ "<" + name + "> without "
+ + "package in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else if (!mDisabledUntilUsedPreinstalledCarrierApps.remove(pkgname)) {
+ Slog.w(TAG,
+ "<" + name + "> packagename:" + pkgname + " not included"
+ + "in disabled-in-sku");
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
case "privapp-permissions": {
if (allowPrivappPermissions) {
// privapp permissions from system, apex, vendor, product and
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fa228627c255..e57b00944f7c 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -65,6 +65,7 @@ import android.telephony.CellSignalStrengthLte;
import android.telephony.CellSignalStrengthNr;
import android.telephony.CellSignalStrengthTdscdma;
import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.CellularIdentifierDisclosure;
import android.telephony.DisconnectCause;
import android.telephony.LinkCapacityEstimate;
import android.telephony.LocationAccessPolicy;
@@ -76,6 +77,7 @@ import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.PreciseDisconnectCause;
import android.telephony.Rlog;
+import android.telephony.SecurityAlgorithmUpdate;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
@@ -590,7 +592,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
|| events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)
|| events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)
|| events.contains(TelephonyCallback
- .EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED);
+ .EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED);
}
private static final int MSG_USER_SWITCHED = 1;
@@ -897,7 +901,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mIsSatelliteEnabled = new AtomicBoolean();
mWasSatelliteEnabledNotified = new AtomicBoolean();
-
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -3825,7 +3828,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
-
/**
* Notify external listeners that carrier roaming non-terrestrial network
* signal strength changed.
@@ -3835,7 +3837,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
public void notifyCarrierRoamingNtnSignalStrengthChanged(int subId,
@NonNull NtnSignalStrength ntnSignalStrength) {
if (!checkNotifyPermission("notifyCarrierRoamingNtnSignalStrengthChanged")) {
- log("nnotifyCarrierRoamingNtnSignalStrengthChanged: caller does not have required "
+ log("notifyCarrierRoamingNtnSignalStrengthChanged: caller does not have required "
+ "permissions.");
return;
}
@@ -3863,6 +3865,98 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ /**
+ * Notify that the radio security algorithms have changed.
+ *
+ * @param phoneId the phone id.
+ * @param subId the subId.
+ * @param update the security algorithm update.
+ */
+ public void notifySecurityAlgorithmsChanged(int phoneId, int subId,
+ SecurityAlgorithmUpdate update) {
+ if (!Flags.securityAlgorithmsUpdateIndications()) {
+ log("Not available due to securityAlgorithmsUpdateIndications() flag");
+ return;
+ }
+ if (!checkNotifyPermission("notifySecurityAlgorithmChanged()")) {
+ return;
+ }
+
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ if (update == null) {
+ loge("SecurityAlgorithmUpdate is null, subId=" + subId
+ + ", phoneId=" + phoneId);
+ // Listeners shouldn't be updated for null updates.
+ return;
+ }
+
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+ try {
+ if (VDBG) {
+ log("notifySecurityAlgorithmsChanged: securityAlgorithmUpdate= "
+ + update);
+ }
+ r.callback.onSecurityAlgorithmsChanged(update);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
+ /**
+ * Notify of a cellular identifier disclosure.
+ *
+ * @param phoneId the phone id.
+ * @param subId the subId.
+ * @param disclosure the cellular identifier disclosure.
+ */
+ public void notifyCellularIdentifierDisclosedChanged(int phoneId, int subId,
+ @NonNull CellularIdentifierDisclosure disclosure) {
+ if (!Flags.cellularIdentifierDisclosureIndications()) {
+ log("Not available due to cellularIdentifierDisclosureIndications() flag");
+ return;
+ }
+ if (!checkNotifyPermission("notifyCellularIdentifierDisclosedChanged()")) {
+ return;
+ }
+
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ if (disclosure == null) {
+ loge("CellularIdentifierDisclosure is null, subId=" + subId
+ + ", phoneId=" + phoneId);
+ // Listeners shouldn't be updated for null disclosures.
+ return;
+ }
+
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+ try {
+ if (VDBG) {
+ log("notifyCellularIdentifierDisclosedChanged: disclosure= "
+ + disclosure);
+ }
+ r.callback.onCellularIdentifierDisclosedChanged(disclosure);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 06e6c8b1ec53..2012f5632a64 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -48,7 +48,6 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
-import android.net.vcn.Flags;
import android.net.vcn.IVcnManagementService;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -890,20 +889,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
while (configsIterator.hasNext()) {
final ParcelUuid subGrp = configsIterator.next();
- if (Flags.fixConfigGarbageCollection()) {
- if (!subGroups.contains(subGrp)) {
- // Trim subGrps with no more subscriptions; must have moved to another subGrp
- logDbg("Garbage collect VcnConfig for group=" + subGrp);
- configsIterator.remove();
- shouldWrite = true;
- }
- } else {
- final List<SubscriptionInfo> subscriptions = subMgr.getSubscriptionsInGroup(subGrp);
- if (subscriptions == null || subscriptions.isEmpty()) {
- // Trim subGrps with no more subscriptions; must have moved to another subGrp
- configsIterator.remove();
- shouldWrite = true;
- }
+ if (!subGroups.contains(subGrp)) {
+ // Trim subGrps with no more subscriptions; must have moved to another subGrp
+ logDbg("Garbage collect VcnConfig for group=" + subGrp);
+ configsIterator.remove();
+ shouldWrite = true;
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 679c7ac3ceac..3ce645158fe4 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -16,6 +16,10 @@
package com.android.server.accounts;
+import static android.Manifest.permission.COPY_ACCOUNTS;
+import static android.Manifest.permission.REMOVE_ACCOUNTS;
+import static android.app.admin.flags.Flags.splitCreateManagedProfileEnabled;
+
import android.Manifest;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
@@ -1739,9 +1743,11 @@ public class AccountManagerService
public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
final int userFrom, int userTo) {
int callingUid = Binder.getCallingUid();
- if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
+ if (isCrossUser(callingUid, UserHandle.USER_ALL)
+ && !hasCopyAccountsPermission()) {
throw new SecurityException("Calling copyAccountToUser requires "
- + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
+ + " or " + COPY_ACCOUNTS);
}
final UserAccounts fromAccounts = getUserAccounts(userFrom);
final UserAccounts toAccounts = getUserAccounts(userTo);
@@ -1793,6 +1799,12 @@ public class AccountManagerService
}
}
+ private boolean hasCopyAccountsPermission() {
+ return splitCreateManagedProfileEnabled()
+ && mContext.checkCallingOrSelfPermission(COPY_ACCOUNTS)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
@Override
public boolean accountAuthenticated(final Account account) {
final int callingUid = Binder.getCallingUid();
@@ -2346,7 +2358,8 @@ public class AccountManagerService
UserHandle user = UserHandle.of(userId);
if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
&& !isSystemUid(callingUid)
- && !isProfileOwner(callingUid)) {
+ && !isProfileOwner(callingUid)
+ && !hasRemoveAccountsPermission()) {
String msg = String.format(
"uid %s cannot remove accounts of type: %s",
callingUid,
@@ -2408,6 +2421,12 @@ public class AccountManagerService
}
}
+ private boolean hasRemoveAccountsPermission() {
+ return splitCreateManagedProfileEnabled()
+ && mContext.checkCallingOrSelfPermission(REMOVE_ACCOUNTS)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
@Override
public boolean removeAccountExplicitly(Account account) {
final int callingUid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3f540ad43da1..71cbc10074d6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -115,6 +115,7 @@ import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_
import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM;
import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__BIND;
import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__START;
+import static com.android.media.flags.Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
@@ -9318,6 +9319,86 @@ public final class ActiveServices {
Slog.e(TAG, "stopForegroundServiceDelegateLocked delegate does not exist");
}
}
+ /**
+ * Handles notifications from MediaSessionService about active media service.
+ * This method evaluates the provided information and transitions corresponding service to
+ * foreground state.
+ *
+ * @param packageName The package name of the app running the service.
+ * @param userId The user ID associated with the service.
+ * @param notificationId The ID of the media notification associated with the service.
+ */
+ void notifyActiveMediaForegroundServiceLocked(@NonNull String packageName,
+ @UserIdInt int userId, int notificationId) {
+ if (!enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ return;
+ }
+
+ final ServiceMap smap = mServiceMap.get(userId);
+ if (smap == null) {
+ return;
+ }
+ final int serviceSize = smap.mServicesByInstanceName.size();
+ for (int i = 0; i < serviceSize; i++) {
+ final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
+ if (sr.appInfo.packageName.equals(packageName) && !sr.isForeground) {
+ // foregroundServiceType is cleared when media session is user-disengaged
+ // and calls notifyInactiveMediaForegroundService->setServiceForegroundInnerLocked.
+ if (sr.foregroundServiceType
+ == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
+ && sr.foregroundId == notificationId) {
+ if (DEBUG_FOREGROUND_SERVICE) {
+ Slog.d(TAG, "Moving media service to foreground for package "
+ + packageName);
+ }
+ setServiceForegroundInnerLocked(sr, sr.foregroundId,
+ sr.foregroundNoti, /* flags */ 0,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
+ /* callingUidStart */ 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles notifications from MediaSessionService about inactive media foreground services.
+ * This method evaluates the provided information and determines whether to stop the
+ * corresponding foreground service.
+ *
+ * @param packageName The package name of the app running the foreground service.
+ * @param userId The user ID associated with the foreground service.
+ * @param notificationId The ID of the media notification associated with the foreground
+ * service.
+ */
+ void notifyInactiveMediaForegroundServiceLocked(@NonNull String packageName,
+ @UserIdInt int userId, int notificationId) {
+ if (!enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ return;
+ }
+
+ final ServiceMap smap = mServiceMap.get(userId);
+ if (smap == null) {
+ return;
+ }
+ final int serviceSize = smap.mServicesByInstanceName.size();
+ for (int i = 0; i < serviceSize; i++) {
+ final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
+ if (sr.appInfo.packageName.equals(packageName) && sr.isForeground) {
+ if (sr.foregroundServiceType
+ == ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
+ && sr.foregroundId == notificationId) {
+ if (DEBUG_FOREGROUND_SERVICE) {
+ Slog.d(TAG, "Forcing media foreground service to background for package "
+ + packageName);
+ }
+ setServiceForegroundInnerLocked(sr, /* id */ 0,
+ /* notification */ null, /* flags */ 0,
+ /* foregroundServiceType */ 0, /* callingUidStart */ 0);
+ }
+ }
+ }
+ }
+
private static void getClientPackages(ServiceRecord sr, ArraySet<String> output) {
var connections = sr.getConnections();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cb89f2895902..053ec824e1a7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -131,6 +131,9 @@ import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.security.Flags.preventIntentRedirect;
+import static android.security.Flags.preventIntentRedirectCollectNestedKeysOnServerIfNotCollected;
+import static android.security.Flags.preventIntentRedirectShowToast;
+import static android.security.Flags.preventIntentRedirectThrowExceptionIfNestedKeysNotCollected;
import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
import static android.view.Display.INVALID_DISPLAY;
@@ -387,6 +390,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.autofill.AutofillManagerInternal;
+import android.widget.Toast;
import com.android.internal.annotations.CompositeRWLock;
import com.android.internal.annotations.GuardedBy;
@@ -437,6 +441,7 @@ import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.ThreadPriorityBooster;
+import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.appop.AppOpsService;
@@ -668,6 +673,8 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
private static final boolean ENABLE_PROC_LOCK = true;
+ private static final int DEFAULT_INTENT_CREATOR_UID = -1;
+
/**
* The lock for process management.
*
@@ -4491,16 +4498,11 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.w(TAG, "Unattached app died before backup, skipping");
final int userId = app.userId;
final String packageName = app.info.packageName;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnectedForUser(userId, packageName);
- } catch (RemoteException e) {
- // Can't happen; the backup manager is local
- }
+ mHandler.post(() -> {
+ try {
+ getBackupManager().agentDisconnectedForUser(userId, packageName);
+ } catch (RemoteException e) {
+ // Can't happen; the backup manager is local
}
});
}
@@ -4671,7 +4673,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
&& ((backupTarget.backupMode == BackupRecord.RESTORE_FULL)
- || (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
+ || (backupTarget.backupMode == BackupRecord.BACKUP_FULL))
+ && backupTarget.useRestrictedMode;
}
final ActiveInstrumentation instr = app.getActiveInstrumentation();
@@ -13497,16 +13500,11 @@ public class ActivityManagerService extends IActivityManager.Stub
if (backupTarget != null && pid == backupTarget.app.getPid()) {
if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
+ backupTarget.appInfo + " died during backup");
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnectedForUser(app.userId, app.info.packageName);
- } catch (RemoteException e) {
- // can't happen; backup manager is local
- }
+ mHandler.post(() -> {
+ try {
+ getBackupManager().agentDisconnectedForUser(app.userId, app.info.packageName);
+ } catch (RemoteException e) {
+ // can't happen; backup manager is local
}
});
}
@@ -14009,7 +14007,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId,
- @BackupDestination int backupDestination) {
+ @BackupDestination int backupDestination, boolean useRestrictedMode) {
long startTimeNs = SystemClock.uptimeNanos();
if (DEBUG_BACKUP) {
Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode
@@ -14094,7 +14092,8 @@ public class ActivityManagerService extends IActivityManager.Stub
+ app.packageName + ": " + e);
}
- BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination);
+ BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination,
+ useRestrictedMode);
ComponentName hostingName =
(backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
|| backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE)
@@ -14120,8 +14119,9 @@ public class ActivityManagerService extends IActivityManager.Stub
// process, etc, then mark it as being in full backup so that certain calls to the
// process can be blocked. This is not reset to false anywhere because we kill the
// process after the full backup is done and the ProcessRecord will vaporize anyway.
- if (UserHandle.isApp(app.uid) &&
- backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL) {
+ if (UserHandle.isApp(app.uid)
+ && backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL
+ && r.useRestrictedMode) {
proc.setInFullBackup(true);
}
r.app = proc;
@@ -14219,9 +14219,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final long oldIdent = Binder.clearCallingIdentity();
try {
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentConnectedForUser(userId, agentPackageName, agent);
+ getBackupManager().agentConnectedForUser(userId, agentPackageName, agent);
} catch (RemoteException e) {
// can't happen; the backup manager service is local
} catch (Exception e) {
@@ -17931,6 +17929,24 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public void notifyActiveMediaForegroundService(@NonNull String packageName,
+ @UserIdInt int userId, int notificationId) {
+ synchronized (ActivityManagerService.this) {
+ mServices.notifyActiveMediaForegroundServiceLocked(packageName, userId,
+ notificationId);
+ }
+ }
+
+ @Override
+ public void notifyInactiveMediaForegroundService(@NonNull String packageName,
+ @UserIdInt int userId, int notificationId) {
+ synchronized (ActivityManagerService.this) {
+ mServices.notifyInactiveMediaForegroundServiceLocked(packageName, userId,
+ notificationId);
+ }
+ }
+
+ @Override
public ArraySet<String> getClientPackages(String servicePackageName) {
synchronized (ActivityManagerService.this) {
return mServices.getClientPackagesLocked(servicePackageName);
@@ -18011,14 +18027,6 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void addStartInfoTimestamp(int key, long timestampNs, int uid, int pid,
int userId) {
- // For the simplification, we don't support USER_ALL nor USER_CURRENT here.
- if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_CURRENT) {
- throw new IllegalArgumentException("Unsupported userId");
- }
-
- mUserController.handleIncomingUser(pid, uid, userId, true,
- ALLOW_NON_FULL, "addStartInfoTimestampSystem", null);
-
addStartInfoTimestampInternal(key, timestampNs, userId, uid);
}
@@ -19086,8 +19094,13 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
@Override
public boolean enableFgsNotificationRateLimit(boolean enable) {
- enforceCallingPermission(permission.WRITE_DEVICE_CONFIG,
- "enableFgsNotificationRateLimit");
+ if (android.security.Flags.protectDeviceConfigFlags()) {
+ enforceCallingHasAtLeastOnePermission("enableFgsNotificationRateLimit",
+ permission.WRITE_DEVICE_CONFIG, permission.WRITE_ALLOWLISTED_DEVICE_CONFIG);
+ } else {
+ enforceCallingPermission(permission.WRITE_DEVICE_CONFIG,
+ "enableFgsNotificationRateLimit");
+ }
synchronized (this) {
return mServices.enableFgsNotificationRateLimitLocked(enable);
}
@@ -19306,24 +19319,61 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
public void addCreatorToken(@Nullable Intent intent, String creatorPackage) {
if (!preventIntentRedirect()) return;
-
if (intent == null) return;
+
+ if ((intent.getExtendedFlags() & Intent.EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED) == 0) {
+ Slog.wtf(TAG,
+ "[IntentRedirect] The intent does not have its nested keys collected as a "
+ + "preparation for creating intent creator tokens. Intent: "
+ + intent + "; creatorPackage: " + creatorPackage);
+ if (preventIntentRedirectShowToast()) {
+ UiThread.getHandler().post(
+ () -> Toast.makeText(mContext,
+ "Nested keys not collected. go/report-bug-intentRedir to report a"
+ + " bug", Toast.LENGTH_LONG).show());
+ }
+ if (preventIntentRedirectThrowExceptionIfNestedKeysNotCollected()) {
+ // this flag will be internal only, not ramped to public.
+ throw new SecurityException(
+ "The intent does not have its nested keys collected as a preparation for "
+ + "creating intent creator tokens. Intent: "
+ + intent + "; creatorPackage: " + creatorPackage);
+ }
+ if (preventIntentRedirectCollectNestedKeysOnServerIfNotCollected()) {
+ // this flag will be ramped to public.
+ intent.collectExtraIntentKeys();
+ }
+ }
+
+ String targetPackage = intent.getComponent() != null
+ ? intent.getComponent().getPackageName()
+ : intent.getPackage();
+ final boolean isCreatorSameAsTarget = creatorPackage != null && creatorPackage.equals(
+ targetPackage);
+ final boolean noExtraIntentKeys =
+ intent.getExtraIntentKeys() == null || intent.getExtraIntentKeys().isEmpty();
+ final int creatorUid = noExtraIntentKeys ? DEFAULT_INTENT_CREATOR_UID : Binder.getCallingUid();
+
intent.forEachNestedCreatorToken(extraIntent -> {
- IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent, creatorPackage);
+ if (isCreatorSameAsTarget) {
+ FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, true);
+ return;
+ }
+ IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent, creatorUid,
+ creatorPackage);
if (creatorToken != null) {
extraIntent.setCreatorToken(creatorToken);
// TODO remove Slog.wtf once proven FrameworkStatsLog works. b/375396329
Slog.wtf(TAG, "A creator token is added to an intent. creatorPackage: "
+ creatorPackage + "; intent: " + extraIntent);
- FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED,
- creatorToken.getCreatorUid());
+ FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, false);
}
});
}
- private IntentCreatorToken createIntentCreatorToken(Intent intent, String creatorPackage) {
+ private IntentCreatorToken createIntentCreatorToken(Intent intent, int creatorUid,
+ String creatorPackage) {
if (IntentCreatorToken.isValid(intent)) return null;
- int creatorUid = getCallingUid();
IntentCreatorToken.Key key = new IntentCreatorToken.Key(creatorUid, creatorPackage, intent);
IntentCreatorToken token;
synchronized (sIntentCreatorTokenCache) {
@@ -19337,4 +19387,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
return token;
}
+
+ private IBackupManager getBackupManager() {
+ return IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 02e2c391bb27..fa40283d43e1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -39,6 +39,8 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRI
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+import static com.android.media.flags.Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange;
+import static com.android.media.flags.Flags.FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE;
import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -445,6 +447,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
return runCapabilities(pw);
case "set-app-zygote-preload-timeout":
return runSetAppZygotePreloadTimeout(pw);
+ case "set-media-foreground-service":
+ return runSetMediaForegroundService(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -454,6 +458,53 @@ final class ActivityManagerShellCommand extends ShellCommand {
return -1;
}
+ int runSetMediaForegroundService(PrintWriter pw) throws RemoteException {
+ mInternal.enforceCallingPermission(
+ android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE,
+ "runSetMediaForegroundService()");
+ final PrintWriter err = getErrPrintWriter();
+ if (!enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ err.println("Error: flag "
+ + FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE
+ + " not enabled");
+ return -1;
+ }
+ int userId = UserHandle.USER_CURRENT;
+ final String cmd = getNextArgRequired();
+ if ("inactive".equals(cmd) || "active".equals(cmd)) {
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ if (userId == UserHandle.USER_ALL) {
+ err.println(
+ "Error: Can't set media fgs with user 'all'");
+ return -1;
+ }
+ } else {
+ err.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ final String pkgName = getNextArgRequired();
+ final int notificationId = Integer.parseInt(getNextArgRequired());
+ if (notificationId == 0) {
+ err.println("Error: notification id cannot be zero");
+ return -1;
+ }
+ if ("inactive".equals(cmd)) {
+ mInternal.mInternal.notifyInactiveMediaForegroundService(pkgName,
+ userId, notificationId);
+ } else {
+ mInternal.mInternal.notifyActiveMediaForegroundService(pkgName,
+ userId, notificationId);
+ }
+ return 0;
+ }
+ err.println("Error: Unknown set-media-foreground-service command: " + cmd);
+ return -1;
+ }
+
int runSetAppZygotePreloadTimeout(PrintWriter pw) throws RemoteException {
final String timeout = getNextArgRequired();
final int timeoutMs = Integer.parseInt(timeout);
@@ -4637,6 +4688,9 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" --protobuf: format output using protobuffer");
pw.println(" set-app-zygote-preload-timeout <TIMEOUT_IN_MS>");
pw.println(" Set the timeout for preloading code in the app-zygote");
+ pw.println(" set-media-foreground-service inactive|active [--user USER_ID] <PACKAGE>"
+ + " <NOTIFICATION_ID>");
+ pw.println(" Set an app's media service inactive or active.");
Intent.printIntentArgsHelp(pw, "");
}
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 415f78aa3ee5..b7a5f3e4099a 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -598,7 +598,7 @@ class AppErrors {
}
if (r != null) {
- mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
+ mPackageWatchdog.notifyPackageFailure(r.getPackageListWithVersionCode(),
PackageWatchdog.FAILURE_REASON_APP_CRASH);
synchronized (mService) {
@@ -1142,7 +1142,7 @@ class AppErrors {
}
// Notify PackageWatchdog without the lock held
if (packageList != null) {
- mPackageWatchdog.onPackageFailure(packageList,
+ mPackageWatchdog.notifyPackageFailure(packageList,
PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
}
}
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 3913d2f2ea92..961022b7231b 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -634,12 +634,20 @@ public final class AppStartInfoTracker {
}
final ApplicationStartInfo info = new ApplicationStartInfo(raw);
+ int uid = raw.getRealUid();
- AppStartInfoContainer container = mData.get(raw.getPackageName(), raw.getRealUid());
+ // Isolated process starts won't be reasonably accessible if stored by their uid, don't
+ // store them.
+ if (com.android.server.am.Flags.appStartInfoIsolatedProcess()
+ && UserHandle.isIsolated(uid)) {
+ return null;
+ }
+
+ AppStartInfoContainer container = mData.get(raw.getPackageName(), uid);
if (container == null) {
container = new AppStartInfoContainer(mAppStartInfoHistoryListSize);
- container.mUid = info.getRealUid();
- mData.put(raw.getPackageName(), raw.getRealUid(), container);
+ container.mUid = uid;
+ mData.put(raw.getPackageName(), uid, container);
}
container.addStartInfoLocked(info);
@@ -1010,6 +1018,17 @@ public final class AppStartInfoTracker {
new AppStartInfoContainer(mAppStartInfoHistoryListSize);
int uid = container.readFromProto(proto, AppsStartInfoProto.Package.USERS,
pkgName);
+
+ // If the isolated process flag is enabled and the uid is that of an isolated
+ // process, then break early so that the container will not be added to mData.
+ // This is expected only as a one time mitigation, records added after this flag
+ // is enabled should always return false for isIsolated and thereby always
+ // continue on.
+ if (com.android.server.am.Flags.appStartInfoIsolatedProcess()
+ && UserHandle.isIsolated(uid)) {
+ break;
+ }
+
synchronized (mLock) {
mData.put(pkgName, uid, container);
}
diff --git a/services/core/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java
index 0b056d7883bf..64cc6f0e66e3 100644
--- a/services/core/java/com/android/server/am/BackupRecord.java
+++ b/services/core/java/com/android/server/am/BackupRecord.java
@@ -32,15 +32,18 @@ final class BackupRecord {
final int userId; // user for which backup is performed
final int backupMode; // full backup / incremental / restore
@BackupDestination final int backupDestination; // see BackupAnnotations#BackupDestination
+ final boolean useRestrictedMode; // whether the app should be put into restricted backup mode
ProcessRecord app; // where this agent is running or null
// ----- Implementation -----
- BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _backupDestination) {
+ BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _backupDestination,
+ boolean _useRestrictedMode) {
appInfo = _appInfo;
backupMode = _backupMode;
userId = _userId;
backupDestination = _backupDestination;
+ useRestrictedMode = _useRestrictedMode;
}
public String toString() {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2eb9f3cb600f..d5bd05764f38 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1262,6 +1262,17 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mFrameworkStatsLogger = frameworkStatsLogger;
}
+ private static float clampPowerMah(double powerMah, String consumer) {
+ float resultPowerMah = 0;
+ if (powerMah <= Float.MAX_VALUE && powerMah >= Float.MIN_VALUE) {
+ resultPowerMah = (float) powerMah;
+ } else {
+ // Handle overflow appropriately
+ Slog.wtfStack(TAG, consumer + " reported powerMah float overflow: " + powerMah);
+ }
+ return resultPowerMah;
+ }
+
/**
* Generates StatsEvents for the supplied battery usage stats and adds them to
* the supplied list.
@@ -1282,7 +1293,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
bus.getAggregateBatteryConsumer(
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
- final float totalDeviceConsumedPowerMah = (float) deviceConsumer.getConsumedPower();
+ final float totalDeviceConsumedPowerMah =
+ clampPowerMah(deviceConsumer.getConsumedPower(), "AggregateBatteryConsumer");
for (@BatteryConsumer.PowerComponentId int powerComponentId :
deviceConsumer.getPowerComponentIds()) {
@@ -1314,7 +1326,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
// Log single atom for BatteryUsageStats per uid/process_state/component/etc.
for (UidBatteryConsumer uidConsumer : uidConsumers) {
final int uid = uidConsumer.getUid();
- final float totalConsumedPowerMah = (float) uidConsumer.getConsumedPower();
+
+ final float totalConsumedPowerMah =
+ clampPowerMah(uidConsumer.getConsumedPower(), "uidConsumer-" + uid);
for (@BatteryConsumer.PowerComponentId int powerComponentId :
uidConsumer.getPowerComponentIds()) {
@@ -1358,7 +1372,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
final String powerComponentName = batteryConsumer.getPowerComponentName(componentId);
- final float powerMah = (float) batteryConsumer.getConsumedPower(key);
+ final double consumedPowerMah = batteryConsumer.getConsumedPower(key);
+ float powerMah =
+ clampPowerMah(
+ consumedPowerMah, "uidConsumer-" + uid + "-" + powerComponentName);
final long powerComponentDurationMillis = batteryConsumer.getUsageDurationMillis(key);
if (powerMah == 0 && powerComponentDurationMillis == 0) {
diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java
index 8a128582c507..c6cb67f4efa8 100644
--- a/services/core/java/com/android/server/am/BroadcastController.java
+++ b/services/core/java/com/android/server/am/BroadcastController.java
@@ -57,7 +57,6 @@ import android.app.ApplicationExitInfo;
import android.app.ApplicationThreadConstants;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
-import android.app.BroadcastStickyCache;
import android.app.IApplicationThread;
import android.app.compat.CompatChanges;
import android.appwidget.AppWidgetManager;
@@ -554,7 +553,7 @@ class BroadcastController {
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
- exported, mService.mPlatformCompat);
+ exported, callerApp.info, mService.mPlatformCompat);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
@@ -702,7 +701,6 @@ class BroadcastController {
boolean serialized, boolean sticky, int userId) {
mService.enforceNotIsolatedCaller("broadcastIntent");
- int result;
synchronized (mService) {
intent = verifyBroadcastLocked(intent);
@@ -724,7 +722,7 @@ class BroadcastController {
final long origId = Binder.clearCallingIdentity();
try {
- result = broadcastIntentLocked(callerApp,
+ return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
@@ -735,10 +733,6 @@ class BroadcastController {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
- if (sticky && result == ActivityManager.BROADCAST_SUCCESS) {
- BroadcastStickyCache.incrementVersion(intent.getAction());
- }
- return result;
}
// Not the binder call surface
@@ -749,7 +743,6 @@ class BroadcastController {
boolean serialized, boolean sticky, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList) {
- int result;
synchronized (mService) {
intent = verifyBroadcastLocked(intent);
@@ -757,7 +750,7 @@ class BroadcastController {
String[] requiredPermissions = requiredPermission == null ? null
: new String[] {requiredPermission};
try {
- result = broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
+ return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
resultToApp, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, null, null, OP_NONE, bOptions, serialized, sticky, -1,
uid, realCallingUid, realCallingPid, userId,
@@ -767,10 +760,6 @@ class BroadcastController {
Binder.restoreCallingIdentity(origId);
}
}
- if (sticky && result == ActivityManager.BROADCAST_SUCCESS) {
- BroadcastStickyCache.incrementVersion(intent.getAction());
- }
- return result;
}
@GuardedBy("mService")
@@ -1469,7 +1458,6 @@ class BroadcastController {
list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive,
callingUid, callerAppProcessState, resolvedType));
}
- BroadcastStickyCache.incrementVersion(intent.getAction());
}
}
@@ -1736,7 +1724,6 @@ class BroadcastController {
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- final ArrayList<String> changedStickyBroadcasts = new ArrayList<>();
synchronized (mStickyBroadcasts) {
ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId);
if (stickies != null) {
@@ -1753,16 +1740,12 @@ class BroadcastController {
if (list.size() <= 0) {
stickies.remove(intent.getAction());
}
- changedStickyBroadcasts.add(intent.getAction());
}
if (stickies.size() <= 0) {
mStickyBroadcasts.remove(userId);
}
}
}
- for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) {
- BroadcastStickyCache.incrementVersionIfExists(changedStickyBroadcasts.get(i));
- }
}
void finishReceiver(IBinder caller, int resultCode, String resultData,
@@ -1925,9 +1908,7 @@ class BroadcastController {
private void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
mService.mProcessList.sendPackageBroadcastLocked(cmd, packages, userId);
- }
-
- private List<ResolveInfo> collectReceiverComponents(
+ }private List<ResolveInfo> collectReceiverComponents(
Intent intent, String resolvedType, int callingUid, int callingPid,
int[] users, int[] broadcastAllowList) {
// TODO: come back and remove this assumption to triage all broadcasts
@@ -2143,18 +2124,9 @@ class BroadcastController {
}
void removeStickyBroadcasts(int userId) {
- final ArrayList<String> changedStickyBroadcasts = new ArrayList<>();
synchronized (mStickyBroadcasts) {
- final ArrayMap<String, ArrayList<StickyBroadcast>> stickies =
- mStickyBroadcasts.get(userId);
- if (stickies != null) {
- changedStickyBroadcasts.addAll(stickies.keySet());
- }
mStickyBroadcasts.remove(userId);
}
- for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) {
- BroadcastStickyCache.incrementVersionIfExists(changedStickyBroadcasts.get(i));
- }
}
@NeverCompile
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 3c7fb52b11b4..a32d3cb86c24 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -16,10 +16,13 @@
package com.android.server.am;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.os.Binder;
import android.os.UserHandle;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -40,7 +43,7 @@ public final class BroadcastFilter extends IntentFilter {
@ChangeId
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
@VisibleForTesting
- static final long CHANGE_RESTRICT_PRIORITY_VALUES = 371309185L;
+ static final long RESTRICT_PRIORITY_VALUES = 371309185L;
// Back-pointer to the list this filter is in.
final ReceiverList receiverList;
@@ -54,11 +57,12 @@ public final class BroadcastFilter extends IntentFilter {
final boolean visibleToInstantApp;
public final boolean exported;
final int initialPriority;
+ final ApplicationInfo applicationInfo;
BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
String _packageName, String _featureId, String _receiverId, String _requiredPermission,
int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp,
- boolean _exported, PlatformCompat platformCompat) {
+ boolean _exported, ApplicationInfo _applicationInfo, PlatformCompat platformCompat) {
super(_filter);
receiverList = _receiverList;
packageName = _packageName;
@@ -70,8 +74,10 @@ public final class BroadcastFilter extends IntentFilter {
instantApp = _instantApp;
visibleToInstantApp = _visibleToInstantApp;
exported = _exported;
+ applicationInfo = _applicationInfo;
initialPriority = getPriority();
- setPriority(calculateAdjustedPriority(owningUid, initialPriority, platformCompat));
+ setPriority(calculateAdjustedPriority(owningUid, initialPriority,
+ applicationInfo, platformCompat));
}
public @Nullable String getReceiverClassName() {
@@ -84,6 +90,10 @@ public final class BroadcastFilter extends IntentFilter {
return null;
}
+ public @NonNull ApplicationInfo getApplicationInfo() {
+ return applicationInfo;
+ }
+
@NeverCompile
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
@@ -125,13 +135,18 @@ public final class BroadcastFilter extends IntentFilter {
@VisibleForTesting
static int calculateAdjustedPriority(int owningUid, int priority,
- PlatformCompat platformCompat) {
+ ApplicationInfo applicationInfo, PlatformCompat platformCompat) {
if (!Flags.restrictPriorityValues()) {
return priority;
}
- if (!platformCompat.isChangeEnabledByUidInternalNoLogging(
- CHANGE_RESTRICT_PRIORITY_VALUES, owningUid)) {
- return priority;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!platformCompat.isChangeEnabledInternalNoLogging(
+ RESTRICT_PRIORITY_VALUES, applicationInfo)) {
+ return priority;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
if (!UserHandle.isCore(owningUid)) {
if (priority >= SYSTEM_HIGH_PRIORITY) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 38df10a0bc8c..a1ab1eea3d3e 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -49,6 +49,7 @@ import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.Bundle;
@@ -57,7 +58,6 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.IntArray;
import android.util.PrintWriterPrinter;
-import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -88,7 +88,7 @@ final class BroadcastRecord extends Binder {
@ChangeId
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
@VisibleForTesting
- static final long CHANGE_LIMIT_PRIORITY_SCOPE = 371307720L;
+ static final long LIMIT_PRIORITY_SCOPE = 371307720L;
final @NonNull Intent intent; // the original intent that generated us
final @Nullable ComponentName targetComp; // original component name set on the intent
@@ -781,7 +781,7 @@ final class BroadcastRecord extends Binder {
} else {
if (Flags.limitPriorityScope()) {
final boolean[] changeEnabled = calculateChangeStateForReceivers(
- receivers, CHANGE_LIMIT_PRIORITY_SCOPE, platformCompat);
+ receivers, LIMIT_PRIORITY_SCOPE, platformCompat);
// Priority of the previous tranche
int lastTranchePriority = 0;
@@ -865,25 +865,35 @@ final class BroadcastRecord extends Binder {
@VisibleForTesting
static @NonNull boolean[] calculateChangeStateForReceivers(@NonNull List<Object> receivers,
long changeId, PlatformCompat platformCompat) {
- final SparseBooleanArray changeStateForUids = new SparseBooleanArray();
+ // TODO: b/371307720 - Remove this method as we are already avoiding the packagemanager
+ // calls by checking the changeId state using ApplicationInfos.
+ final ArrayMap<String, Boolean> changeStates = new ArrayMap<>();
final int count = receivers.size();
final boolean[] changeStateForReceivers = new boolean[count];
for (int i = 0; i < count; ++i) {
- final int receiverUid = getReceiverUid(receivers.get(i));
+ final ApplicationInfo receiverAppInfo = getReceiverAppInfo(receivers.get(i));
final boolean isChangeEnabled;
- final int idx = changeStateForUids.indexOfKey(receiverUid);
+ final int idx = changeStates.indexOfKey(receiverAppInfo.packageName);
if (idx >= 0) {
- isChangeEnabled = changeStateForUids.valueAt(idx);
+ isChangeEnabled = changeStates.valueAt(idx);
} else {
- isChangeEnabled = platformCompat.isChangeEnabledByUidInternalNoLogging(
- changeId, receiverUid);
- changeStateForUids.put(receiverUid, isChangeEnabled);
+ isChangeEnabled = platformCompat.isChangeEnabledInternalNoLogging(
+ changeId, receiverAppInfo);
+ changeStates.put(receiverAppInfo.packageName, isChangeEnabled);
}
changeStateForReceivers[i] = isChangeEnabled;
}
return changeStateForReceivers;
}
+ static ApplicationInfo getReceiverAppInfo(@NonNull Object receiver) {
+ if (receiver instanceof BroadcastFilter) {
+ return ((BroadcastFilter) receiver).getApplicationInfo();
+ } else {
+ return ((ResolveInfo) receiver).activityInfo.applicationInfo;
+ }
+ }
+
static int getReceiverUid(@NonNull Object receiver) {
if (receiver instanceof BroadcastFilter) {
return ((BroadcastFilter) receiver).owningUid;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 416c11090515..2f5362f53361 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -101,7 +101,7 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executor;
-public final class CachedAppOptimizer {
+public class CachedAppOptimizer {
// Flags stored in the DeviceConfig API.
@VisibleForTesting static final String KEY_USE_COMPACTION = "use_compaction";
@@ -2122,7 +2122,7 @@ public final class CachedAppOptimizer {
Slog.d(TAG_AM,
"Performing native compaction for pid=" + pid
+ " type=" + compactProfile.name());
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem");
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactNative");
try {
mProcessDependencies.performCompaction(compactProfile, pid);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c0676623a1e9..f42641ece09b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT;
import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_CPU_TIME;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
@@ -155,6 +156,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -469,7 +471,6 @@ public class OomAdjuster {
}
Process.setThreadPriority(tid, priority);
}
-
}
// TODO(b/346822474): hook up global state usage.
@@ -499,7 +500,8 @@ public class OomAdjuster {
}
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
- ServiceThread adjusterThread, GlobalState globalState, Injector injector) {
+ ServiceThread adjusterThread, GlobalState globalState,
+ CachedAppOptimizer cachedAppOptimizer, Injector injector) {
mService = service;
mGlobalState = globalState;
mInjector = injector;
@@ -508,7 +510,7 @@ public class OomAdjuster {
mActiveUids = activeUids;
mConstants = mService.mConstants;
- mCachedAppOptimizer = new CachedAppOptimizer(mService);
+ mCachedAppOptimizer = cachedAppOptimizer;
mCacheOomRanker = new CacheOomRanker(service);
mLogger = new OomAdjusterDebugLogger(this, mService.mConstants);
@@ -1374,9 +1376,11 @@ public class OomAdjuster {
ProcessRecord app = lruList.get(i);
final ProcessStateRecord state = app.mState;
if (!app.isKilledByAm() && app.getThread() != null) {
- // We don't need to apply the update for the process which didn't get computed
- if (state.getCompletedAdjSeq() == mAdjSeq) {
- applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+ if (!Flags.fixApplyOomadjOrder()) {
+ // We don't need to apply the update for the process which didn't get computed
+ if (state.getCompletedAdjSeq() == mAdjSeq) {
+ applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+ }
}
if (app.isPendingFinishAttach()) {
@@ -1478,6 +1482,19 @@ public class OomAdjuster {
}
}
+ if (Flags.fixApplyOomadjOrder()) {
+ // We need to apply the update starting from the least recently used.
+ // Otherwise, they won't be in the correct LRU order in LMKD.
+ for (int i = 0; i < numLru; i++) {
+ ProcessRecord app = lruList.get(i);
+ // We don't need to apply the update for the process which didn't get computed
+ if (!app.isKilledByAm() && app.getThread() != null
+ && app.mState.getCompletedAdjSeq() == mAdjSeq) {
+ applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+ }
+ }
+ }
+
if (!mProcsToOomAdj.isEmpty()) {
mInjector.batchSetOomAdj(mProcsToOomAdj);
mProcsToOomAdj.clear();
@@ -2597,6 +2614,7 @@ public class OomAdjuster {
}
capability |= getDefaultCapability(app, procState);
+ capability |= getCpuCapability(app, now);
// Procstates below BFGS should never have this capability.
if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
@@ -2739,8 +2757,12 @@ public class OomAdjuster {
if (app.mOptRecord.setShouldNotFreeze(true, dryRun,
app.mOptRecord.shouldNotFreezeReason()
| client.mOptRecord.shouldNotFreezeReason(), mAdjSeq)) {
- // Bail out early, as we only care about the return value for a dryrun.
- return true;
+ if (Flags.useCpuTimeCapability()) {
+ // Do nothing, capability updated check will handle the dryrun output.
+ } else {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
}
@@ -2751,6 +2773,8 @@ public class OomAdjuster {
// we check the final procstate, and remove it if the procsate is below BFGS.
capability |= getBfslCapabilityFromClient(client);
+ capability |= getCpuCapabilityFromClient(client);
+
if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) {
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
capability |= cstate.getCurCapability();
@@ -2809,9 +2833,14 @@ public class OomAdjuster {
app.mOptRecord.shouldNotFreezeReason()
| ProcessCachedOptimizerRecord
.SHOULD_NOT_FREEZE_REASON_BINDER_ALLOW_OOM_MANAGEMENT, mAdjSeq)) {
- // Bail out early, as we only care about the return value for a dryrun.
- return true;
+ if (Flags.useCpuTimeCapability()) {
+ // Do nothing, capability updated check will handle the dryrun output.
+ } else {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
+ capability |= PROCESS_CAPABILITY_CPU_TIME;
}
// Not doing bind OOM management, so treat
// this guy more like a started service.
@@ -3053,9 +3082,14 @@ public class OomAdjuster {
app.mOptRecord.shouldNotFreezeReason()
| ProcessCachedOptimizerRecord
.SHOULD_NOT_FREEZE_REASON_BIND_WAIVE_PRIORITY, mAdjSeq)) {
- // Bail out early, as we only care about the return value for a dryrun.
- return true;
+ if (Flags.useCpuTimeCapability()) {
+ // Do nothing, capability updated check will handle the dryrun output.
+ } else {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
+ capability |= PROCESS_CAPABILITY_CPU_TIME;
}
}
if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
@@ -3108,9 +3142,24 @@ public class OomAdjuster {
capability &= ~PROCESS_CAPABILITY_BFSL;
}
if (!updated) {
- updated = adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
- || (capability != prevCapability
- && (capability & prevCapability) == prevCapability);
+ if (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup) {
+ updated = true;
+ }
+
+ if (Flags.useCpuTimeCapability()) {
+ if ((capability != prevCapability)
+ && ((capability & prevCapability) == prevCapability)) {
+ updated = true;
+ }
+ } else {
+ // Ignore PROCESS_CAPABILITY_CPU_TIME in capability comparison
+ final int curFiltered = capability & ~PROCESS_CAPABILITY_CPU_TIME;
+ final int prevFiltered = prevCapability & ~PROCESS_CAPABILITY_CPU_TIME;
+ if ((curFiltered != prevFiltered)
+ && ((curFiltered & prevFiltered) == prevFiltered)) {
+ updated = true;
+ }
+ }
}
if (dryRun) {
@@ -3186,6 +3235,8 @@ public class OomAdjuster {
// we check the final procstate, and remove it if the procsate is below BFGS.
capability |= getBfslCapabilityFromClient(client);
+ capability |= getCpuCapabilityFromClient(client);
+
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty.
@@ -3196,8 +3247,12 @@ public class OomAdjuster {
if (app.mOptRecord.setShouldNotFreeze(true, dryRun,
app.mOptRecord.shouldNotFreezeReason()
| client.mOptRecord.shouldNotFreezeReason(), mAdjSeq)) {
- // Bail out early, as we only care about the return value for a dryrun.
- return true;
+ if (Flags.useCpuTimeCapability()) {
+ // Do nothing, capability updated check will handle the dryrun output.
+ } else {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
}
@@ -3273,10 +3328,25 @@ public class OomAdjuster {
capability &= ~PROCESS_CAPABILITY_BFSL;
}
- if (dryRun && (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
- || (capability != prevCapability
- && (capability & prevCapability) == prevCapability))) {
- return true;
+ if (dryRun) {
+ if (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup) {
+ return true;
+ }
+
+ if (Flags.useCpuTimeCapability()) {
+ if ((capability != prevCapability)
+ && ((capability & prevCapability) == prevCapability)) {
+ return true;
+ }
+ } else {
+ // Ignore PROCESS_CAPABILITY_CPU_TIME in capability comparison
+ final int curFiltered = capability & ~PROCESS_CAPABILITY_CPU_TIME;
+ final int prevFiltered = prevCapability & ~PROCESS_CAPABILITY_CPU_TIME;
+ if ((curFiltered != prevFiltered)
+ && ((curFiltered & prevFiltered) == prevFiltered)) {
+ return true;
+ }
+ }
}
if (adj < prevRawAdj) {
@@ -3328,6 +3398,29 @@ public class OomAdjuster {
return baseCapabilities | networkCapabilities;
}
+ private static int getCpuCapability(ProcessRecord app, long nowUptime) {
+ final UidRecord uidRec = app.getUidRecord();
+ if (uidRec != null && uidRec.isCurAllowListed()) {
+ // Process has user visible activities.
+ return PROCESS_CAPABILITY_CPU_TIME;
+ }
+ if (UserHandle.isCore(app.uid)) {
+ // Make sure all system components are not frozen.
+ return PROCESS_CAPABILITY_CPU_TIME;
+ }
+ if (app.mState.getCachedHasVisibleActivities()) {
+ // Process has user visible activities.
+ return PROCESS_CAPABILITY_CPU_TIME;
+ }
+ if (app.mServices.hasUndemotedShortForegroundService(nowUptime)) {
+ // It running a short fgs, just give it cpu time.
+ return PROCESS_CAPABILITY_CPU_TIME;
+ }
+ // TODO(b/370817323): Populate this method with all of the reasons to keep a process
+ // unfrozen.
+ return 0;
+ }
+
/**
* @return the BFSL capability from a client (of a service binding or provider).
*/
@@ -3376,6 +3469,15 @@ public class OomAdjuster {
}
/**
+ * @return the CPU capability from a client (of a service binding or provider).
+ */
+ private static int getCpuCapabilityFromClient(ProcessRecord client) {
+ // Just grant CPU capability every time
+ // TODO(b/370817323): Populate with reasons to not propagate cpu capability across bindings.
+ return client.mState.getCurCapability() & PROCESS_CAPABILITY_CPU_TIME;
+ }
+
+ /**
* Checks if for the given app and client, there's a cycle that should skip over the client
* for now or use partial values to evaluate the effect of the client binding.
* @param app
@@ -3955,6 +4057,39 @@ public class OomAdjuster {
mCacheOomRanker.dump(pw);
}
+ /**
+ * Return whether or not a process should be frozen.
+ */
+ boolean getFreezePolicy(ProcessRecord proc) {
+ // Reasons to not freeze:
+ if (Flags.useCpuTimeCapability()) {
+ if ((proc.mState.getCurCapability() & PROCESS_CAPABILITY_CPU_TIME) != 0) {
+ /// App is important enough (see {@link #getCpuCapability}) or bound by something
+ /// important enough to not be frozen.
+ return false;
+ }
+ } else {
+ // The CPU capability handling covers all setShouldNotFreeze paths. Must check
+ // shouldNotFreeze, if the CPU capability is not being used.
+ if (proc.mOptRecord.shouldNotFreeze()) {
+ return false;
+ }
+ }
+
+ if (proc.mOptRecord.isFreezeExempt()) {
+ return false;
+ }
+
+ // Reasons to freeze:
+ if (proc.mState.getCurAdj() >= FREEZER_CUTOFF_ADJ) {
+ // Oomscore is in a high enough state, it is safe to freeze.
+ return true;
+ }
+
+ // Default, do not freeze a process.
+ return false;
+ }
+
@GuardedBy({"mService", "mProcLock"})
void updateAppFreezeStateLSP(ProcessRecord app, @OomAdjReason int oomAdjReason,
boolean immediate, int oldOomAdj) {
@@ -3969,43 +4104,44 @@ public class OomAdjuster {
(state.getCurAdj() >= FREEZER_CUTOFF_ADJ ^ oldOomAdj >= FREEZER_CUTOFF_ADJ)
|| oldOomAdj == UNKNOWN_ADJ;
final boolean shouldNotFreezeChanged = opt.shouldNotFreezeAdjSeq() == mAdjSeq;
- if ((oomAdjChanged || shouldNotFreezeChanged)
+ final boolean hasCpuCapability =
+ (PROCESS_CAPABILITY_CPU_TIME & app.mState.getCurCapability())
+ == PROCESS_CAPABILITY_CPU_TIME;
+ final boolean usedToHaveCpuCapability =
+ (PROCESS_CAPABILITY_CPU_TIME & app.mState.getSetCapability())
+ == PROCESS_CAPABILITY_CPU_TIME;
+ final boolean cpuCapabilityChanged = hasCpuCapability != usedToHaveCpuCapability;
+ if ((oomAdjChanged || shouldNotFreezeChanged || cpuCapabilityChanged)
&& Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER,
CachedAppOptimizer.ATRACE_FREEZER_TRACK,
"updateAppFreezeStateLSP " + app.processName
+ + " pid: " + app.getPid()
+ " isFreezeExempt: " + opt.isFreezeExempt()
+ " isFrozen: " + opt.isFrozen()
+ " shouldNotFreeze: " + opt.shouldNotFreeze()
+ " shouldNotFreezeReason: " + opt.shouldNotFreezeReason()
+ " curAdj: " + state.getCurAdj()
+ " oldOomAdj: " + oldOomAdj
- + " immediate: " + immediate);
+ + " immediate: " + immediate
+ + " cpuCapability: " + hasCpuCapability);
}
}
- if (app.mOptRecord.isFreezeExempt()) {
- return;
- }
-
- // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze
- if (opt.isFrozen() && opt.shouldNotFreeze()) {
- mCachedAppOptimizer.unfreezeAppLSP(app,
- CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason));
- return;
- }
-
- // Use current adjustment when freezing, set adjustment when unfreezing.
- if (state.getCurAdj() >= FREEZER_CUTOFF_ADJ && !opt.isFrozen()
- && !opt.shouldNotFreeze()) {
- if (!immediate) {
- mCachedAppOptimizer.freezeAppAsyncLSP(app);
- } else {
+ if (getFreezePolicy(app)) {
+ // This process should be frozen.
+ if (immediate && !opt.isFrozen()) {
+ // And it will be frozen immediately.
mCachedAppOptimizer.freezeAppAsyncAtEarliestLSP(app);
+ } else if (!opt.isFrozen() || !opt.isPendingFreeze()) {
+ mCachedAppOptimizer.freezeAppAsyncLSP(app);
+ }
+ } else {
+ // This process should not be frozen.
+ if (opt.isFrozen() || opt.isPendingFreeze()) {
+ mCachedAppOptimizer.unfreezeAppLSP(app,
+ CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason));
}
- } else if (state.getSetAdj() < FREEZER_CUTOFF_ADJ) {
- mCachedAppOptimizer.unfreezeAppLSP(app,
- CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason));
}
}
@@ -4029,7 +4165,8 @@ public class OomAdjuster {
final int size = processes.size();
for (int i = 0; i < size; i++) {
ProcessRecord proc = processes.get(i);
- mCachedAppOptimizer.unfreezeTemporarily(proc, reason);
+ mCachedAppOptimizer.unfreezeTemporarily(proc,
+ CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(reason));
}
processes.clear();
}
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index 8b660559f550..1b7e8f0bd244 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -758,8 +758,9 @@ public class OomAdjusterModernImpl extends OomAdjuster {
OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
ActiveUids activeUids, ServiceThread adjusterThread, GlobalState globalState,
- Injector injector) {
- super(service, processList, activeUids, adjusterThread, globalState, injector);
+ CachedAppOptimizer cachedAppOptimizer, Injector injector) {
+ super(service, processList, activeUids, adjusterThread, globalState, cachedAppOptimizer,
+ injector);
}
private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b51db137f293..98f738c38d63 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -351,7 +351,8 @@ class ProcessRecord implements WindowProcessListener {
private String[] mIsolatedEntryPointArgs;
/**
- * Process is currently hosting a backup agent for backup or restore.
+ * Process is currently hosting a backup agent for backup or restore. Note that this is only set
+ * when the process is put into restricted backup mode.
*/
@GuardedBy("mService")
private boolean mInFullBackup;
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 5cb8b954a2ba..14d3fbc22372 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -256,18 +256,24 @@ final class ProcessServiceRecord {
}
// Now we need to look at all short-FGS within the process and see if all of them are
// procstate-timed-out or not.
+ return !hasUndemotedShortForegroundService(nowUptime);
+ }
+
+ boolean hasUndemotedShortForegroundService(long nowUptime) {
for (int i = mServices.size() - 1; i >= 0; i--) {
final ServiceRecord sr = mServices.valueAt(i);
if (!sr.isShortFgs() || !sr.hasShortFgsInfo()) {
continue;
}
if (sr.getShortFgsInfo().getProcStateDemoteTime() >= nowUptime) {
- return false;
+ // This short fgs has not timed out yet.
+ return true;
}
}
- return true;
+ return false;
}
+
int getReportedForegroundServiceTypes() {
return mRepFgServiceTypes;
}
@@ -387,6 +393,8 @@ final class ProcessServiceRecord {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+ } else if (Flags.addModifyRawOomAdjServiceLevel() && adj < ProcessList.SERVICE_ADJ) {
+ adj = ProcessList.SERVICE_ADJ;
} else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
adj = ProcessList.CACHED_APP_MIN_ADJ;
} else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
diff --git a/services/core/java/com/android/server/am/ProcessStateController.java b/services/core/java/com/android/server/am/ProcessStateController.java
index 01468c640f6c..57899228e6ad 100644
--- a/services/core/java/com/android/server/am/ProcessStateController.java
+++ b/services/core/java/com/android/server/am/ProcessStateController.java
@@ -29,6 +29,7 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.ServiceThread;
/**
@@ -44,13 +45,14 @@ public class ProcessStateController {
private final GlobalState mGlobalState = new GlobalState();
private ProcessStateController(ActivityManagerService ams, ProcessList processList,
- ActiveUids activeUids, ServiceThread handlerThread, OomAdjuster.Injector oomAdjInjector,
+ ActiveUids activeUids, ServiceThread handlerThread,
+ CachedAppOptimizer cachedAppOptimizer, OomAdjuster.Injector oomAdjInjector,
boolean useOomAdjusterModernImpl) {
mOomAdjuster = useOomAdjusterModernImpl
? new OomAdjusterModernImpl(ams, processList, activeUids, handlerThread,
- mGlobalState, oomAdjInjector)
+ mGlobalState, cachedAppOptimizer, oomAdjInjector)
: new OomAdjuster(ams, processList, activeUids, handlerThread, mGlobalState,
- oomAdjInjector);
+ cachedAppOptimizer, oomAdjInjector);
}
/**
@@ -594,6 +596,7 @@ public class ProcessStateController {
private final ActiveUids mActiveUids;
private ServiceThread mHandlerThread = null;
+ private CachedAppOptimizer mCachedAppOptimizer = null;
private OomAdjuster.Injector mOomAdjInjector = null;
private boolean mUseOomAdjusterModernImpl = false;
@@ -610,24 +613,38 @@ public class ProcessStateController {
if (mHandlerThread == null) {
mHandlerThread = OomAdjuster.createAdjusterThread();
}
+ if (mCachedAppOptimizer == null) {
+ mCachedAppOptimizer = new CachedAppOptimizer(mAms);
+ }
if (mOomAdjInjector == null) {
mOomAdjInjector = new OomAdjuster.Injector();
}
return new ProcessStateController(mAms, mProcessList, mActiveUids, mHandlerThread,
- mOomAdjInjector, mUseOomAdjusterModernImpl);
+ mCachedAppOptimizer, mOomAdjInjector, mUseOomAdjusterModernImpl);
}
/**
* For Testing Purposes. Set what thread OomAdjuster will offload tasks on to.
*/
+ @VisibleForTesting
public Builder setHandlerThread(ServiceThread handlerThread) {
mHandlerThread = handlerThread;
return this;
}
/**
+ * For Testing Purposes. Set the CachedAppOptimzer used by OomAdjuster.
+ */
+ @VisibleForTesting
+ public Builder setCachedAppOptimizer(CachedAppOptimizer cachedAppOptimizer) {
+ mCachedAppOptimizer = cachedAppOptimizer;
+ return this;
+ }
+
+ /**
* For Testing Purposes. Set an injector for OomAdjuster.
*/
+ @VisibleForTesting
public Builder setOomAdjusterInjector(OomAdjuster.Injector injector) {
mOomAdjInjector = injector;
return this;
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 3dd5ec9a3834..78c4f74f3afa 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -221,6 +221,7 @@ public class SettingsToPropertiesMapper {
"preload_safety",
"printing",
"privacy_infra_policy",
+ "psap_ai",
"ravenwood",
"resource_manager",
"responsible_apis",
@@ -256,6 +257,7 @@ public class SettingsToPropertiesMapper {
"wear_systems",
"wear_sysui",
"wear_system_managed_surfaces",
+ "wear_watchfaces",
"window_surfaces",
"windowing_frontend",
"xr",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 8395685349e4..89e4a8d82676 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -245,6 +245,14 @@ flag {
}
flag {
+ name: "fix_apply_oomadj_order"
+ namespace: "backstage_power"
+ is_fixed_read_only: true
+ description: "Fix the iteration direction of process LRU list when applying oom adj"
+ bug: "378580264"
+}
+
+flag {
name: "phantom_processes_fix"
namespace: "backstage_power"
description: "Make sure setProcessGroupForPhantomProcessOfApp deals with phantom processes properly"
@@ -253,3 +261,30 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "use_cpu_time_capability"
+ namespace: "backstage_power"
+ description: "Use PROCESS_CAPABILITY_CPU_TIME to control unfreeze state."
+ bug: "370817323"
+}
+
+flag {
+ name: "add_modify_raw_oom_adj_service_level"
+ namespace: "backstage_power"
+ description: "Add a SERVICE_ADJ level to the modifyRawOomAdj method"
+ bug: "374810368"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "app_start_info_isolated_process"
+ namespace: "system_performance"
+ description: "Adjust handling of isolated process records to be discarded."
+ bug: "374032823"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 8c5152fdb0d6..6f8dc105850d 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -100,6 +100,7 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
+import com.android.server.utils.LazyJniRegistrar;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.CompatScaleProvider;
@@ -158,6 +159,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
private static final String GAME_MODE_INTERVENTION_LIST_FILE_NAME =
"game_mode_intervention.list";
+ static {
+ LazyJniRegistrar.registerGameManagerService();
+ }
+
private final Context mContext;
private final Object mLock = new Object();
private final Object mDeviceConfigLock = new Object();
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 5e74d67905a6..06c586f5e9c2 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2876,7 +2876,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
@Override
- public int checkOperationForDevice(int code, int uid, String packageName, int virtualDeviceId) {
+ public int checkOperationForDevice(int code, int uid, String packageName,
+ @Nullable String attributionTag, int virtualDeviceId) {
if (Binder.getCallingPid() != Process.myPid()
&& Flags.appopAccessTrackingLoggingEnabled()) {
FrameworkStatsLog.write(
@@ -2884,7 +2885,7 @@ public class AppOpsService extends IAppOpsService.Stub {
APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION,
false);
}
- return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
+ return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, attributionTag,
virtualDeviceId, false /*raw*/);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index ed41f2e881f8..fa2e674d37c7 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -31,7 +31,6 @@ import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
-import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
@@ -177,8 +176,6 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
case OP_RECORD_AUDIO:
case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
return PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
- case OP_TAKE_AUDIO_FOCUS:
- return PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
default:
return PROCESS_CAPABILITY_NONE;
}
diff --git a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
index 5283eddd90fb..473691874262 100644
--- a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
+++ b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
@@ -24,6 +24,7 @@ import static android.Manifest.permission.CAPTURE_AUDIO_OUTPUT;
import static android.Manifest.permission.CAPTURE_MEDIA_OUTPUT;
import static android.Manifest.permission.CAPTURE_TUNER_AUDIO_INPUT;
import static android.Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT;
+import static android.Manifest.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION;
import static android.Manifest.permission.MODIFY_AUDIO_ROUTING;
import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS;
import static android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS;
@@ -37,7 +38,6 @@ import android.os.Trace;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.IntArray;
-import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.media.permission.INativePermissionController;
@@ -82,6 +82,8 @@ public class AudioServerPermissionProvider {
MONITORED_PERMS[PermissionEnum.CAPTURE_VOICE_COMMUNICATION_OUTPUT] =
CAPTURE_VOICE_COMMUNICATION_OUTPUT;
MONITORED_PERMS[PermissionEnum.BLUETOOTH_CONNECT] = BLUETOOTH_CONNECT;
+ MONITORED_PERMS[PermissionEnum.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION] =
+ BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION;
}
private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6ba356990cac..5c2eb5cf1086 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -49,6 +49,7 @@ import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import static android.media.AudioManager.STREAM_SYSTEM;
import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.media.audio.Flags.automaticBtDeviceType;
+import static android.media.audio.Flags.concurrentAudioRecordBypassPermission;
import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
import static android.media.audio.Flags.focusFreezeTestApi;
import static android.media.audio.Flags.roForegroundAudioControl;
@@ -4888,6 +4889,8 @@ public class AudioService extends IAudioService.Stub
+ equalScoLeaVcIndexRange());
pw.println("\tcom.android.media.audio.ringMyCar:"
+ ringMyCar());
+ pw.println("\tandroid.media.audio.Flags.concurrentAudioRecordBypassPermission:"
+ + concurrentAudioRecordBypassPermission());
}
private void dumpAudioMode(PrintWriter pw) {
@@ -4951,6 +4954,15 @@ public class AudioService extends IAudioService.Stub
}
final Set<Integer> deviceTypes = getDeviceSetForStreamDirect(streamType);
+
+ final Set<Integer> a2dpDevices = AudioSystem.intersectionAudioDeviceTypes(
+ AudioSystem.DEVICE_OUT_ALL_A2DP_SET, deviceTypes);
+ if (!a2dpDevices.isEmpty()) {
+ int index = getStreamVolume(streamType,
+ a2dpDevices.toArray(new Integer[0])[0].intValue());
+ mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index);
+ }
+
final Set<Integer> absVolumeMultiModeCaseDevices =
AudioSystem.intersectionAudioDeviceTypes(
mAbsVolumeMultiModeCaseDevices, deviceTypes);
@@ -9224,6 +9236,9 @@ public class AudioService extends IAudioService.Stub
return;
}
+ // index values sent to APM are in the stream type SDK range, not *10
+ int indexMinVolCurve = MIN_STREAM_VOLUME[mStreamType];
+ int indexMaxVolCurve = MAX_STREAM_VOLUME[mStreamType];
synchronized (this) {
if (mStreamType == AudioSystem.STREAM_VOICE_CALL) {
if (MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO]
@@ -9234,11 +9249,15 @@ public class AudioService extends IAudioService.Stub
if (!equalScoLeaVcIndexRange() && isStreamBluetoothSco(mStreamType)) {
// SCO devices have a different min index
mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10;
+ indexMinVolCurve = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
+ indexMaxVolCurve = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
mIndexStepFactor = 1.f;
} else if (equalScoLeaVcIndexRange() && isStreamBluetoothComm(mStreamType)) {
// For non SCO devices the stream state does not change the min index
if (mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) {
mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10;
+ indexMinVolCurve = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
+ indexMaxVolCurve = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
} else {
mIndexMin = MIN_STREAM_VOLUME[mStreamType] * 10;
}
@@ -9259,7 +9278,7 @@ public class AudioService extends IAudioService.Stub
}
final int status = AudioSystem.initStreamVolume(
- mStreamType, mIndexMin / 10, mIndexMax / 10);
+ mStreamType, indexMinVolCurve, indexMaxVolCurve);
sVolumeLogger.enqueue(new EventLogger.StringEvent(
"updateIndexFactors() stream:" + mStreamType + " index min/max:"
+ mIndexMin / 10 + "/" + mIndexMax / 10 + " indexStepFactor:"
@@ -11415,6 +11434,10 @@ public class AudioService extends IAudioService.Stub
return mSpatializerHelper.canBeSpatialized(attributes, format);
}
+ public @NonNull List<Integer> getSpatializedChannelMasks() {
+ return mSpatializerHelper.getSpatializedChannelMasks();
+ }
+
/** @see Spatializer.SpatializerInfoDispatcherStub */
public void registerSpatializerCallback(
@NonNull ISpatializerCallback cb) {
@@ -14159,10 +14182,10 @@ public class AudioService extends IAudioService.Stub
* Update player event
* @param piid Player id to update
* @param event The new player event
- * @param eventValue The value associated with this event
+ * @param eventValues The values associated with this event
*/
- public void playerEvent(int piid, int event, int eventValue) {
- mPlaybackMonitor.playerEvent(piid, event, eventValue, Binder.getCallingUid());
+ public void playerEvent(int piid, int event, int[] eventValues) {
+ mPlaybackMonitor.playerEvent(piid, event, eventValues, Binder.getCallingUid());
}
/**
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b63b07f0453e..a2200c9f8bf5 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -20,9 +20,11 @@ import static android.media.AudioPlaybackConfiguration.EXTRA_PLAYER_EVENT_MUTE;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_APP_OPS;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_CLIENT_VOLUME;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_MASTER;
+import static android.media.AudioPlaybackConfiguration.MUTED_BY_PORT_VOLUME;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_MUTED;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_VOLUME;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_VOLUME_SHAPER;
+import static android.media.AudioPlaybackConfiguration.MUTED_BY_OP_CONTROL_AUDIO;
import static android.media.AudioPlaybackConfiguration.PLAYER_PIID_INVALID;
import static android.media.AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED;
@@ -364,10 +366,11 @@ public final class PlaybackActivityMonitor
* @param eventValue The value associated with this event
* @param binderUid Calling binder uid
*/
- public void playerEvent(int piid, int event, int eventValue, int binderUid) {
+ public void playerEvent(int piid, int event, int[] eventValues, int binderUid) {
if (DEBUG) {
- Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValue=%d)",
- piid, AudioPlaybackConfiguration.playerStateToString(event), eventValue));
+ Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValues=%d)",
+ piid, AudioPlaybackConfiguration.playerStateToString(event),
+ Arrays.toString(eventValues)));
}
boolean change;
synchronized(mPlayerLock) {
@@ -381,13 +384,13 @@ public final class PlaybackActivityMonitor
// do not log nor dispatch events for "ignored" players other than the release
return;
}
- sEventLogger.enqueue(new PlayerEvent(piid, event, eventValue));
+ sEventLogger.enqueue(new PlayerEvent(piid, event, eventValues));
if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) {
if (portToPiidSimplification()) {
- mPiidToPortId.put(piid, eventValue);
+ mPiidToPortId.put(piid, eventValues[0]);
} else {
- mPortIdToPiid.put(eventValue, piid);
+ mPortIdToPiid.put(eventValues[0], piid);
}
return;
} else if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
@@ -408,7 +411,7 @@ public final class PlaybackActivityMonitor
if (checkConfigurationCaller(piid, apc, binderUid)) {
//TODO add generation counter to only update to the latest state
checkVolumeForPrivilegedAlarm(apc, event);
- change = apc.handleStateEvent(event, eventValue);
+ change = apc.handleStateEvent(event, eventValues);
} else {
Log.e(TAG, "Error handling event " + event);
change = false;
@@ -444,7 +447,7 @@ public final class PlaybackActivityMonitor
}
if (DEBUG) {
- Log.v(TAG, TextUtils.formatSimple("BLA portEvent(portId=%d, event=%s, extras=%s)",
+ Log.v(TAG, TextUtils.formatSimple("portEvent(portId=%d, event=%s, extras=%s)",
portId, AudioPlaybackConfiguration.playerStateToString(event), extras));
}
@@ -516,7 +519,7 @@ public final class PlaybackActivityMonitor
mMutedPlayersAwaitingConnection.remove(Integer.valueOf(piid));
checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED,
- AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+ AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID);
if (portToPiidSimplification()) {
mPiidToPortId.delete(piid);
@@ -1335,12 +1338,12 @@ public final class PlaybackActivityMonitor
// only keeping the player interface ID as it uniquely identifies the player in the event
final int mPlayerIId;
final int mEvent;
- final int mEventValue;
+ final int[] mEventValues;
- PlayerEvent(int piid, int event, int eventValue) {
+ PlayerEvent(int piid, int event, int[] eventValues) {
mPlayerIId = piid;
mEvent = event;
- mEventValue = eventValue;
+ mEventValues = eventValues;
}
@Override
@@ -1352,35 +1355,44 @@ public final class PlaybackActivityMonitor
switch (mEvent) {
case AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID:
return AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent) + " portId:"
- + mEventValue + " mapped to player piid:" + mPlayerIId;
+ + Arrays.toString(mEventValues) + " mapped to player piid:"
+ + mPlayerIId;
case AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID:
- if (mEventValue != 0) {
- builder.append(" deviceId:").append(mEventValue);
+ if ((mEventValues.length > 0) && (mEventValues[0] != 0)) {
+ builder.append(" deviceIds:").append(Arrays.toString(mEventValues));
}
return builder.toString();
case AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED:
builder.append(" source:");
- if (mEventValue <= 0) {
+ int eventValue = mEventValues[0];
+ if (eventValue <= 0) {
builder.append("none ");
} else {
- if ((mEventValue & MUTED_BY_MASTER) != 0) {
+ if ((eventValue & MUTED_BY_MASTER) != 0) {
builder.append("masterMute ");
}
- if ((mEventValue & MUTED_BY_STREAM_VOLUME) != 0) {
+ if ((eventValue & MUTED_BY_STREAM_VOLUME) != 0) {
builder.append("streamVolume ");
}
- if ((mEventValue & MUTED_BY_STREAM_MUTED) != 0) {
+ if ((eventValue & MUTED_BY_STREAM_MUTED) != 0) {
builder.append("streamMute ");
}
- if ((mEventValue & MUTED_BY_APP_OPS) != 0) {
+ if ((eventValue & MUTED_BY_APP_OPS) != 0) {
builder.append("appOps ");
}
- if ((mEventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
+ if ((eventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
builder.append("clientVolume ");
}
- if ((mEventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
+ if ((eventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
builder.append("volumeShaper ");
}
+ if ((eventValue & MUTED_BY_PORT_VOLUME) != 0) {
+ builder.append("portVolume ");
+ }
+ if ((eventValue & MUTED_BY_OP_CONTROL_AUDIO) != 0) {
+ builder.append("opControlAudio ");
+ }
+
}
return builder.toString();
default:
@@ -1728,8 +1740,11 @@ public final class PlaybackActivityMonitor
synchronized (mPlayerLock) {
int piid = msg.arg1;
+
+ int[] eventValues = new int[1];
+ eventValues[0] = eventValue;
sEventLogger.enqueue(
- new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValue));
+ new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValues));
final AudioPlaybackConfiguration apc = mPlayers.get(piid);
if (apc == null || !apc.handleMutedEvent(eventValue)) {
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 9265ff2d9b2d..afa90d5869e3 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -59,6 +59,8 @@ import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
@@ -1100,6 +1102,23 @@ public class SpatializerHelper {
return able;
}
+ synchronized @NonNull List<Integer> getSpatializedChannelMasks() {
+ if (!checkSpatializer("getSpatializedChannelMasks")) {
+ return Collections.emptyList();
+ }
+ try {
+ final int[] nativeMasks = new int[0]; // FIXME mSpat query goes here
+ for (int i = 0; i < nativeMasks.length; i++) {
+ nativeMasks[i] = AudioFormat.convertNativeChannelMaskToOutMask(nativeMasks[i]);
+ }
+ final List<Integer> masks = Arrays.stream(nativeMasks).boxed().toList();
+ return masks;
+ } catch (Exception e) { // just catch Exception in case nativeMasks is null
+ Log.e(TAG, "Error calling getSpatializedChannelMasks", e);
+ return Collections.emptyList();
+ }
+ }
+
//------------------------------------------------------
// head tracking
final RemoteCallbackList<ISpatializerHeadTrackingModeCallback> mHeadTrackingModeCallbacks =
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 65780238ede4..b365ef7ff61c 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -101,6 +101,7 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
/**
@@ -132,7 +133,7 @@ public class BiometricService extends SystemService {
IGateKeeperService mGateKeeper;
// Get and cache the available biometric authenticators and their associated info.
- final ArrayList<BiometricSensor> mSensors = new ArrayList<>();
+ final CopyOnWriteArrayList<BiometricSensor> mSensors = new CopyOnWriteArrayList<>();
@VisibleForTesting
BiometricStrengthController mBiometricStrengthController;
@@ -156,13 +157,13 @@ public class BiometricService extends SystemService {
@NonNull private final Set<Integer> mSensorsPendingInvalidation;
public static InvalidationTracker start(@NonNull Context context,
- @NonNull ArrayList<BiometricSensor> sensors,
- int userId, int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
+ @NonNull List<BiometricSensor> sensors, int userId,
+ int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
return new InvalidationTracker(context, sensors, userId, fromSensorId, clientCallback);
}
private InvalidationTracker(@NonNull Context context,
- @NonNull ArrayList<BiometricSensor> sensors, int userId,
+ @NonNull List<BiometricSensor> sensors, int userId,
int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
mClientCallback = clientCallback;
mSensorsPendingInvalidation = new ArraySet<>();
@@ -433,21 +434,12 @@ public class BiometricService extends SystemService {
public boolean getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(int userId) {
if (!mMandatoryBiometricsEnabled.containsKey(userId)) {
- Slog.d(TAG, "update mb toggle for user " + userId);
updateMandatoryBiometricsForAllProfiles(userId);
}
if (!mMandatoryBiometricsRequirementsSatisfied.containsKey(userId)) {
- Slog.d(TAG, "update mb reqs for user " + userId);
updateMandatoryBiometricsRequirementsForAllProfiles(userId);
}
- Slog.d(TAG, mMandatoryBiometricsEnabled.getOrDefault(userId,
- DEFAULT_MANDATORY_BIOMETRICS_STATUS)
- + " " + mMandatoryBiometricsRequirementsSatisfied.getOrDefault(userId,
- DEFAULT_MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED_STATUS)
- + " " + getEnabledForApps(userId)
- + " " + (mFingerprintEnrolledForUser.getOrDefault(userId, false /* default */)
- || mFaceEnrolledForUser.getOrDefault(userId, false /* default */)));
return mMandatoryBiometricsEnabled.getOrDefault(userId,
DEFAULT_MANDATORY_BIOMETRICS_STATUS)
&& mMandatoryBiometricsRequirementsSatisfied.getOrDefault(userId,
@@ -879,7 +871,7 @@ public class BiometricService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
- public synchronized void registerAuthenticator(int id, int modality,
+ public void registerAuthenticator(int id, int modality,
@Authenticators.Types int strength,
@NonNull IBiometricAuthenticator authenticator) {
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index afdc0c0294a6..6ed1ac859501 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -226,10 +226,6 @@ class PreAuthInfo {
return BIOMETRIC_NO_HARDWARE;
}
- if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) {
- return BIOMETRIC_HARDWARE_NOT_DETECTED;
- }
-
final boolean wasStrongEnough =
Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength);
final boolean isStrongEnough =
@@ -241,6 +237,10 @@ class PreAuthInfo {
return BIOMETRIC_INSUFFICIENT_STRENGTH;
}
+ if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) {
+ return BIOMETRIC_HARDWARE_NOT_DETECTED;
+ }
+
try {
if (!sensor.impl.isHardwareDetected(opPackageName)) {
return BIOMETRIC_HARDWARE_NOT_DETECTED;
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 82d5d4d8141d..e8786be4d8e6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -677,10 +677,11 @@ public class BiometricScheduler<T, U> {
* Start the timeout for the watchdog.
*/
public void startWatchdog() {
- if (mCurrentOperation == null) {
+ final BiometricSchedulerOperation operation = mCurrentOperation;
+ if (operation == null) {
+ Slog.e(TAG, "Current operation is null,no need to start watchdog");
return;
}
- final BiometricSchedulerOperation operation = mCurrentOperation;
mHandler.postDelayed(() -> {
if (operation == mCurrentOperation && !operation.isFinished()) {
Counter.logIncrement("biometric.value_scheduler_watchdog_triggered_count");
diff --git a/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java b/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
index eed2bddb0312..958ab8ee0b6a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
+++ b/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
@@ -18,6 +18,8 @@ package com.android.server.biometrics.sensors;
import android.util.SparseArray;
+import java.util.concurrent.ConcurrentHashMap;
+
/**
* Tracks biometric performance across sensors and users.
*/
@@ -25,17 +27,12 @@ public class PerformanceTracker {
private static final String TAG = "PerformanceTracker";
// Keyed by SensorId
- private static SparseArray<PerformanceTracker> sTrackers;
+ private static final ConcurrentHashMap<Integer, PerformanceTracker> sTrackers =
+ new ConcurrentHashMap<>();
public static PerformanceTracker getInstanceForSensorId(int sensorId) {
- if (sTrackers == null) {
- sTrackers = new SparseArray<>();
- }
-
- if (!sTrackers.contains(sensorId)) {
- sTrackers.put(sensorId, new PerformanceTracker());
- }
- return sTrackers.get(sensorId);
+ PerformanceTracker tracker = sTrackers.putIfAbsent(sensorId, new PerformanceTracker());
+ return tracker != null ? tracker : sTrackers.get(sensorId);
}
private static class Info {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 36e4a7e6a7ef..944e85cc970e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -851,13 +851,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
for (int i = 0; i < mFaceSensors.size(); i++) {
final Sensor sensor = mFaceSensors.valueAt(i);
final int sensorId = mFaceSensors.keyAt(i);
- final PerformanceTracker performanceTracker = PerformanceTracker.getInstanceForSensorId(
- sensorId);
- if (performanceTracker != null) {
- performanceTracker.incrementHALDeathCount();
- } else {
- Slog.w(getTag(), "Performance tracker is null. Not counting HAL death.");
- }
+ PerformanceTracker.getInstanceForSensorId(sensorId)
+ .incrementHALDeathCount();
sensor.onBinderDied();
}
});
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index eeac26031719..6feae34f1a2d 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -522,7 +522,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
// b/282922910 - we don't want apps sharing system uid and targeting
// older target sdk to impact all system uid apps
if (Flags.systemUidTargetSystemSdk() && !mIsWear &&
- uid == Process.SYSTEM_UID) {
+ uid == Process.SYSTEM_UID && appInfo != null) {
appInfo.targetSdkVersion = Build.VERSION.SDK_INT;
}
return appInfo;
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java b/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
index 8e725465ddd6..eef2b15c3387 100644
--- a/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
+++ b/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
@@ -93,7 +93,8 @@ public final class CrashRecoveryHelper {
return;
}
final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
- PackageWatchdog.getInstance(mContext).onPackageFailure(pkgList, PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+ PackageWatchdog.getInstance(mContext).notifyPackageFailure(pkgList,
+ PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
});
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 448c42b71731..805357e79565 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -1280,7 +1280,7 @@ public class AutomaticBrightnessController {
private boolean shouldApplyDozeScaleFactor() {
// We don't apply the doze scale factor if we have a designated brightness curve for doze.
- return (mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled()
+ return (mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)
? (!mUseNormalBrightnessForDoze && mDisplayPolicy == POLICY_DOZE)
|| Display.isDozeState(mDisplayState) : Display.isDozeState(mDisplayState))
&& getMode() != AUTO_BRIGHTNESS_MODE_DOZE;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index d2c044fdbb5e..1c1bdad01034 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -311,6 +311,11 @@ final class DisplayDeviceInfo {
*/
public FrameRateCategoryRate frameRateCategoryRate;
/**
+ * All the refresh rates supported for the default display mode.
+ */
+ public float[] supportedRefreshRates = new float[0];
+
+ /**
* The default mode of the display.
*/
public int defaultModeId;
@@ -562,7 +567,8 @@ final class DisplayDeviceInfo {
|| installOrientation != other.installOrientation
|| !Objects.equals(displayShape, other.displayShape)
|| hasArrSupport != other.hasArrSupport
- || !Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)) {
+ || !Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)
+ || !Arrays.equals(supportedRefreshRates, other.supportedRefreshRates)) {
diff |= DIFF_OTHER;
}
return diff;
@@ -582,6 +588,7 @@ final class DisplayDeviceInfo {
renderFrameRate = other.renderFrameRate;
hasArrSupport = other.hasArrSupport;
frameRateCategoryRate = other.frameRateCategoryRate;
+ supportedRefreshRates = other.supportedRefreshRates;
defaultModeId = other.defaultModeId;
userPreferredModeId = other.userPreferredModeId;
supportedModes = other.supportedModes;
@@ -628,6 +635,7 @@ final class DisplayDeviceInfo {
sb.append(", renderFrameRate ").append(renderFrameRate);
sb.append(", hasArrSupport ").append(hasArrSupport);
sb.append(", frameRateCategoryRate ").append(frameRateCategoryRate);
+ sb.append(", supportedRefreshRates ").append(Arrays.toString(supportedRefreshRates));
sb.append(", defaultModeId ").append(defaultModeId);
sb.append(", userPreferredModeId ").append(userPreferredModeId);
sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 5a2610b00772..3871f2a57f76 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
+import static android.Manifest.permission.ADD_MIRROR_DISPLAY;
import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
@@ -177,6 +178,7 @@ import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.Layout;
import com.android.server.display.mode.DisplayModeDirector;
import com.android.server.display.notifications.DisplayNotificationManager;
+import com.android.server.display.plugin.PluginManager;
import com.android.server.display.utils.DebugUtils;
import com.android.server.display.utils.SensorUtils;
import com.android.server.input.InputManagerInternal;
@@ -583,6 +585,7 @@ public final class DisplayManagerService extends SystemService {
private final DisplayNotificationManager mDisplayNotificationManager;
private final ExternalDisplayStatsService mExternalDisplayStatsService;
+ private final PluginManager mPluginManager;
// Manages the relative placement of extended displays
@Nullable
@@ -669,6 +672,7 @@ public final class DisplayManagerService extends SystemService {
} else {
mDisplayTopologyCoordinator = null;
}
+ mPluginManager = new PluginManager(mContext, mFlags);
}
public void setupSchedulerPolicies() {
@@ -739,6 +743,7 @@ public final class DisplayManagerService extends SystemService {
mLogicalDisplayMapper.onBootCompleted();
mDisplayNotificationManager.onBootCompleted();
mExternalDisplayPolicy.onBootCompleted();
+ mPluginManager.onBootCompleted();
}
}
@@ -1673,15 +1678,10 @@ public final class DisplayManagerService extends SystemService {
}
private boolean canCreateMirrorDisplays(IVirtualDevice virtualDevice) {
- if (virtualDevice == null) {
- return false;
- }
- try {
- return virtualDevice.canCreateMirrorDisplays();
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to query virtual device for permissions", e);
- return false;
+ if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+ return checkCallingPermission(ADD_MIRROR_DISPLAY, "canCreateMirrorDisplays");
}
+ return virtualDevice != null;
}
private boolean canProjectVideo(IMediaProjection projection) {
@@ -1814,7 +1814,7 @@ public final class DisplayManagerService extends SystemService {
// display.
if (!canProjectVideo(projection) && !canCreateMirrorDisplays(virtualDevice)
&& !hasVideoOutputPermission("createVirtualDisplayInternal")) {
- throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+ throw new SecurityException("Requires ADD_MIRROR_DISPLAY, CAPTURE_VIDEO_OUTPUT or "
+ "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
+ "MediaProjection token in order to create a screen sharing virtual "
+ "display. In order to create a virtual display that does not perform "
@@ -2460,6 +2460,15 @@ public final class DisplayManagerService extends SystemService {
DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED);
}
+ private void handleLogicalDisplayRefreshRateChangedLocked(@NonNull LogicalDisplay display) {
+ sendDisplayEventIfEnabledLocked(display,
+ DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED);
+ }
+
+ private void handleLogicalDisplayStateChangedLocked(@NonNull LogicalDisplay display) {
+ sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED);
+ }
+
private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
mDisplayModeDirector.defaultDisplayDeviceUpdated(display.getPrimaryDisplayDeviceLocked()
.mDisplayDeviceConfig);
@@ -3543,6 +3552,9 @@ public final class DisplayManagerService extends SystemService {
SparseArray<DisplayPowerController> displayPowerControllersLocal = new SparseArray<>();
int displayPowerControllerCount;
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.increaseIndent();
+
synchronized (mSyncRoot) {
brightnessTrackerLocal = mBrightnessTracker;
@@ -3590,9 +3602,6 @@ public final class DisplayManagerService extends SystemService {
pw.println(" Display SdrBrightness=" + brightnessPair.sdrBrightness);
}
- IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.increaseIndent();
-
pw.println();
pw.println("Display Adapters: size=" + mDisplayAdapters.size());
pw.println("------------------------");
@@ -3655,6 +3664,8 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mDisplayTopologyCoordinator.dump(pw);
}
+ pw.println();
+ mPluginManager.dump(ipw);
pw.println();
mFlags.dump(pw);
@@ -3991,6 +4002,12 @@ public final class DisplayManagerService extends SystemService {
case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DISCONNECTED:
handleLogicalDisplayDisconnectedLocked(display);
break;
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED:
+ handleLogicalDisplayRefreshRateChangedLocked(display);
+ break;
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_STATE_CHANGED:
+ handleLogicalDisplayStateChangedLocked(display);
+ break;
}
}
@@ -4198,6 +4215,13 @@ public final class DisplayManagerService extends SystemService {
return (mask
& DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED)
!= 0;
+ case DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+ return (mask
+ & DisplayManagerGlobal
+ .INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE) != 0;
+ case DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED:
+ return (mask & DisplayManagerGlobal
+ .INTERNAL_EVENT_FLAG_DISPLAY_STATE) != 0;
default:
// This should never happen.
Slog.e(TAG, "Unknown display event " + event);
@@ -5261,6 +5285,23 @@ public final class DisplayManagerService extends SystemService {
}
@Override
+ public void setScreenBrightnessOverrideFromWindowManager(
+ SparseArray<DisplayBrightnessOverrideRequest> brightnessOverrides) {
+ SparseArray<DisplayPowerController> dpcs = new SparseArray<>();
+ synchronized (mSyncRoot) {
+ for (int i = 0; i < mDisplayPowerControllers.size(); i++) {
+ dpcs.put(mDisplayPowerControllers.keyAt(i),
+ mDisplayPowerControllers.valueAt(i));
+ }
+ }
+ for (int i = 0; i < dpcs.size(); ++i) {
+ final int displayId = dpcs.keyAt(i);
+ final DisplayPowerController dpc = dpcs.valueAt(i);
+ dpc.setBrightnessOverrideRequest(brightnessOverrides.get(displayId));
+ }
+ }
+
+ @Override
public boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index c90dfbf5456e..945365dcf8fe 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -42,6 +42,7 @@ import android.hardware.display.AmbientBrightnessDayStats;
import android.hardware.display.BrightnessChangeEvent;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
@@ -170,6 +171,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static final int MSG_OFFLOADING_SCREEN_ON_UNBLOCKED = 18;
private static final int MSG_SET_STYLUS_BEING_USED = 19;
private static final int MSG_SET_STYLUS_USE_ENDED = 20;
+ private static final int MSG_SET_WINDOW_MANAGER_BRIGHTNESS_OVERRIDE = 21;
private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500;
@@ -850,6 +852,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
+ public void setBrightnessOverrideRequest(
+ DisplayManagerInternal.DisplayBrightnessOverrideRequest request) {
+ Message msg = mHandler.obtainMessage(MSG_SET_WINDOW_MANAGER_BRIGHTNESS_OVERRIDE, request);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
+ }
+
public void setDisplayOffloadSession(DisplayOffloadSession session) {
if (session == mDisplayOffloadSession) {
return;
@@ -1391,7 +1399,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Use doze brightness if one of following is true:
// 1. The target `state` isDozeState.
// 2. Doze power request(POLICY_DOZE) if there's no exception(useNormalBrightnessForDoze).
- final boolean useDozeBrightness = mFlags.isNormalBrightnessForDozeParameterEnabled()
+ final boolean useDozeBrightness = mFlags.isNormalBrightnessForDozeParameterEnabled(mContext)
? (!mPowerRequest.useNormalBrightnessForDoze && mPowerRequest.policy == POLICY_DOZE)
|| Display.isDozeState(state) : Display.isDozeState(state);
DisplayBrightnessState displayBrightnessState =
@@ -3100,6 +3108,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
updatePowerState();
break;
+ case MSG_SET_WINDOW_MANAGER_BRIGHTNESS_OVERRIDE:
+ if (mDisplayBrightnessController.updateWindowManagerBrightnessOverride(
+ (DisplayManagerInternal.DisplayBrightnessOverrideRequest) msg.obj)) {
+ updatePowerState();
+ }
+ break;
+
case MSG_STOP:
cleanupHandlerThreadAfterStop();
break;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index a4bb8c348d3f..0b8f7d5ef2cf 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -249,6 +249,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private int mActiveColorMode;
private boolean mHasArrSupport;
private FrameRateCategoryRate mFrameRateCategoryRate;
+ private float[] mSupportedRefreshRates = new float[0];
private Display.HdrCapabilities mHdrCapabilities;
private boolean mAllmSupported;
private boolean mGameContentTypeSupported;
@@ -316,6 +317,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported);
changed |= updateHasArrSupportLocked(dynamicInfo.hasArrSupport);
changed |= updateFrameRateCategoryRatesLocked(dynamicInfo.frameRateCategoryRate);
+ changed |= updateSupportedRefreshatesLocked(dynamicInfo.supportedRefreshRates);
if (changed) {
mHavePendingChanges = true;
@@ -624,6 +626,20 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
+ private boolean updateSupportedRefreshatesLocked(float[] supportedRefreshRates) {
+ if (!getFeatureFlags().enableGetSupportedRefreshRates()) {
+ return false;
+ }
+ if (supportedRefreshRates == null) {
+ return false;
+ }
+ if (Arrays.equals(mSupportedRefreshRates, supportedRefreshRates)) {
+ return false;
+ }
+ mSupportedRefreshRates = supportedRefreshRates;
+ return true;
+ }
+
private boolean updateAllmSupport(boolean supported) {
if (mAllmSupported == supported) {
return false;
@@ -708,6 +724,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.hdrCapabilities = mHdrCapabilities;
mInfo.hasArrSupport = mHasArrSupport;
mInfo.frameRateCategoryRate = mFrameRateCategoryRate;
+ mInfo.supportedRefreshRates = mSupportedRefreshRates;
mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
mInfo.state = mState;
@@ -1299,6 +1316,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mDefaultModeId=" + mDefaultModeId);
pw.println("mUserPreferredModeId=" + mUserPreferredModeId);
pw.println("mHasArrSupport=" + mHasArrSupport);
+ pw.println("mSupportedRefreshRates=" + Arrays.toString(mSupportedRefreshRates));
pw.println("mState=" + Display.stateToString(mState));
pw.println("mCommittedState=" + Display.stateToString(mCommittedState));
pw.println("mBrightnessState=" + mBrightnessState);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 7cfdcafcb610..85465981c473 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -508,6 +508,8 @@ final class LogicalDisplay {
mBaseDisplayInfo.renderFrameRate = deviceInfo.renderFrameRate;
mBaseDisplayInfo.hasArrSupport = deviceInfo.hasArrSupport;
mBaseDisplayInfo.frameRateCategoryRate = deviceInfo.frameRateCategoryRate;
+ mBaseDisplayInfo.supportedRefreshRates = Arrays.copyOf(
+ deviceInfo.supportedRefreshRates, deviceInfo.supportedRefreshRates.length);
mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
mBaseDisplayInfo.userPreferredModeId = deviceInfo.userPreferredModeId;
mBaseDisplayInfo.supportedModes = Arrays.copyOf(
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 09fa4e6aa628..c0903a9bafac 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -79,15 +79,18 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
// 'adb shell setprop persist.log.tag.LogicalDisplayMapper DEBUG && adb reboot'
private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
- public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1;
- public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2;
- public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3;
- public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
- public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
- public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6;
- public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 7;
- public static final int LOGICAL_DISPLAY_EVENT_CONNECTED = 8;
- public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 9;
+ public static final int LOGICAL_DISPLAY_EVENT_BASE = 0;
+ public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1 << 0;
+ public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 1 << 1;
+ public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 1 << 2;
+ public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 1 << 3;
+ public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 1 << 4;
+ public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 1 << 5;
+ public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 1 << 6;
+ public static final int LOGICAL_DISPLAY_EVENT_CONNECTED = 1 << 7;
+ public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 1 << 8;
+ public static final int LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED = 1 << 9;
+ public static final int LOGICAL_DISPLAY_EVENT_STATE_CHANGED = 1 << 10;
public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
@@ -804,6 +807,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW;
final boolean wasPreviouslyEnabled = mDisplaysEnabledCache.get(displayId);
final boolean isCurrentlyEnabled = display.isEnabledLocked();
+ int logicalDisplayEventMask = mLogicalDisplaysToUpdate
+ .get(displayId, LOGICAL_DISPLAY_EVENT_BASE);
// The display is no longer valid and needs to be removed.
if (!display.isValidLocked()) {
@@ -821,20 +826,20 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
if (mDisplaysEnabledCache.get(displayId)) {
// We still need to send LOGICAL_DISPLAY_EVENT_DISCONNECTED
reloop = true;
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED;
} else {
mUpdatedLogicalDisplays.delete(displayId);
- mLogicalDisplaysToUpdate.put(displayId,
- LOGICAL_DISPLAY_EVENT_DISCONNECTED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DISCONNECTED;
}
} else {
mUpdatedLogicalDisplays.delete(displayId);
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED;
}
} else {
// This display never left this class, safe to remove without notification
mLogicalDisplays.removeAt(i);
}
+ mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask);
continue;
// The display is new.
@@ -842,38 +847,40 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
if (mFlags.isConnectedDisplayManagementEnabled()) {
// We still need to send LOGICAL_DISPLAY_EVENT_ADDED
reloop = true;
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CONNECTED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CONNECTED;
} else {
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_ADDED;
}
// Underlying displays device has changed to a different one.
} else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) {
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_SWAPPED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_SWAPPED;
// Something about the display device has changed.
} else if (mFlags.isConnectedDisplayManagementEnabled()
&& wasPreviouslyEnabled != isCurrentlyEnabled) {
int event = isCurrentlyEnabled ? LOGICAL_DISPLAY_EVENT_ADDED :
LOGICAL_DISPLAY_EVENT_REMOVED;
- mLogicalDisplaysToUpdate.put(displayId, event);
+ logicalDisplayEventMask |= event;
} else if (wasDirty || !mTempDisplayInfo.equals(newDisplayInfo)) {
// If only the hdr/sdr ratio changed, then send just the event for that case
if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) {
- mLogicalDisplaysToUpdate.put(displayId,
- LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED;
} else {
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CHANGED;
}
- // The display is involved in a display layout transition
+ if (mFlags.isDisplayListenerPerformanceImprovementsEnabled()) {
+ logicalDisplayEventMask
+ |= updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo);
+ }
+
+ // The display is involved in a display layout transition
} else if (updateState == UPDATE_STATE_TRANSITION) {
- mLogicalDisplaysToUpdate.put(displayId,
- LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION;
// Display frame rate overrides changed.
} else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
- mLogicalDisplaysToUpdate.put(
- displayId, LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED;
// Non-override display values changed.
} else {
@@ -882,10 +889,10 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
// things like display cutouts.
display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+ logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CHANGED;
}
}
-
+ mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask);
mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED);
}
@@ -922,6 +929,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED);
}
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED);
+ sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED);
+ sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_STATE_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
if (mFlags.isConnectedDisplayManagementEnabled()) {
@@ -944,13 +953,25 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
}
}
+ @VisibleForTesting
+ int updateAndGetMaskForDisplayPropertyChanges(DisplayInfo newDisplayInfo) {
+ int mask = LOGICAL_DISPLAY_EVENT_BASE;
+ if (mTempDisplayInfo.getRefreshRate() != newDisplayInfo.getRefreshRate()) {
+ mask |= LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED;
+ }
+
+ if (mTempDisplayInfo.state != newDisplayInfo.state) {
+ mask |= LOGICAL_DISPLAY_EVENT_STATE_CHANGED;
+ }
+ return mask;
+ }
/**
* Send the specified message for all relevant displays in the specified display-to-message map.
*/
- private void sendUpdatesForDisplaysLocked(int msg) {
+ private void sendUpdatesForDisplaysLocked(int logicalDisplayEvent) {
for (int i = mLogicalDisplaysToUpdate.size() - 1; i >= 0; --i) {
- final int currMsg = mLogicalDisplaysToUpdate.valueAt(i);
- if (currMsg != msg) {
+ final int logicalDisplayEventMask = mLogicalDisplaysToUpdate.valueAt(i);
+ if ((logicalDisplayEventMask & logicalDisplayEvent) == 0) {
continue;
}
@@ -959,25 +980,25 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
if (DEBUG) {
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
final String uniqueId = device == null ? "null" : device.getUniqueId();
- Slog.d(TAG, "Sending " + displayEventToString(msg) + " for display=" + id
- + " with device=" + uniqueId);
+ Slog.d(TAG, "Sending " + displayEventToString(logicalDisplayEvent) + " for "
+ + "display=" + id + " with device=" + uniqueId);
}
if (mFlags.isConnectedDisplayManagementEnabled()) {
- if (msg == LOGICAL_DISPLAY_EVENT_ADDED) {
+ if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_ADDED) {
mDisplaysEnabledCache.put(id, true);
- } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) {
+ } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) {
mDisplaysEnabledCache.delete(id);
}
}
- mListener.onLogicalDisplayEventLocked(display, msg);
+ mListener.onLogicalDisplayEventLocked(display, logicalDisplayEvent);
if (mFlags.isConnectedDisplayManagementEnabled()) {
- if (msg == LOGICAL_DISPLAY_EVENT_DISCONNECTED) {
+ if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_DISCONNECTED) {
mLogicalDisplays.delete(id);
}
- } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) {
+ } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) {
// We wait until we sent the EVENT_REMOVED event before actually removing the
// display.
mLogicalDisplays.delete(id);
@@ -1348,6 +1369,10 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
return "connected";
case LOGICAL_DISPLAY_EVENT_DISCONNECTED:
return "disconnected";
+ case LOGICAL_DISPLAY_EVENT_STATE_CHANGED:
+ return "state_changed";
+ case LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED:
+ return "refresh_rate_changed";
}
return null;
}
diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS
index 9439eaa3a4c6..9f0cabfd9208 100644
--- a/services/core/java/com/android/server/display/OWNERS
+++ b/services/core/java/com/android/server/display/OWNERS
@@ -1,5 +1,4 @@
michaelwr@google.com
-dangittik@google.com
hackbod@google.com
ogunwale@google.com
santoscordon@google.com
@@ -7,5 +6,6 @@ flc@google.com
wilczynskip@google.com
brup@google.com
petsjonkin@google.com
+olb@google.com
per-file ColorDisplayService.java=christyfranks@google.com
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 5b12dfb951d5..35f6fd047ec6 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -180,6 +180,20 @@ public final class DisplayBrightnessController {
}
/**
+ * Updates the brightness override from WindowManager.
+ *
+ * @param request The request to override the brightness
+ * @return whether this request will result in a change of the brightness
+ */
+ public boolean updateWindowManagerBrightnessOverride(
+ DisplayManagerInternal.DisplayBrightnessOverrideRequest request) {
+ synchronized (mLock) {
+ return mDisplayBrightnessStrategySelector.getOverrideBrightnessStrategy()
+ .updateWindowManagerBrightnessOverride(request);
+ }
+ }
+
+ /**
* Sets the brightness to follow
*/
public void setBrightnessToFollow(float brightnessToFollow, boolean slowChange) {
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 60c1b8ff4db9..2c6f37448735 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -109,6 +109,8 @@ public class DisplayBrightnessStrategySelector {
private final int mDisplayId;
+ private final Context mContext;
+
/**
* The constructor of DozeBrightnessStrategy.
*/
@@ -117,6 +119,7 @@ public class DisplayBrightnessStrategySelector {
if (injector == null) {
injector = new Injector();
}
+ mContext = context;
mDisplayManagerFlags = flags;
mDisplayId = displayId;
mDozeBrightnessStrategy = injector.getDozeBrightnessStrategy();
@@ -180,8 +183,10 @@ public class DisplayBrightnessStrategySelector {
displayBrightnessStrategy = mFollowerBrightnessStrategy;
} else if (displayPowerRequest.boostScreenBrightness) {
displayBrightnessStrategy = mBoostBrightnessStrategy;
- } else if (BrightnessUtils
- .isValidBrightnessValue(displayPowerRequest.screenBrightnessOverride)) {
+ } else if (BrightnessUtils.isValidBrightnessValue(
+ displayPowerRequest.screenBrightnessOverride)
+ || BrightnessUtils.isValidBrightnessValue(
+ mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())) {
displayBrightnessStrategy = mOverrideBrightnessStrategy;
} else if (BrightnessUtils.isValidBrightnessValue(
mTemporaryBrightnessStrategy.getTemporaryScreenBrightness())) {
@@ -256,6 +261,10 @@ public class DisplayBrightnessStrategySelector {
return mAutoBrightnessFallbackStrategy;
}
+ public OverrideBrightnessStrategy getOverrideBrightnessStrategy() {
+ return mOverrideBrightnessStrategy;
+ }
+
/**
* Dumps the state of this class.
*/
@@ -342,7 +351,7 @@ public class DisplayBrightnessStrategySelector {
// a user can define a different display state(displayPowerRequest.dozeScreenState) too
// in the request with the Doze policy and user might request an override to force certain
// brightness.
- return (!mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled()
+ return (!mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)
|| !displayPowerRequest.useNormalBrightnessForDoze)
&& displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
&& !mAllowAutoBrightnessWhileDozing
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index ff73693d803b..94522d197429 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -525,7 +525,7 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2
}
final boolean shouldUseDozeMode =
- mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled()
+ mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)
? (!useNormalBrightnessForDoze && policy == POLICY_DOZE)
|| Display.isDozeState(state)
: Display.isDozeState(state);
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
index 3fc15d120434..649f9dacf8ab 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
@@ -16,10 +16,13 @@
package com.android.server.display.brightness.strategy;
+import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.PowerManager;
import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.BrightnessUtils;
import com.android.server.display.brightness.StrategyExecutionRequest;
import com.android.server.display.brightness.StrategySelectionNotifyRequest;
@@ -29,6 +32,10 @@ import java.io.PrintWriter;
* Manages the brightness of the display when the system brightness is overridden
*/
public class OverrideBrightnessStrategy implements DisplayBrightnessStrategy {
+
+ private float mWindowManagerBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ private CharSequence mWindowManagerBrightnessOverrideTag = null;
+
@Override
public DisplayBrightnessState updateBrightness(
StrategyExecutionRequest strategyExecutionRequest) {
@@ -36,9 +43,18 @@ public class OverrideBrightnessStrategy implements DisplayBrightnessStrategy {
// the brightness
DisplayPowerRequest dpr = strategyExecutionRequest.getDisplayPowerRequest();
BrightnessReason reason = new BrightnessReason(BrightnessReason.REASON_OVERRIDE);
- reason.setTag(dpr.screenBrightnessOverrideTag);
+
+ float brightness = dpr.screenBrightnessOverride;
+ if (BrightnessUtils.isValidBrightnessValue(dpr.screenBrightnessOverride)) {
+ brightness = dpr.screenBrightnessOverride;
+ reason.setTag(dpr.screenBrightnessOverrideTag);
+ } else if (BrightnessUtils.isValidBrightnessValue(mWindowManagerBrightnessOverride)) {
+ brightness = mWindowManagerBrightnessOverride;
+ reason.setTag(mWindowManagerBrightnessOverrideTag);
+ }
+
return new DisplayBrightnessState.Builder()
- .setBrightness(dpr.screenBrightnessOverride)
+ .setBrightness(brightness)
.setBrightnessReason(reason)
.setDisplayBrightnessStrategyName(getName())
.build();
@@ -50,7 +66,12 @@ public class OverrideBrightnessStrategy implements DisplayBrightnessStrategy {
}
@Override
- public void dump(PrintWriter writer) {}
+ public void dump(PrintWriter writer) {
+ writer.println("OverrideBrightnessStrategy:");
+ writer.println(" mWindowManagerBrightnessOverride=" + mWindowManagerBrightnessOverride);
+ writer.println(" mWindowManagerBrightnessOverrideTag="
+ + mWindowManagerBrightnessOverrideTag);
+ }
@Override
public void strategySelectionPostProcessor(
@@ -58,6 +79,37 @@ public class OverrideBrightnessStrategy implements DisplayBrightnessStrategy {
// DO NOTHING
}
+ /**
+ * Updates the brightness override from WindowManager.
+ *
+ * @param request The request to override the brightness
+ * @return whether this request will result in a change of the brightness
+ */
+ public boolean updateWindowManagerBrightnessOverride(
+ DisplayManagerInternal.DisplayBrightnessOverrideRequest request) {
+ float newBrightness = request == null
+ ? PowerManager.BRIGHTNESS_INVALID_FLOAT : request.brightness;
+ mWindowManagerBrightnessOverrideTag = request == null ? null : request.tag;
+
+ if (floatEquals(newBrightness, mWindowManagerBrightnessOverride)) {
+ return false;
+ }
+
+ mWindowManagerBrightnessOverride = newBrightness;
+ return true;
+ }
+
+ /**
+ * Returns the current brightness override from WindowManager.
+ */
+ public float getWindowManagerBrightnessOverride() {
+ return mWindowManagerBrightnessOverride;
+ }
+
+ private boolean floatEquals(float f1, float f2) {
+ return f1 == f2 || (Float.isNaN(f1) && Float.isNaN(f2));
+ }
+
@Override
public int getReason() {
return BrightnessReason.REASON_OVERRIDE;
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index 716661dd6c3c..68dc80fa51c8 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -19,6 +19,7 @@ package com.android.server.display.color;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
@@ -29,23 +30,33 @@ abstract class TintController {
*/
private static final long TRANSITION_DURATION = 3000L;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
private ValueAnimator mAnimator;
+ @GuardedBy("mLock")
private Boolean mIsActivated;
public ValueAnimator getAnimator() {
- return mAnimator;
+ synchronized (mLock) {
+ return mAnimator;
+ }
}
public void setAnimator(ValueAnimator animator) {
- mAnimator = animator;
+ synchronized (mLock) {
+ mAnimator = animator;
+ }
}
/**
* Cancel the animator if it's still running.
*/
public void cancelAnimator() {
- if (mAnimator != null) {
- mAnimator.cancel();
+ synchronized (mLock) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
}
}
@@ -53,22 +64,30 @@ abstract class TintController {
* End the animator if it's still running, jumping to the end state.
*/
public void endAnimator() {
- if (mAnimator != null) {
- mAnimator.end();
- mAnimator = null;
+ synchronized (mLock) {
+ if (mAnimator != null) {
+ mAnimator.end();
+ mAnimator = null;
+ }
}
}
public void setActivated(Boolean isActivated) {
- mIsActivated = isActivated;
+ synchronized (mLock) {
+ mIsActivated = isActivated;
+ }
}
public boolean isActivated() {
- return mIsActivated != null && mIsActivated;
+ synchronized (mLock) {
+ return mIsActivated != null && mIsActivated;
+ }
}
public boolean isActivatedStateNotSet() {
- return mIsActivated == null;
+ synchronized (mLock) {
+ return mIsActivated == null;
+ }
}
public long getTransitionDurationMilliseconds() {
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 71f17d1f411e..e273c6862fe0 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -16,6 +16,7 @@
package com.android.server.display.feature;
+import android.content.Context;
import android.os.Build;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -242,10 +243,19 @@ public class DisplayManagerFlags {
Flags::autoBrightnessModeBedtimeWear
);
+ private final FlagState mGetSupportedRefreshRatesFlagState = new FlagState(
+ Flags.FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES,
+ Flags::enableGetSupportedRefreshRates
+ );
+
private final FlagState mEnablePluginManagerFlagState = new FlagState(
Flags.FLAG_ENABLE_PLUGIN_MANAGER,
Flags::enablePluginManager
);
+ private final FlagState mDisplayListenerPerformanceImprovementsFlagState = new FlagState(
+ Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS,
+ Flags::displayListenerPerformanceImprovements
+ );
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
@@ -457,8 +467,9 @@ public class DisplayManagerFlags {
/**
* @return Whether the useDozeBrightness parameter should be used
*/
- public boolean isNormalBrightnessForDozeParameterEnabled() {
- return mNormalBrightnessForDozeParameter.isEnabled();
+ public boolean isNormalBrightnessForDozeParameterEnabled(Context context) {
+ return mNormalBrightnessForDozeParameter.isEnabled() && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowNormalBrightnessForDozePolicy);
}
/**
@@ -522,11 +533,25 @@ public class DisplayManagerFlags {
return mAutoBrightnessModeBedtimeWearFlagState.isEnabled();
}
+ /**
+ * @return {@code true} if supported refresh rate api is enabled.
+ */
+ public boolean enableGetSupportedRefreshRates() {
+ return mGetSupportedRefreshRatesFlagState.isEnabled();
+ }
+
public boolean isPluginManagerEnabled() {
return mEnablePluginManagerFlagState.isEnabled();
}
/**
+ * @return {@code true} if the flag for display listener performance improvements is enabled
+ */
+ public boolean isDisplayListenerPerformanceImprovementsEnabled() {
+ return mDisplayListenerPerformanceImprovementsFlagState.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -577,7 +602,9 @@ public class DisplayManagerFlags {
pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled);
pw.println(" " + mHasArrSupport);
pw.println(" " + mAutoBrightnessModeBedtimeWearFlagState);
+ pw.println(" " + mGetSupportedRefreshRatesFlagState);
pw.println(" " + mEnablePluginManagerFlagState);
+ pw.println(" " + mDisplayListenerPerformanceImprovementsFlagState);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 7850360c7dbf..e7ea868ca04f 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -4,6 +4,14 @@ container: "system"
# Important: Flags must be accessed through DisplayManagerFlags.
flag {
+ name: "is_always_on_available_api"
+ namespace: "display_manager"
+ description: "Allows querying of AOD availability"
+ bug: "324046664"
+ is_fixed_read_only: true
+}
+
+flag {
name: "enable_port_in_display_layout"
namespace: "display_manager"
description: "Allows refering to displays by port in display layout"
@@ -440,6 +448,14 @@ flag {
}
flag {
+ name: "display_listener_performance_improvements"
+ namespace: "display_manager"
+ description: "Feature flag for an API to let the apps subscribe to a specific property change of the Display."
+ bug: "372700957"
+ is_fixed_read_only: true
+}
+
+flag {
name: "enable_get_supported_refresh_rates"
namespace: "core_graphics"
description: "Flag to use the surfaceflinger rates for getSupportedRefreshRates"
@@ -454,3 +470,11 @@ flag {
bug: "354059797"
is_fixed_read_only: true
}
+
+flag {
+ name: "enable_display_content_mode_management"
+ namespace: "lse_desktop_experience"
+ description: "Enable switching the content mode of connected displays between mirroring and extened. Also change the default content mode to extended mode."
+ bug: "378385869"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/SystemRequestObserver.java b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
index 15f19cca99db..4a4c8da1a335 100644
--- a/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
+++ b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -28,12 +29,15 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
/**
* SystemRequestObserver responsible for handling system requests to filter allowable display
* modes
*/
class SystemRequestObserver {
+ private static final String TAG = "SystemRequestObserver";
+
private final VotesStorage mVotesStorage;
private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@@ -43,6 +47,7 @@ class SystemRequestObserver {
}
@Override
public void binderDied(@NonNull IBinder who) {
+ Slog.d(TAG, "binder died: " + who);
removeSystemRequestedVotes(who);
who.unlinkToDeath(mDeathRecipient, 0);
}
@@ -83,9 +88,11 @@ class SystemRequestObserver {
updateStorageLocked(displayId);
}
if (needLinkToDeath) {
+ Slog.d(TAG, "binder linking to death: " + token);
token.linkToDeath(mDeathRecipient, 0);
}
} catch (RemoteException re) {
+ Slog.d(TAG, "linking to death failed: " + token, re);
removeSystemRequestedVotes(token);
}
}
@@ -94,14 +101,19 @@ class SystemRequestObserver {
boolean needToUnlink = false;
synchronized (mLock) {
SparseArray<List<Integer>> modesByDisplay = mDisplaysRestrictions.get(token);
- if (modesByDisplay != null) {
+ if (modesByDisplay != null && modesByDisplay.size() > 0) {
modesByDisplay.remove(displayId);
needToUnlink = modesByDisplay.size() == 0;
updateStorageLocked(displayId);
}
}
if (needToUnlink) {
- token.unlinkToDeath(mDeathRecipient, 0);
+ try {
+ Slog.d(TAG, "binder unlinking to death: " + token);
+ token.unlinkToDeath(mDeathRecipient, 0);
+ } catch (NoSuchElementException e) {
+ Slog.d(TAG, "unlinking to death failed: " + token, e);
+ }
}
}
diff --git a/services/core/java/com/android/server/display/plugin/Plugin.java b/services/core/java/com/android/server/display/plugin/Plugin.java
new file mode 100644
index 000000000000..1bef4641b9ad
--- /dev/null
+++ b/services/core/java/com/android/server/display/plugin/Plugin.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.plugin;
+
+import com.android.tools.r8.keepanno.annotations.KeepForApi;
+
+import java.io.PrintWriter;
+
+/**
+ * Interface that OEMs should implement in order to inject custom code to system process.
+ * Communication between OEM Plugin and Framework is implemented via {@link PluginStorage}.
+ * OEM Plugin pushes values to PluginStorage, that are picked up by
+ * {@link PluginManager.PluginChangeListener}, implemented on Framework side.
+ * Avoid calling heavy operations in constructor - it will be called during boot and will
+ * negatively impact boot time. Use onBootComplete and separate thread for long running operations.
+ */
+@KeepForApi
+public interface Plugin {
+
+ /**
+ * Called when device boot completed
+ */
+ void onBootCompleted();
+
+ /**
+ * Print the object's state and debug information into the given stream.
+ */
+ void dump(PrintWriter pw);
+}
+
diff --git a/services/core/java/com/android/server/display/plugin/PluginManager.java b/services/core/java/com/android/server/display/plugin/PluginManager.java
new file mode 100644
index 000000000000..d4099975cafa
--- /dev/null
+++ b/services/core/java/com/android/server/display/plugin/PluginManager.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.plugin;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SystemServerClassLoaderFactory;
+import com.android.server.display.feature.DisplayManagerFlags;
+
+import dalvik.system.PathClassLoader;
+
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Responsible for loading Plugins. Plugins and PluginSupplier are loaded from
+ * standalone system jar.
+ * Plugin manager will look for PROVIDER_IMPL_CLASS in configured jar.
+ * After device booted, PluginManager will delegate this call to each Plugin
+ */
+public class PluginManager {
+ private static final String PROVIDER_IMPL_CLASS =
+ "com.android.server.display.plugin.PluginsProviderImpl";
+ private static final String TAG = "PluginManager";
+
+ private final DisplayManagerFlags mFlags;
+ private final PluginStorage mPluginStorage;
+ private final List<Plugin> mPlugins;
+
+ public PluginManager(Context context, DisplayManagerFlags flags) {
+ this(context, flags, new Injector());
+ }
+
+ @VisibleForTesting
+ PluginManager(Context context, DisplayManagerFlags flags, Injector injector) {
+ mFlags = flags;
+ mPluginStorage = injector.getPluginStorage();
+ if (mFlags.isPluginManagerEnabled()) {
+ mPlugins = Collections.unmodifiableList(injector.loadPlugins(context, mPluginStorage));
+ Slog.d(TAG, "loaded Plugins:" + mPlugins);
+ } else {
+ mPlugins = List.of();
+ Slog.d(TAG, "PluginManager disabled");
+ }
+ }
+
+ /**
+ * Forwards boot completed event to Plugins
+ */
+ public void onBootCompleted() {
+ mPlugins.forEach(Plugin::onBootCompleted);
+ }
+
+ /**
+ * Adds change listener for particular plugin type
+ */
+ public <T> void subscribe(PluginType<T> type, PluginChangeListener<T> listener) {
+ mPluginStorage.addListener(type, listener);
+ }
+
+ /**
+ * Removes change listener
+ */
+ public <T> void unsubscribe(PluginType<T> type, PluginChangeListener<T> listener) {
+ mPluginStorage.removeListener(type, listener);
+ }
+
+ /**
+ * Print the object's state and debug information into the given stream.
+ */
+ public void dump(PrintWriter pw) {
+ pw.println("PluginManager:");
+ mPluginStorage.dump(pw);
+ for (Plugin plugin : mPlugins) {
+ plugin.dump(pw);
+ }
+ }
+
+ /**
+ * Listens for changes in PluginStorage for a particular type
+ * @param <T> plugin value type
+ */
+ public interface PluginChangeListener<T> {
+ /**
+ * Called when Plugin value changed
+ */
+ void onChanged(@Nullable T value);
+ }
+
+ static class Injector {
+ PluginStorage getPluginStorage() {
+ return new PluginStorage();
+ }
+
+ List<Plugin> loadPlugins(Context context, PluginStorage storage) {
+ String providerJarPath = context
+ .getString(com.android.internal.R.string.config_pluginsProviderJarPath);
+ Slog.d(TAG, "loading plugins from:" + providerJarPath);
+ if (TextUtils.isEmpty(providerJarPath)) {
+ return List.of();
+ }
+ try {
+ PathClassLoader pathClassLoader =
+ SystemServerClassLoaderFactory.getOrCreateClassLoader(
+ providerJarPath, getClass().getClassLoader(), false);
+ @SuppressWarnings("PrivateApi")
+ Class<? extends PluginsProvider> cp = pathClassLoader.loadClass(PROVIDER_IMPL_CLASS)
+ .asSubclass(PluginsProvider.class);
+ PluginsProvider provider = cp.getDeclaredConstructor().newInstance();
+ return provider.getPlugins(context, storage);
+ } catch (ClassNotFoundException e) {
+ Slog.e(TAG, "loading failed: " + PROVIDER_IMPL_CLASS + " is not found in"
+ + providerJarPath, e);
+ } catch (InvocationTargetException | InstantiationException | IllegalAccessException
+ | NoSuchMethodException e) {
+ Slog.e(TAG, "Class instantiation failed", e);
+ }
+ return List.of();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/plugin/PluginStorage.java b/services/core/java/com/android/server/display/plugin/PluginStorage.java
new file mode 100644
index 000000000000..2bcea777e681
--- /dev/null
+++ b/services/core/java/com/android/server/display/plugin/PluginStorage.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.plugin;
+
+import android.annotation.Nullable;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.tools.r8.keepanno.annotations.KeepForApi;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Stores values pushed by Plugins and forwards them to corresponding listener.
+ */
+public class PluginStorage {
+ private static final String TAG = "PluginStorage";
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final Map<PluginType<?>, Object> mValues = new HashMap<>();
+ @GuardedBy("mLock")
+ private final Map<PluginType<?>, ListenersContainer<?>> mListeners = new HashMap<>();
+
+ /**
+ * Updates value in storage and forwards it to corresponding listeners.
+ * Should be called by OEM Plugin implementation in order to provide communicate with Framework
+ */
+ @KeepForApi
+ public <T> void updateValue(PluginType<T> type, @Nullable T value) {
+ Slog.d(TAG, "updateValue, type=" + type.mName + "; value=" + value);
+ Set<PluginManager.PluginChangeListener<T>> localListeners;
+ synchronized (mLock) {
+ mValues.put(type, value);
+ ListenersContainer<T> container = getListenersContainerForTypeLocked(type);
+ localListeners = new LinkedHashSet<>(container.mListeners);
+ }
+ Slog.d(TAG, "updateValue, notifying listeners=" + localListeners);
+ localListeners.forEach(l -> l.onChanged(value));
+ }
+
+ /**
+ * Adds listener for PluginType. If storage already has value for this type, listener will
+ * be notified immediately.
+ */
+ <T> void addListener(PluginType<T> type, PluginManager.PluginChangeListener<T> listener) {
+ T value = null;
+ synchronized (mLock) {
+ ListenersContainer<T> container = getListenersContainerForTypeLocked(type);
+ if (container.mListeners.add(listener)) {
+ value = getValueForTypeLocked(type);
+ }
+ }
+ if (value != null) {
+ listener.onChanged(value);
+ }
+ }
+
+ /**
+ * Removes listener
+ */
+ <T> void removeListener(PluginType<T> type, PluginManager.PluginChangeListener<T> listener) {
+ synchronized (mLock) {
+ ListenersContainer<T> container = getListenersContainerForTypeLocked(type);
+ container.mListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Print the object's state and debug information into the given stream.
+ */
+ void dump(PrintWriter pw) {
+ Map<PluginType<?>, Object> localValues;
+ @SuppressWarnings("rawtypes")
+ Map<PluginType, Set> localListeners = new HashMap<>();
+ synchronized (mLock) {
+ localValues = new HashMap<>(mValues);
+ mListeners.forEach((type, container) -> localListeners.put(type, container.mListeners));
+ }
+ pw.println("PluginStorage:");
+ pw.println("values=" + localValues);
+ pw.println("listeners=" + localListeners);
+ }
+
+ @GuardedBy("mLock")
+ @SuppressWarnings("unchecked")
+ private <T> T getValueForTypeLocked(PluginType<T> type) {
+ Object value = mValues.get(type);
+ if (value == null) {
+ return null;
+ } else if (type.mType == value.getClass()) {
+ return (T) value;
+ } else {
+ Slog.d(TAG, "getValueForType: unexpected value type=" + value.getClass().getName()
+ + ", expected=" + type.mType.getName());
+ return null;
+ }
+ }
+
+ @GuardedBy("mLock")
+ @SuppressWarnings("unchecked")
+ private <T> ListenersContainer<T> getListenersContainerForTypeLocked(PluginType<T> type) {
+ ListenersContainer<?> container = mListeners.get(type);
+ if (container == null) {
+ ListenersContainer<T> lc = new ListenersContainer<>();
+ mListeners.put(type, lc);
+ return lc;
+ } else {
+ return (ListenersContainer<T>) container;
+ }
+ }
+
+ private static final class ListenersContainer<T> {
+ private final Set<PluginManager.PluginChangeListener<T>> mListeners = new LinkedHashSet<>();
+ }
+}
diff --git a/services/core/java/com/android/server/display/plugin/PluginType.java b/services/core/java/com/android/server/display/plugin/PluginType.java
new file mode 100644
index 000000000000..fb60833d259e
--- /dev/null
+++ b/services/core/java/com/android/server/display/plugin/PluginType.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.plugin;
+
+import com.android.internal.annotations.Keep;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Represent customisation entry point to Framework. OEM and Framework team should define
+ * new PluginTypes together, after that, Framework team can integrate listener and OEM team
+ * create Plugin implementation
+ *
+ * @param <T> type of plugin value
+ */
+@Keep
+public class PluginType<T> {
+
+ final Class<T> mType;
+ final String mName;
+
+ @VisibleForTesting
+ PluginType(Class<T> type, String name) {
+ mType = type;
+ mName = name;
+ }
+
+ @Override
+ public String toString() {
+ return "PluginType{"
+ + "mType=" + mType
+ + ", mName=" + mName
+ + '}';
+ }
+}
diff --git a/services/core/java/com/android/server/display/plugin/PluginsProvider.java b/services/core/java/com/android/server/display/plugin/PluginsProvider.java
new file mode 100644
index 000000000000..9ad85f67bc8b
--- /dev/null
+++ b/services/core/java/com/android/server/display/plugin/PluginsProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.plugin;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import com.android.tools.r8.keepanno.annotations.KeepForApi;
+
+import java.util.List;
+
+/**
+ * Interface that OEMs should implement in order to supply Plugins to PluginManager
+ */
+@KeepForApi
+public interface PluginsProvider {
+ /**
+ * Provides list of Plugins to PluginManager
+ */
+ @NonNull
+ List<Plugin> getPlugins(Context context, PluginStorage storage);
+}
diff --git a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
index b0e93989d463..f9a1cebc952f 100644
--- a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
@@ -25,8 +25,8 @@ import com.android.internal.annotations.VisibleForTesting;
* Feature action that sends <Request Active Source> message and waits for <Active Source>.
*
* For TV panels, this action has a delay before sending <Request Active Source>. This is because it
- * should wait for a possible request from LauncherX and can be cancelled if an <Active Source>
- * message was received or the TV switched to another input.
+ * should wait for a possible request from LauncherX or TIF (TV Input Framework) and can be
+ * cancelled if an <Active Source> message was received or the TV switched to another input.
*/
public class RequestActiveSourceAction extends HdmiCecFeatureAction {
private static final String TAG = "RequestActiveSourceAction";
@@ -40,9 +40,9 @@ public class RequestActiveSourceAction extends HdmiCecFeatureAction {
// Number of retries <Request Active Source> is sent if no device answers this message.
private static final int MAX_SEND_RETRY_COUNT = 1;
- // Timeout to wait for the LauncherX API call to be completed.
+ // Timeout to wait for LauncherX or TIF to call the CEC API.
@VisibleForTesting
- protected static final int TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS = 10000;
+ protected static final int TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS = 15000;
private int mSendRetryCount = 0;
@@ -67,7 +67,7 @@ public class RequestActiveSourceAction extends HdmiCecFeatureAction {
// We wait for default timeout to allow the message triggered by the LauncherX API call to
// be sent by the TV and another default timeout in case the message has to be answered
// (e.g. TV sent a <Set Stream Path> or <Routing Change>).
- addTimer(mState, TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS);
+ addTimer(mState, TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS);
return true;
}
diff --git a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
index aef207f9c027..8c028bc92841 100644
--- a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
+++ b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
@@ -21,6 +21,7 @@ import android.annotation.SuppressLint;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
+import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.hardware.input.AppLaunchData;
import android.hardware.input.InputGestureData;
@@ -137,11 +138,19 @@ final class AppLaunchShortcutManager {
String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE);
-
- // TODO(b/358569822): Shift bookmarks to use keycode instead of shortcutChar
- int keycode = KeyEvent.KEYCODE_UNKNOWN;
String shortcut = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
- if (!TextUtils.isEmpty(shortcut)) {
+ int keycode;
+ int modifierState;
+ TypedArray a = mContext.getResources().obtainAttributes(parser,
+ R.styleable.Bookmark);
+ try {
+ keycode = a.getInt(R.styleable.Bookmark_keycode, KeyEvent.KEYCODE_UNKNOWN);
+ modifierState = a.getInt(R.styleable.Bookmark_modifierState, 0);
+ } finally {
+ a.recycle();
+ }
+ if (keycode == KeyEvent.KEYCODE_UNKNOWN && !TextUtils.isEmpty(shortcut)) {
+ // Fetch keycode using shortcut char
KeyEvent[] events = virtualKcm.getEvents(new char[]{shortcut.toLowerCase(
Locale.ROOT).charAt(0)});
// Single key press can generate the character
@@ -153,12 +162,17 @@ final class AppLaunchShortcutManager {
Log.w(TAG, "Keycode required for bookmark with category=" + categoryName
+ " packageName=" + packageName + " className=" + className
+ " role=" + roleName + " shiftName=" + shiftName
- + " shortcut=" + shortcut);
+ + " shortcut=" + shortcut + " modifierState=" + modifierState);
continue;
}
- final boolean isShiftShortcut = (shiftName != null && shiftName.toLowerCase(
- Locale.ROOT).equals("true"));
+ if (modifierState == 0) {
+ // Fetch modifierState using shiftName
+ boolean isShiftShortcut = shiftName != null && shiftName.toLowerCase(
+ Locale.ROOT).equals("true");
+ modifierState =
+ KeyEvent.META_META_ON | (isShiftShortcut ? KeyEvent.META_SHIFT_ON : 0);
+ }
AppLaunchData launchData = null;
if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) {
launchData = AppLaunchData.createLaunchDataForComponent(packageName, className);
@@ -168,11 +182,9 @@ final class AppLaunchShortcutManager {
launchData = AppLaunchData.createLaunchDataForRole(roleName);
}
if (launchData != null) {
- Log.d(TAG, "adding shortcut " + launchData + "shift="
- + isShiftShortcut + " keycode=" + keycode);
+ Log.d(TAG, "adding shortcut " + launchData + " modifierState="
+ + modifierState + " keycode=" + keycode);
// All bookmarks are based on Action key
- int modifierState =
- KeyEvent.META_META_ON | (isShiftShortcut ? KeyEvent.META_SHIFT_ON : 0);
InputGestureData bookmark = new InputGestureData.Builder()
.setTrigger(InputGestureData.createKeyTrigger(keycode, modifierState))
.setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION)
@@ -198,16 +210,16 @@ final class AppLaunchShortcutManager {
/**
* Handle the shortcut to {@link IShortcutService}
- * @param keyCode The key code of the event.
- * @param metaState The meta key modifier state.
- * @return True if invoked the shortcut, otherwise false.
+ * @return true if invoked the shortcut, otherwise false.
*/
- private boolean handleShortcutService(int keyCode, int metaState) {
- final long shortcutCodeMeta = metaState & SHORTCUT_CODE_META_MASK;
+ public boolean handleShortcutService(KeyEvent event) {
+ // TODO(b/358569822): Ideally shortcut service custom shortcuts should be either
+ // migrated to bookmarks or customizable shortcut APIs.
+ final long shortcutCodeMeta = event.getMetaState() & SHORTCUT_CODE_META_MASK;
if (shortcutCodeMeta == 0) {
return false;
}
- long shortcutCode = keyCode | (shortcutCodeMeta << Integer.SIZE);
+ long shortcutCode = event.getKeyCode() | (shortcutCodeMeta << Integer.SIZE);
IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
if (shortcutService != null) {
try {
@@ -280,7 +292,6 @@ final class AppLaunchShortcutManager {
return InterceptKeyResult.DO_NOTHING;
}
- final int metaState = event.getModifiers();
final int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
@@ -301,15 +312,7 @@ final class AppLaunchShortcutManager {
}
// Intercept shortcuts defined in bookmarks or through application launch keycodes
- AppLaunchData appLaunchData = interceptShortcut(event);
-
- // TODO(b/358569822): Ideally shortcut service custom shortcuts should be either
- // migrated to bookmarks or customizable shortcut APIs.
- if (appLaunchData == null && handleShortcutService(keyCode, metaState)) {
- return InterceptKeyResult.CONSUME_KEY;
- }
-
- return new InterceptKeyResult(/* consumed =*/ false, appLaunchData);
+ return new InterceptKeyResult(/* consumed =*/ false, interceptShortcut(event));
}
/**
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index 6f3540221b63..73d563069632 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -228,6 +228,28 @@ final class InputGestureManager {
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK));
}
+ if (enableTaskResizingKeyboardShortcuts()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_LEFT_BRACKET,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW
+ ));
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_RIGHT_BRACKET,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW
+ ));
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_EQUALS,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW
+ ));
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_MINUS,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW
+ ));
+ }
if (keyboardA11yShortcutControl()) {
if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()) {
systemShortcuts.add(createKeyGesture(
@@ -257,28 +279,6 @@ final class InputGestureManager {
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS
));
}
- if (enableTaskResizingKeyboardShortcuts()) {
- systemShortcuts.add(createKeyGesture(
- KeyEvent.KEYCODE_LEFT_BRACKET,
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW
- ));
- systemShortcuts.add(createKeyGesture(
- KeyEvent.KEYCODE_RIGHT_BRACKET,
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW
- ));
- systemShortcuts.add(createKeyGesture(
- KeyEvent.KEYCODE_EQUALS,
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW
- ));
- systemShortcuts.add(createKeyGesture(
- KeyEvent.KEYCODE_MINUS,
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE
- ));
- }
}
synchronized (mGestureLock) {
for (InputGestureData systemShortcut : systemShortcuts) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index f4dd71706761..1adf1c99024a 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.input;
import static android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW;
import static android.content.PermissionChecker.PERMISSION_GRANTED;
import static android.content.PermissionChecker.PID_UNKNOWN;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.provider.DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT;
import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -136,6 +137,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.input.InputManagerInternal.LidSwitchCallback;
import com.android.server.input.debug.FocusEventDebugView;
@@ -193,7 +195,6 @@ public class InputManagerService extends IInputManager.Stub
private DisplayManagerInternal mDisplayManagerInternal;
private WindowManagerInternal mWindowManagerInternal;
- private PackageManagerInternal mPackageManagerInternal;
private final File mDoubleTouchGestureEnableFile;
@@ -573,7 +574,6 @@ public class InputManagerService extends IInputManager.Stub
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
- mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mSettingsObserver.registerAndUpdate();
@@ -623,9 +623,10 @@ public class InputManagerService extends IInputManager.Stub
mKeyRemapper.systemRunning();
mPointerIconCache.systemRunning();
mKeyboardGlyphManager.systemRunning();
- mKeyGestureController.systemRunning();
-
- initKeyGestures();
+ if (useKeyGestureEventHandler()) {
+ mKeyGestureController.systemRunning();
+ initKeyGestures();
+ }
}
private void reloadDeviceAliases() {
@@ -2608,9 +2609,6 @@ public class InputManagerService extends IInputManager.Stub
}
private void initKeyGestures() {
- if (!useKeyGestureEventHandler()) {
- return;
- }
InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
im.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() {
@Override
@@ -2939,10 +2937,11 @@ public class InputManagerService extends IInputManager.Stub
private void enforceManageKeyGesturePermission() {
// TODO(b/361567988): Use @EnforcePermission to enforce permission once flag guarding the
// permission is rolled out
- if (mSystemReady) {
- String systemUIPackage = mContext.getString(R.string.config_systemUi);
- int systemUIAppId = UserHandle.getAppId(mPackageManagerInternal
- .getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY,
+ String systemUIPackage = mContext.getString(R.string.config_systemUi);
+ PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
+ if (pm != null) {
+ int systemUIAppId = UserHandle.getAppId(
+ pm.getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY,
UserHandle.USER_SYSTEM));
if (UserHandle.getCallingAppId() == systemUIAppId) {
return;
@@ -3034,6 +3033,19 @@ public class InputManagerService extends IInputManager.Stub
return mKeyGestureController.getAppLaunchBookmarks();
}
+ @Override
+ public void resetLockedModifierState() {
+ mNative.resetLockedModifierState();
+ }
+
+ private void onUserSwitching(@NonNull SystemService.TargetUser from,
+ @NonNull SystemService.TargetUser to) {
+ if (DEBUG) {
+ Slog.d(TAG, "onUserSwitching from=" + from + " to=" + to);
+ }
+ mHandler.obtainMessage(MSG_CURRENT_USER_CHANGED, to.getUserIdentifier()).sendToTarget();
+ }
+
private void handleCurrentUserChanged(@UserIdInt int userId) {
mCurrentUserId = userId;
mKeyGestureController.setCurrentUserId(userId);
@@ -3394,6 +3406,42 @@ public class InputManagerService extends IInputManager.Stub
}
}
+ /**
+ * {@link SystemService} used to publish and manage the lifecycle of {@link InputManagerService}
+ */
+ public static final class Lifecycle extends SystemService {
+
+ private final InputManagerService mService;
+
+ public Lifecycle(@NonNull Context context) {
+ super(context);
+ mService = new InputManagerService(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.INPUT_SERVICE, mService,
+ /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ // Called on ActivityManager thread.
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mService.systemRunning();
+ }
+ }
+
+ @Override
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ mService.onUserSwitching(from, to);
+ }
+
+ public InputManagerService getService() {
+ return mService;
+ }
+ }
+
private final class LocalService extends InputManagerInternal {
@Override
public void setDisplayViewports(List<DisplayViewport> viewports) {
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 420db9041dc2..3b2305cec9db 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -117,7 +117,10 @@ class InputSettingsObserver extends ContentObserver {
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_STROKE_STYLE),
(reason) -> updatePointerStrokeStyleFromSettings()),
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SCALE),
- (reason) -> updatePointerScaleFromSettings()));
+ (reason) -> updatePointerScaleFromSettings()),
+ Map.entry(Settings.System.getUriFor(
+ Settings.System.TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION),
+ (reason) -> updateTouchpadThreeFingerTapShortcutEnabled()));
}
/**
@@ -143,10 +146,6 @@ class InputSettingsObserver extends ContentObserver {
observer.accept("just booted");
}
- // TODO(b/365063048): add an entry to mObservers that calls this instead, once we have a
- // setting that can be observed.
- updateTouchpadThreeFingerTapShortcutEnabled();
-
configureUserActivityPokeInterval();
}
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index 98330163a693..5bc08a0ff85d 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -475,6 +475,7 @@ public class InputShellCommand extends ShellCommand {
}
}
}
+ event = KeyEvent.changeTimeRepeat(event, SystemClock.uptimeMillis(), 0);
injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP), async);
}
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index bb0b19009962..55d2de2b6865 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -793,6 +793,11 @@ final class KeyGestureController {
return true;
}
+ // Handle shortcuts through shortcut services
+ if (mAppLaunchShortcutManager.handleShortcutService(event)) {
+ return true;
+ }
+
// Handle custom shortcuts
if (firstDown) {
InputGestureData customGesture;
diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java
index c3205afe14f2..0defd27eaae2 100644
--- a/services/core/java/com/android/server/input/KeyboardBacklightController.java
+++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java
@@ -20,6 +20,7 @@ import android.animation.ValueAnimator;
import android.annotation.BinderThread;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Color;
import android.hardware.input.IKeyboardBacklightListener;
import android.hardware.input.IKeyboardBacklightState;
@@ -81,9 +82,6 @@ final class KeyboardBacklightController implements
private static final String UEVENT_KEYBOARD_BACKLIGHT_TAG = "kbd_backlight";
@VisibleForTesting
- static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis();
-
- @VisibleForTesting
static final int[] DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL =
new int[DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS + 1];
@@ -112,6 +110,7 @@ final class KeyboardBacklightController implements
private AmbientKeyboardBacklightController.AmbientKeyboardBacklightListener mAmbientListener;
private int mAmbientBacklightValue = 0;
+ private final int mUserInactivityThresholdMs;
static {
// Fixed brightness levels to avoid issues when converting back and forth from the
@@ -139,6 +138,9 @@ final class KeyboardBacklightController implements
mAnimatorFactory = animatorFactory;
mAmbientController = new AmbientKeyboardBacklightController(context, looper);
mUEventManager = uEventManager;
+ Resources res = mContext.getResources();
+ mUserInactivityThresholdMs = res.getInteger(
+ com.android.internal.R.integer.config_keyboardBacklightTimeoutMs);
}
@Override
@@ -300,7 +302,7 @@ final class KeyboardBacklightController implements
}
mHandler.removeMessages(MSG_NOTIFY_USER_INACTIVITY);
mHandler.sendEmptyMessageAtTime(MSG_NOTIFY_USER_INACTIVITY,
- SystemClock.uptimeMillis() + USER_INACTIVITY_THRESHOLD_MILLIS);
+ SystemClock.uptimeMillis() + mUserInactivityThresholdMs);
}
private void handleUserInactivity() {
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 8903c27b491a..728e44062e82 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -98,6 +98,8 @@ interface NativeInputManagerService {
void toggleCapsLock(int deviceId);
+ void resetLockedModifierState();
+
void displayRemoved(int displayId);
void setInputDispatchMode(boolean enabled, boolean frozen);
@@ -370,6 +372,9 @@ interface NativeInputManagerService {
public native void toggleCapsLock(int deviceId);
@Override
+ public native void resetLockedModifierState();
+
+ @Override
public native void displayRemoved(int displayId);
@Override
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index d13244905633..da2089131b9f 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -19,13 +19,19 @@ package com.android.server.inputmethod;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.Region;
import android.os.InputConfig;
import android.os.Process;
+import android.util.Slog;
import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import android.view.WindowMetrics;
+import android.view.inputmethod.Flags;
import com.android.server.input.InputManagerService;
@@ -39,8 +45,8 @@ final class HandwritingEventReceiverSurface {
private final SurfaceControl mInputSurface;
private boolean mIsIntercepting;
- HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc,
- @NonNull InputChannel inputChannel) {
+ HandwritingEventReceiverSurface(Context context, String name, int displayId,
+ @NonNull SurfaceControl sc, @NonNull InputChannel inputChannel) {
mClientChannel = inputChannel;
mInputSurface = sc;
@@ -59,15 +65,31 @@ final class HandwritingEventReceiverSurface {
| InputConfig.SPY
| InputConfig.INTERCEPTS_STYLUS;
- // Configure the surface to receive stylus events across the entire display.
- mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+ Rect bounds = null;
+ if (Flags.adaptiveHandwritingBounds()) {
+ mWindowHandle.setTouchableRegionCrop(mInputSurface);
+ // Default touchable area to getMaximumWindowMetrics()
+ WindowMetrics windowMetrics = context.getSystemService(WindowManager.class)
+ .getMaximumWindowMetrics();
+ bounds = windowMetrics.getBounds();
+ if (DEBUG) Slog.d(TAG, "initial handwriting touchable bounds: " + bounds);
+ mWindowHandle.setTouchableRegion(windowMetrics.getBounds());
+ } else {
+ // Configure the surface to receive stylus events across the entire display.
+ mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+ }
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);
t.setPosition(mInputSurface, 0, 0);
- t.setCrop(mInputSurface, null /* crop to parent surface */);
+ if (Flags.adaptiveHandwritingBounds()) {
+ // crop to parent surface if null, else bounds.
+ t.setCrop(mInputSurface, bounds);
+ } else {
+ t.setCrop(mInputSurface, null /* crop to parent surface */);
+ }
t.show(mInputSurface);
t.apply();
@@ -79,12 +101,23 @@ final class HandwritingEventReceiverSurface {
mWindowHandle.ownerUid = imeUid;
mWindowHandle.inputConfig &= ~InputConfig.SPY;
+ if (Flags.adaptiveHandwritingBounds()) {
+ // watch outside touch to finish handwriting.
+ mWindowHandle.inputConfig |= InputConfig.WATCH_OUTSIDE_TOUCH;
+ }
new SurfaceControl.Transaction()
.setInputWindowInfo(mInputSurface, mWindowHandle)
.apply();
mIsIntercepting = true;
}
+ void setTouchableRegion(Region touchableRegion) {
+ mWindowHandle.touchableRegion.set(touchableRegion);
+ new SurfaceControl.Transaction()
+ .setInputWindowInfo(mInputSurface, mWindowHandle)
+ .apply();
+ }
+
void setNotTouchable(boolean notTouchable) {
if (notTouchable) {
mWindowHandle.inputConfig |= InputConfig.NOT_TOUCHABLE;
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index c19cb030ef37..45d7d0464fe1 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -27,6 +27,7 @@ import android.annotation.UiThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.graphics.Region;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
import android.os.Handler;
@@ -139,7 +140,7 @@ final class HandwritingModeController {
}
mHandwritingSurface = new HandwritingEventReceiverSurface(
- name, displayId, surface, channel);
+ mContext, name, displayId, surface, channel);
// Use a dup of the input channel so that event processing can be paused by disposing the
// event receiver without causing a fd hangup.
@@ -163,6 +164,13 @@ final class HandwritingModeController {
mHandwritingSurface.setNotTouchable(notTouchable);
}
+ void setHandwritingTouchableRegion(Region region) {
+ if (!getCurrentRequestId().isPresent()) {
+ return;
+ }
+ mHandwritingSurface.setTouchableRegion(region);
+ }
+
boolean isStylusGestureOngoing() {
if (mRecordingGestureAfterStylusUp && !mHandwritingBuffer.isEmpty()) {
// If it is less than AFTER_STYLUS_UP_ALLOW_PERIOD_MS after the stylus up event, return
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d8483f721306..b7af9a4b17bd 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1310,7 +1310,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// Do not reset the default (current) IME when it is a 3rd-party IME
String selectedMethodId = bindingController.getSelectedMethodId();
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
- if (selectedMethodId != null
+ if (selectedMethodId != null && settings.getMethodMap().get(selectedMethodId) != null
&& !settings.getMethodMap().get(selectedMethodId).isSystem()) {
return;
}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index bb4ae96da53b..a132876b72a3 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -46,7 +46,6 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
-import com.android.server.integrity.model.RuleMetadata;
import java.io.File;
import java.nio.charset.StandardCharsets;
diff --git a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
deleted file mode 100644
index b0647fc46473..000000000000
--- a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
+++ /dev/null
@@ -1,93 +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.server.integrity.model;
-
-import android.annotation.Nullable;
-import android.content.integrity.Rule;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A class encapsulating the result from the evaluation engine after evaluating rules against app
- * install metadata.
- *
- * <p>It contains the outcome effect (whether to allow or block the install), and the rule causing
- * that effect.
- */
-public final class IntegrityCheckResult {
-
- public enum Effect {
- ALLOW,
- DENY
- }
-
- private final Effect mEffect;
- private final List<Rule> mRuleList;
-
- private IntegrityCheckResult(Effect effect, @Nullable List<Rule> ruleList) {
- this.mEffect = effect;
- this.mRuleList = ruleList;
- }
-
- public Effect getEffect() {
- return mEffect;
- }
-
- public List<Rule> getMatchedRules() {
- return mRuleList;
- }
-
- /**
- * Create an ALLOW evaluation outcome.
- *
- * @return An evaluation outcome with ALLOW effect and no rule.
- */
- public static IntegrityCheckResult allow() {
- return new IntegrityCheckResult(Effect.ALLOW, Collections.emptyList());
- }
-
- /**
- * Create an ALLOW evaluation outcome.
- *
- * @return An evaluation outcome with ALLOW effect and rule causing that effect.
- */
- public static IntegrityCheckResult allow(List<Rule> ruleList) {
- return new IntegrityCheckResult(Effect.ALLOW, ruleList);
- }
-
- /**
- * Create a DENY evaluation outcome.
- *
- * @param ruleList All valid rules that cause the DENY effect.
- * @return An evaluation outcome with DENY effect and rule causing that effect.
- */
- public static IntegrityCheckResult deny(List<Rule> ruleList) {
- return new IntegrityCheckResult(Effect.DENY, ruleList);
- }
-
- /** Returns true when the {@code mEffect} is caused by an app certificate mismatch. */
- public boolean isCausedByAppCertRule() {
- return mRuleList.stream().anyMatch(rule -> rule.getFormula().isAppCertificateFormula());
- }
-
- /** Returns true when the {@code mEffect} is caused by an installer rule. */
- public boolean isCausedByInstallerRule() {
- return mRuleList.stream().anyMatch(rule -> rule.getFormula().isInstallerFormula());
- }
-
-}
diff --git a/services/core/java/com/android/server/integrity/model/RuleMetadata.java b/services/core/java/com/android/server/integrity/model/RuleMetadata.java
deleted file mode 100644
index 6b582ae7b5f2..000000000000
--- a/services/core/java/com/android/server/integrity/model/RuleMetadata.java
+++ /dev/null
@@ -1,41 +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.server.integrity.model;
-
-import android.annotation.Nullable;
-
-/** Data class containing relevant metadata associated with a rule set. */
-public class RuleMetadata {
-
- private final String mRuleProvider;
- private final String mVersion;
-
- public RuleMetadata(String ruleProvider, String version) {
- mRuleProvider = ruleProvider;
- mVersion = version;
- }
-
- @Nullable
- public String getRuleProvider() {
- return mRuleProvider;
- }
-
- @Nullable
- public String getVersion() {
- return mVersion;
- }
-}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
index 0fdd0ae641df..5248a051404d 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
@@ -237,15 +237,16 @@ import java.util.function.Consumer;
if (message.isBroadcastMessage()) {
if (message.isReliable()) {
- Log.e(TAG, "Received reliable broadcast message from " + message.getNanoAppId());
+ Log.e(TAG, "Received reliable broadcast message from 0x"
+ + Long.toHexString(message.getNanoAppId()));
return ErrorCode.PERMANENT_ERROR;
}
// Broadcast messages shouldn't be sent with any permissions tagged per CHRE API
// requirements.
if (!messagePermissions.isEmpty()) {
- Log.e(TAG, "Received broadcast message with permissions from "
- + message.getNanoAppId());
+ Log.e(TAG, "Received broadcast message with permissions from 0x"
+ + Long.toHexString(message.getNanoAppId()));
return ErrorCode.PERMANENT_ERROR;
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java
new file mode 100644
index 000000000000..c05f7a0c0e00
--- /dev/null
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 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.contexthub;
+
+import android.hardware.contexthub.EndpointId;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.IEndpointCallback;
+import android.hardware.contexthub.Message;
+import android.hardware.contexthub.MessageDeliveryStatus;
+import android.os.RemoteException;
+
+/** IEndpointCallback implementation. */
+public class ContextHubHalEndpointCallback
+ extends android.hardware.contexthub.IEndpointCallback.Stub {
+ private final IEndpointLifecycleCallback mEndpointLifecycleCallback;
+
+ /** Interface for listening for endpoint start and stop events. */
+ public interface IEndpointLifecycleCallback {
+ /** Called when a batch of endpoints started. */
+ void onEndpointStarted(HubEndpointInfo[] endpointInfos);
+
+ /** Called when a batch of endpoints stopped. */
+ void onEndpointStopped(HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason);
+ }
+
+ ContextHubHalEndpointCallback(IEndpointLifecycleCallback endpointLifecycleCallback) {
+ mEndpointLifecycleCallback = endpointLifecycleCallback;
+ }
+
+ @Override
+ public void onEndpointStarted(android.hardware.contexthub.EndpointInfo[] halEndpointInfos)
+ throws RemoteException {
+ if (halEndpointInfos.length == 0) {
+ return;
+ }
+ HubEndpointInfo[] endpointInfos = new HubEndpointInfo[halEndpointInfos.length];
+ for (int i = 0; i < halEndpointInfos.length; i++) {
+ endpointInfos[i++] = new HubEndpointInfo(halEndpointInfos[i]);
+ }
+ mEndpointLifecycleCallback.onEndpointStarted(endpointInfos);
+ }
+
+ @Override
+ public void onEndpointStopped(EndpointId[] halEndpointIds, byte reason) throws RemoteException {
+ HubEndpointInfo.HubEndpointIdentifier[] endpointIds =
+ new HubEndpointInfo.HubEndpointIdentifier[halEndpointIds.length];
+ for (int i = 0; i < halEndpointIds.length; i++) {
+ endpointIds[i] = new HubEndpointInfo.HubEndpointIdentifier(halEndpointIds[i]);
+ }
+ mEndpointLifecycleCallback.onEndpointStopped(endpointIds, reason);
+ }
+
+ @Override
+ public void onMessageReceived(int i, Message message) throws RemoteException {}
+
+ @Override
+ public void onMessageDeliveryStatusReceived(int i, MessageDeliveryStatus messageDeliveryStatus)
+ throws RemoteException {}
+
+ @Override
+ public void onEndpointSessionOpenRequest(
+ int i, EndpointId endpointId, EndpointId endpointId1, String s)
+ throws RemoteException {}
+
+ @Override
+ public void onCloseEndpointSession(int i, byte b) throws RemoteException {}
+
+ @Override
+ public void onEndpointSessionOpenComplete(int i) throws RemoteException {}
+
+ @Override
+ public int getInterfaceVersion() throws RemoteException {
+ return IEndpointCallback.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() throws RemoteException {
+ return IEndpointCallback.HASH;
+ }
+}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index f611c57dab03..76049ca824c2 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -31,6 +31,9 @@ import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManagerInternal;
import android.hardware.contexthub.ErrorCode;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.IContextHubEndpoint;
+import android.hardware.contexthub.IContextHubEndpointCallback;
import android.hardware.contexthub.MessageDeliveryStatus;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubMessage;
@@ -249,6 +252,7 @@ public class ContextHubService extends IContextHubService.Stub {
public void handleServiceRestart() {
Log.i(TAG, "Recovering from Context Hub HAL restart...");
initExistingCallbacks();
+ mHubInfoRegistry.onHalRestart();
resetSettings();
if (Flags.reconnectHostEndpointsAfterHalRestart()) {
mClientManager.forEachClientOfHub(mContextHubId,
@@ -321,15 +325,23 @@ public class ContextHubService extends IContextHubService.Stub {
return;
}
- if (Flags.offloadApi()) {
- mHubInfoRegistry = new HubInfoRegistry(mContextHubWrapper);
- Log.i(TAG, "Enabling generic offload API");
+ if (Flags.offloadApi() && Flags.offloadImplementation()) {
+ HubInfoRegistry registry;
+ try {
+ registry = new HubInfoRegistry(mContextHubWrapper);
+ Log.i(TAG, "Enabling generic offload API");
+ } catch (UnsupportedOperationException e) {
+ registry = null;
+ Log.w(TAG, "Generic offload API not supported, disabling");
+ }
+ mHubInfoRegistry = registry;
} else {
mHubInfoRegistry = null;
Log.i(TAG, "Disabling generic offload API");
}
initDefaultClientMap();
+ initEndpointCallback();
initLocationSettingNotifications();
initWifiSettingNotifications();
@@ -508,6 +520,18 @@ public class ContextHubService extends IContextHubService.Stub {
mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
}
+ private void initEndpointCallback() {
+ if (mHubInfoRegistry == null) {
+ return;
+ }
+ try {
+ mContextHubWrapper.registerEndpointCallback(
+ new ContextHubHalEndpointCallback(mHubInfoRegistry));
+ } catch (RemoteException | UnsupportedOperationException e) {
+ Log.e(TAG, "Exception while registering IEndpointCallback", e);
+ }
+ }
+
/**
* Initializes existing callbacks with the mContextHubWrapper for every context hub
*/
@@ -739,6 +763,36 @@ public class ContextHubService extends IContextHubService.Stub {
return mHubInfoRegistry.getHubs();
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @Override
+ public List<HubEndpointInfo> findEndpoints(long endpointId) {
+ super.findEndpoints_enforcePermission();
+ if (mHubInfoRegistry == null) {
+ return Collections.emptyList();
+ }
+ return mHubInfoRegistry.findEndpoints(endpointId);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @Override
+ public List<HubEndpointInfo> findEndpointsWithService(String serviceDescriptor) {
+ super.findEndpointsWithService_enforcePermission();
+ if (mHubInfoRegistry == null) {
+ return Collections.emptyList();
+ }
+ return mHubInfoRegistry.findEndpointsWithService(serviceDescriptor);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @Override
+ public IContextHubEndpoint registerEndpoint(
+ HubEndpointInfo pendingHubEndpointInfo, IContextHubEndpointCallback callback)
+ throws RemoteException {
+ super.registerEndpoint_enforcePermission();
+ // TODO(b/375487784): Implement this
+ return null;
+ }
+
/**
* Creates an internal load transaction callback to be used for old API clients
*
diff --git a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
index 68de9dbda2e1..d2b2331d54f3 100644
--- a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
+++ b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
@@ -16,45 +16,161 @@
package com.android.server.location.contexthub;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.HubServiceInfo;
import android.hardware.location.HubInfo;
import android.os.RemoteException;
+import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-class HubInfoRegistry {
+class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycleCallback {
private static final String TAG = "HubInfoRegistry";
+ private final Object mLock = new Object();
private final IContextHubWrapper mContextHubWrapper;
- private final List<HubInfo> mHubsInfo;
+ @GuardedBy("mLock")
+ private List<HubInfo> mHubsInfo;
+
+ @GuardedBy("mLock")
+ private final ArrayMap<HubEndpointInfo.HubEndpointIdentifier, HubEndpointInfo>
+ mHubEndpointInfos = new ArrayMap<>();
HubInfoRegistry(IContextHubWrapper contextHubWrapper) {
- List<HubInfo> hubInfos;
mContextHubWrapper = contextHubWrapper;
+ refreshCachedHubs();
+ refreshCachedEndpoints();
+ }
+
+ /** Retrieve the list of hubs available. */
+ List<HubInfo> getHubs() {
+ synchronized (mLock) {
+ return mHubsInfo;
+ }
+ }
+
+ private void refreshCachedHubs() {
+ List<HubInfo> hubInfos;
try {
hubInfos = mContextHubWrapper.getHubs();
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while getting Hub info", e);
hubInfos = Collections.emptyList();
}
- mHubsInfo = hubInfos;
+
+ synchronized (mLock) {
+ mHubsInfo = hubInfos;
+ }
}
- /** Retrieve the list of hubs available. */
- List<HubInfo> getHubs() {
- return mHubsInfo;
+ private void refreshCachedEndpoints() {
+ List<HubEndpointInfo> endpointInfos;
+ try {
+ endpointInfos = mContextHubWrapper.getEndpoints();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while getting Hub info", e);
+ endpointInfos = Collections.emptyList();
+ }
+
+ synchronized (mLock) {
+ mHubEndpointInfos.clear();
+ for (HubEndpointInfo endpointInfo : endpointInfos) {
+ mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo);
+ }
+ }
+ }
+
+ /** Invoked when HAL restarts */
+ public void onHalRestart() {
+ synchronized (mLock) {
+ refreshCachedHubs();
+ refreshCachedEndpoints();
+ }
+ }
+
+ @Override
+ public void onEndpointStarted(HubEndpointInfo[] endpointInfos) {
+ synchronized (mLock) {
+ for (HubEndpointInfo endpointInfo : endpointInfos) {
+ mHubEndpointInfos.remove(endpointInfo.getIdentifier());
+ mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo);
+ }
+ }
+ }
+
+ @Override
+ public void onEndpointStopped(
+ HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason) {
+ synchronized (mLock) {
+ for (HubEndpointInfo.HubEndpointIdentifier endpointId : endpointIds) {
+ mHubEndpointInfos.remove(endpointId);
+ }
+ }
+ }
+
+ /** Return a list of {@link HubEndpointInfo} that represents endpoints with the matching id. */
+ public List<HubEndpointInfo> findEndpoints(long endpointIdQuery) {
+ List<HubEndpointInfo> searchResult = new ArrayList<>();
+ synchronized (mLock) {
+ for (HubEndpointInfo.HubEndpointIdentifier endpointId : mHubEndpointInfos.keySet()) {
+ if (endpointId.getEndpoint() == endpointIdQuery) {
+ searchResult.add(mHubEndpointInfos.get(endpointId));
+ }
+ }
+ }
+ return searchResult;
+ }
+
+ /**
+ * Return a list of {@link HubEndpointInfo} that represents endpoints with the matching service.
+ */
+ public List<HubEndpointInfo> findEndpointsWithService(String serviceDescriptor) {
+ List<HubEndpointInfo> searchResult = new ArrayList<>();
+ synchronized (mLock) {
+ for (HubEndpointInfo endpointInfo : mHubEndpointInfos.values()) {
+ for (HubServiceInfo serviceInfo : endpointInfo.getServiceInfoCollection()) {
+ if (serviceDescriptor.equals(serviceInfo.getServiceDescriptor())) {
+ searchResult.add(endpointInfo);
+ }
+ }
+ }
+ }
+ return searchResult;
}
void dump(IndentingPrintWriter ipw) {
+ synchronized (mLock) {
+ dumpLocked(ipw);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void dumpLocked(IndentingPrintWriter ipw) {
ipw.println(TAG);
ipw.increaseIndent();
+ ipw.println("Hubs");
for (HubInfo hubInfo : mHubsInfo) {
ipw.println(hubInfo);
}
ipw.decreaseIndent();
+
+ ipw.println();
+
+ ipw.increaseIndent();
+ ipw.println("Endpoints");
+ for (HubEndpointInfo endpointInfo : mHubEndpointInfos.values()) {
+ ipw.println(endpointInfo);
+ }
+ ipw.decreaseIndent();
+
+ ipw.println();
}
}
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 6656a6fe9eb4..9b729eb11eed 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -19,6 +19,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.chre.flags.Flags;
import android.hardware.contexthub.HostEndpointInfo;
+import android.hardware.contexthub.HubEndpointInfo;
import android.hardware.contexthub.MessageDeliveryStatus;
import android.hardware.contexthub.NanSessionRequest;
import android.hardware.contexthub.V1_0.ContextHub;
@@ -229,6 +230,15 @@ public abstract class IContextHubWrapper {
return Collections.emptyList();
}
+ /** Calls the appropriate getEndpoints function depending on the HAL version. */
+ public List<HubEndpointInfo> getEndpoints() throws RemoteException {
+ return Collections.emptyList();
+ }
+
+ /** Calls the appropriate registerEndpointCallback function depending on the HAL version. */
+ public void registerEndpointCallback(android.hardware.contexthub.IEndpointCallback cb)
+ throws RemoteException {}
+
/**
* @return True if this version of the Contexthub HAL supports Location setting notifications.
*/
@@ -622,6 +632,45 @@ public abstract class IContextHubWrapper {
return retVal;
}
+ @Override
+ public List<HubEndpointInfo> getEndpoints() throws RemoteException {
+ android.hardware.contexthub.IContextHub hub = getHub();
+ if (hub == null) {
+ return Collections.emptyList();
+ }
+
+ List<HubEndpointInfo> retVal = new ArrayList<>();
+ final List<android.hardware.contexthub.EndpointInfo> halEndpointInfos =
+ hub.getEndpoints();
+ for (android.hardware.contexthub.EndpointInfo halEndpointInfo : halEndpointInfos) {
+ /* HAL -> API Type conversion */
+ final HubEndpointInfo endpointInfo = new HubEndpointInfo(halEndpointInfo);
+ if (DEBUG) {
+ Log.i(TAG, "getEndpoints: endpointInfo=" + endpointInfo);
+ }
+ retVal.add(endpointInfo);
+ }
+
+ if (DEBUG) {
+ Log.i(TAG, "getEndpoints: total count=" + retVal.size());
+ }
+ return retVal;
+ }
+
+ @Override
+ public void registerEndpointCallback(android.hardware.contexthub.IEndpointCallback cb)
+ throws RemoteException {
+ android.hardware.contexthub.IContextHub hub = getHub();
+ if (hub == null) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(TAG, "registerEndpointCallback: cb=" + cb);
+ }
+ hub.registerEndpointCallback(cb);
+ }
+
public boolean supportsLocationSettingNotifications() {
return true;
}
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
index c62e3237e487..6536ca084421 100644
--- a/services/core/java/com/android/server/location/contexthub/OWNERS
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -1,3 +1,4 @@
bduddie@google.com
+arthuri@google.com
matthewsedam@google.com
stange@google.com
diff --git a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
index 6c74cba99bcb..05fe78114eca 100644
--- a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
+++ b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
@@ -30,7 +30,8 @@ public class FrameworkStatsLogWrapper {
int hostUid,
int targetUid,
int timeSinceLastActive,
- int creationSource) {
+ int creationSource,
+ int stopSource) {
FrameworkStatsLog.write(
code,
sessionId,
@@ -39,7 +40,8 @@ public class FrameworkStatsLogWrapper {
hostUid,
targetUid,
timeSinceLastActive,
- creationSource);
+ creationSource,
+ stopSource);
}
/** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionTargetChanged atom. */
@@ -49,13 +51,23 @@ public class FrameworkStatsLogWrapper {
int targetType,
int hostUid,
int targetUid,
- int windowingMode) {
+ int windowingMode,
+ int width,
+ int height,
+ int centerX,
+ int centerY,
+ int targetChangeType) {
FrameworkStatsLog.write(
code,
sessionId,
targetType,
hostUid,
targetUid,
- windowingMode);
+ windowingMode,
+ width,
+ height,
+ centerX,
+ centerY,
+ targetChangeType);
}
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 436acba6e492..c428f39fd9d0 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.media.projection;
import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
-import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED;
import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -28,7 +27,6 @@ import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL;
import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;
import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_TASK;
import static android.media.projection.ReviewGrantedConsentResult.UNKNOWN;
-import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -41,10 +39,7 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityOptions.LaunchCookie;
import android.app.AppOpsManager;
import android.app.IProcessObserver;
-import android.app.KeyguardManager;
import android.app.compat.CompatChanges;
-import android.app.role.RoleManager;
-import android.companion.AssociationRequest;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
@@ -56,6 +51,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.projection.IMediaProjection;
@@ -65,6 +61,7 @@ import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -74,7 +71,6 @@ import android.os.PermissionEnforcer;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Slog;
import android.view.ContentRecordingSession;
@@ -85,7 +81,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
-import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.wm.WindowManagerInternal;
@@ -140,12 +135,12 @@ public final class MediaProjectionManagerService extends SystemService
private final ActivityManagerInternal mActivityManagerInternal;
private final PackageManager mPackageManager;
private final WindowManagerInternal mWmInternal;
- private final KeyguardManager mKeyguardManager;
- private final RoleManager mRoleManager;
+
private final MediaRouter mMediaRouter;
private final MediaRouterCallback mMediaRouterCallback;
private final MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
+ private final MediaProjectionStopController mMediaProjectionStopController;
private MediaRouter.RouteInfo mMediaRouteInfo;
@GuardedBy("mLock")
@@ -175,73 +170,17 @@ public final class MediaProjectionManagerService extends SystemService
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mMediaRouterCallback = new MediaRouterCallback();
mMediaProjectionMetricsLogger = injector.mediaProjectionMetricsLogger(context);
- mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mKeyguardManager.addKeyguardLockedStateListener(
- mContext.getMainExecutor(), this::onKeyguardLockedStateChanged);
- mRoleManager = mContext.getSystemService(RoleManager.class);
+ mMediaProjectionStopController = new MediaProjectionStopController(context,
+ this::maybeStopMediaProjection);
Watchdog.getInstance().addMonitor(this);
}
- /**
- * In order to record the keyguard, the MediaProjection package must be either:
- * - a holder of RECORD_SENSITIVE_CONTENT permission, or
- * - be one of the bugreport allowlisted packages, or
- * - hold the OP_PROJECT_MEDIA AppOp.
- */
- @SuppressWarnings("BooleanMethodIsAlwaysInverted")
- private boolean canCaptureKeyguard() {
- if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
- return true;
- }
- synchronized (mLock) {
- if (mProjectionGrant == null || mProjectionGrant.packageName == null) {
- return false;
- }
- boolean disableScreenShareProtections = Settings.Global.getInt(
- getContext().getContentResolver(),
- DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0;
- if (disableScreenShareProtections) {
- Slog.v(TAG,
- "Allowing keyguard capture as screenshare protections are disabled.");
- return true;
- }
-
- if (mPackageManager.checkPermission(RECORD_SENSITIVE_CONTENT,
- mProjectionGrant.packageName)
- == PackageManager.PERMISSION_GRANTED) {
- Slog.v(TAG,
- "Allowing keyguard capture for package with RECORD_SENSITIVE_CONTENT "
- + "permission");
- return true;
- }
- if (AppOpsManager.MODE_ALLOWED == mAppOps.noteOpNoThrow(AppOpsManager.OP_PROJECT_MEDIA,
- mProjectionGrant.uid, mProjectionGrant.packageName, /* attributionTag= */ null,
- "recording lockscreen")) {
- // Some tools use media projection by granting the OP_PROJECT_MEDIA app
- // op via a shell command. Those tools can be granted keyguard capture
- Slog.v(TAG,
- "Allowing keyguard capture for package with OP_PROJECT_MEDIA AppOp ");
- return true;
- }
- if (isProjectionAppHoldingAppStreamingRoleLocked()) {
- Slog.v(TAG,
- "Allowing keyguard capture for package holding app streaming role.");
- return true;
- }
- return SystemConfig.getInstance().getBugreportWhitelistedPackages()
- .contains(mProjectionGrant.packageName);
- }
- }
-
- @VisibleForTesting
- void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
- if (!isKeyguardLocked) return;
+ private void maybeStopMediaProjection(int reason) {
synchronized (mLock) {
- if (mProjectionGrant != null && !canCaptureKeyguard()
- && mProjectionGrant.mVirtualDisplayId != INVALID_DISPLAY) {
- Slog.d(TAG, "Content Recording: Stopped MediaProjection"
- + " due to keyguard lock");
- mProjectionGrant.stop();
+ if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) {
+ Slog.d(TAG, "Content Recording: Stopping MediaProjection due to "
+ + MediaProjectionStopController.stopReasonToString(reason));
+ mProjectionGrant.stop(StopReason.STOP_DEVICE_LOCKED);
}
}
}
@@ -310,6 +249,8 @@ public final class MediaProjectionManagerService extends SystemService
}
});
}
+
+ mMediaProjectionStopController.startTrackingStopReasons(mContext);
}
@Override
@@ -318,7 +259,7 @@ public final class MediaProjectionManagerService extends SystemService
synchronized (mLock) {
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopped MediaProjection due to user switching");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_USER_SWITCH);
}
}
}
@@ -356,7 +297,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.d(TAG,
"Content Recording: Stopped MediaProjection due to foreground service change");
if (mProjectionGrant != null) {
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_FOREGROUND_SERVICE_CHANGE);
}
}
}
@@ -365,7 +306,7 @@ public final class MediaProjectionManagerService extends SystemService
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopped MediaProjection to start new "
+ "incoming projection");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_NEW_PROJECTION);
}
if (mMediaRouteInfo != null) {
mMediaRouter.getFallbackRoute().select();
@@ -375,7 +316,10 @@ public final class MediaProjectionManagerService extends SystemService
dispatchStart(projection);
}
- private void stopProjectionLocked(final MediaProjection projection) {
+ private void stopProjectionLocked(
+ final MediaProjection projection,
+ @StopReason int stopReason
+ ) {
Slog.d(TAG, "Content Recording: Stopped active MediaProjection and "
+ "dispatching stop to callbacks");
ContentRecordingSession session = projection.mSession;
@@ -383,7 +327,7 @@ public final class MediaProjectionManagerService extends SystemService
session != null
? session.getTargetUid()
: ContentRecordingSession.TARGET_UID_UNKNOWN;
- mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid);
+ mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid, stopReason);
mProjectionToken = null;
mProjectionGrant = null;
dispatchStop(projection);
@@ -464,7 +408,7 @@ public final class MediaProjectionManagerService extends SystemService
+ "ContentRecordingSession - id= "
+ mProjectionGrant.getVirtualDisplayId() + "type=" + projectionType);
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_ERROR);
}
return false;
}
@@ -578,6 +522,18 @@ public final class MediaProjectionManagerService extends SystemService
}
}
+ @VisibleForTesting
+ void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds) {
+ synchronized (mLock) {
+ if (mProjectionGrant == null) {
+ Slog.i(TAG, "Cannot log MediaProjectionTargetChanged atom due to null projection");
+ } else {
+ mMediaProjectionMetricsLogger.logChangedCaptureBounds(
+ contentToRecord, mProjectionGrant.uid, targetUid, captureBounds);
+ }
+ }
+ }
+
/**
* Handles result of dialog shown from
* {@link BinderService#buildReviewGrantedConsentIntentLocked()}.
@@ -618,7 +574,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.w(TAG, "Content Recording: Stopped MediaProjection due to user "
+ "consent result of CANCEL - "
+ "id= " + mProjectionGrant.getVirtualDisplayId());
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_ERROR);
}
break;
case RECORD_CONTENT_DISPLAY:
@@ -736,20 +692,6 @@ public final class MediaProjectionManagerService extends SystemService
}
}
- /**
- * Application holding the app streaming role
- * ({@value AssociationRequest#DEVICE_PROFILE_APP_STREAMING}) are allowed to record the
- * lockscreen.
- *
- * @return true if the is held by the recording application.
- */
- @GuardedBy("mLock")
- private boolean isProjectionAppHoldingAppStreamingRoleLocked() {
- return mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
- mContext.getUser())
- .contains(mProjectionGrant.packageName);
- }
-
private void dump(final PrintWriter pw) {
pw.println("MEDIA PROJECTION MANAGER (dumpsys media_projection)");
synchronized (mLock) {
@@ -848,14 +790,14 @@ public final class MediaProjectionManagerService extends SystemService
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public void stopActiveProjection() {
+ public void stopActiveProjection(@StopReason int stopReason) {
stopActiveProjection_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopping active projection");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(stopReason);
}
}
} finally {
@@ -865,8 +807,9 @@ public final class MediaProjectionManagerService extends SystemService
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public void notifyActiveProjectionCapturedContentResized(int width, int height) {
- notifyActiveProjectionCapturedContentResized_enforcePermission();
+ public void notifyCaptureBoundsChanged(
+ int contentToRecord, int targetProcessUid, Rect newBounds) {
+ notifyCaptureBoundsChanged_enforcePermission();
synchronized (mLock) {
if (!isCurrentProjection(mProjectionGrant)) {
return;
@@ -876,7 +819,13 @@ public final class MediaProjectionManagerService extends SystemService
try {
synchronized (mLock) {
if (mProjectionGrant != null && mCallbackDelegate != null) {
- mCallbackDelegate.dispatchResize(mProjectionGrant, width, height);
+ // log metrics for the new bounds
+ MediaProjectionManagerService.this.notifyCaptureBoundsChanged(
+ contentToRecord, targetProcessUid, newBounds);
+
+ // update clients of the new update bounds
+ mCallbackDelegate.dispatchResize(
+ mProjectionGrant, newBounds.width(), newBounds.height());
}
}
} finally {
@@ -957,18 +906,19 @@ public final class MediaProjectionManagerService extends SystemService
public void requestConsentForInvalidProjection(@NonNull IMediaProjection projection) {
requestConsentForInvalidProjection_enforcePermission();
- if (android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()
- && mKeyguardManager.isKeyguardLocked()) {
- Slog.v(TAG, "Reusing token: Won't request consent while the keyguard is locked");
- return;
- }
-
synchronized (mLock) {
if (!isCurrentProjection(projection)) {
Slog.v(TAG, "Reusing token: Won't request consent again for a token that "
+ "isn't current");
return;
}
+
+ if (mMediaProjectionStopController.isStartForbidden(mProjectionGrant)) {
+ Slog.v(TAG,
+ "Reusing token: Won't request consent while MediaProjection is "
+ + "restricted");
+ return;
+ }
}
// Remove calling app identity before performing any privileged operations.
@@ -1076,14 +1026,13 @@ public final class MediaProjectionManagerService extends SystemService
}
}
- @VisibleForTesting
final class MediaProjection extends IMediaProjection.Stub {
// Host app has 5 minutes to begin using the token before it is invalid.
// Some apps show a dialog for the user to interact with (selecting recording resolution)
// before starting capture, but after requesting consent.
- final long mDefaultTimeoutMs = Duration.ofMinutes(5).toMillis();
+ final long mDefaultTimeoutMillis = Duration.ofMinutes(5).toMillis();
// The creation timestamp in milliseconds, measured by {@link SystemClock#uptimeMillis}.
- private final long mCreateTimeMs;
+ private final long mCreateTimeMillis;
public final int uid;
public final String packageName;
public final UserHandle userHandle;
@@ -1092,7 +1041,7 @@ public final class MediaProjectionManagerService extends SystemService
private final int mType;
// Values for tracking token validity.
// Timeout value to compare creation time against.
- private final long mTimeoutMs = mDefaultTimeoutMs;
+ private final long mTimeoutMillis = mDefaultTimeoutMillis;
private final int mDisplayId;
private IMediaProjectionCallback mCallback;
@@ -1123,7 +1072,7 @@ public final class MediaProjectionManagerService extends SystemService
userHandle = new UserHandle(UserHandle.getUserId(uid));
mTargetSdkVersion = targetSdkVersion;
mIsPrivileged = isPrivileged;
- mCreateTimeMs = mClock.uptimeMillis();
+ mCreateTimeMillis = mClock.uptimeMillis();
mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
MEDIA_PROJECTION_TOKEN_EVENT_CREATED);
mDisplayId = displayId;
@@ -1208,7 +1157,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.d(TAG, "Content Recording: MediaProjection stopped by Binder death - "
+ "id= " + mVirtualDisplayId);
mCallbackDelegate.remove(callback);
- stop();
+ stop(StopReason.STOP_TARGET_REMOVED);
};
mToken.linkToDeath(mDeathEater, 0);
} catch (RemoteException e) {
@@ -1257,7 +1206,7 @@ public final class MediaProjectionManagerService extends SystemService
}
@Override // Binder call
- public void stop() {
+ public void stop(@StopReason int stopReason) {
synchronized (mLock) {
if (!isCurrentProjection(asBinder())) {
Slog.w(TAG, "Attempted to stop inactive MediaProjection "
@@ -1284,9 +1233,9 @@ public final class MediaProjectionManagerService extends SystemService
}
}
Slog.d(TAG, "Content Recording: handling stopping this projection token"
- + " createTime= " + mCreateTimeMs
+ + " createTime= " + mCreateTimeMillis
+ " countStarts= " + mCountStarts);
- stopProjectionLocked(this);
+ stopProjectionLocked(this, stopReason);
mToken.unlinkToDeath(mDeathEater, 0);
mToken = null;
unregisterCallback(mCallback);
@@ -1347,13 +1296,17 @@ public final class MediaProjectionManagerService extends SystemService
return mDisplayId;
}
+ long getCreateTimeMillis() {
+ return mCreateTimeMillis;
+ }
+
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override
public boolean isValid() {
isValid_enforcePermission();
synchronized (mLock) {
- final long curMs = mClock.uptimeMillis();
- final boolean hasTimedOut = curMs - mCreateTimeMs > mTimeoutMs;
+ final long curMillis = mClock.uptimeMillis();
+ final boolean hasTimedOut = curMillis - mCreateTimeMillis > mTimeoutMillis;
final boolean virtualDisplayCreated = mVirtualDisplayId != INVALID_DISPLAY;
final boolean isValid =
!hasTimedOut && (mCountStarts <= 1) && !virtualDisplayCreated;
@@ -1366,7 +1319,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.v(TAG, "Reusing token: Throw exception due to invalid projection.");
// Tear down projection here; necessary to ensure (among other reasons) that
// stop is dispatched to client and cast icon disappears from status bar.
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_ERROR);
throw new SecurityException("Don't re-use the resultData to retrieve "
+ "the same projection instance, and don't use a token that has "
+ "timed out. Don't take multiple captures by invoking "
@@ -1381,12 +1334,14 @@ public final class MediaProjectionManagerService extends SystemService
@Override
public void notifyVirtualDisplayCreated(int displayId) {
notifyVirtualDisplayCreated_enforcePermission();
- if (mKeyguardManager.isKeyguardLocked() && !canCaptureKeyguard()) {
- Slog.w(TAG, "Content Recording: Keyguard locked, aborting MediaProjection");
- stop();
- return;
- }
synchronized (mLock) {
+ if (mMediaProjectionStopController.isStartForbidden(mProjectionGrant)) {
+ Slog.w(TAG,
+ "Content Recording: MediaProjection start disallowed, aborting "
+ + "MediaProjection");
+ stop(StopReason.STOP_DEVICE_LOCKED);
+ return;
+ }
mVirtualDisplayId = displayId;
// If prior session was does not have a valid display id, then update the display
@@ -1425,7 +1380,7 @@ public final class MediaProjectionManagerService extends SystemService
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopped MediaProjection due to "
+ "route type of REMOTE_DISPLAY not selected");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_NEW_MEDIA_ROUTE);
}
}
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
index be2a25a755a5..8e5c01685275 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
@@ -19,15 +19,34 @@ package com.android.server.media.projection;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN;
@@ -36,8 +55,12 @@ import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGE
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN;
+import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.media.projection.StopReason;
import android.util.Log;
import android.view.ContentRecordingSession.RecordContent;
@@ -59,8 +82,10 @@ public class MediaProjectionMetricsLogger {
private final MediaProjectionSessionIdGenerator mSessionIdGenerator;
private final MediaProjectionTimestampStore mTimestampStore;
- private int mPreviousState =
- FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+ private final Rect mPreviousTargetBounds = new Rect();
+ private int mPreviousTargetWindowingMode = WINDOWING_MODE_UNDEFINED;
+ private int mPreviousProjectionState =
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
MediaProjectionMetricsLogger(
FrameworkStatsLogWrapper frameworkStatsLogWrapper,
@@ -113,7 +138,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
TARGET_UID_UNKNOWN,
timeSinceLastActiveInSeconds,
- sessionCreationSource);
+ sessionCreationSource,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -130,7 +156,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
TARGET_UID_UNKNOWN,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -141,13 +168,12 @@ public class MediaProjectionMetricsLogger {
public void logProjectionPermissionRequestCancelled(int hostUid) {
writeStateChanged(
mSessionIdGenerator.getCurrentSessionId(),
- FrameworkStatsLog
- .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
hostUid,
TARGET_UID_UNKNOWN,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- FrameworkStatsLog
- .MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -163,7 +189,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
TARGET_UID_UNKNOWN,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -180,7 +207,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
targetUid,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -196,14 +224,63 @@ public class MediaProjectionMetricsLogger {
*/
public void logChangedWindowingMode(
int contentToRecord, int hostUid, int targetUid, int windowingMode) {
- Log.d(TAG, "logChangedWindowingMode");
+ Log.d(TAG, "logChangedWindowingMode: windowingMode= "
+ + WindowConfiguration.windowingModeToString(windowingMode));
+ Log.d(TAG, "targetChangeType= changeWindowingMode");
writeTargetChanged(
mSessionIdGenerator.getCurrentSessionId(),
contentToRecordToTargetType(contentToRecord),
hostUid,
targetUid,
- windowingModeToTargetWindowingMode(windowingMode));
+ windowingModeToTargetWindowingMode(windowingMode),
+ mPreviousTargetBounds.width(),
+ mPreviousTargetBounds.height(),
+ mPreviousTargetBounds.centerX(),
+ mPreviousTargetBounds.centerY(),
+ MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE);
+ mPreviousTargetWindowingMode = windowingMode;
+ }
+ /**
+ * Logs that the bounds of projection's capture target has changed.
+ *
+ * @param contentToRecord ContentRecordingSession.RecordContent indicating whether it is a
+ * task capture or display capture - gets converted to the corresponding
+ * TargetType before being logged.
+ * @param hostUid UID of the package that initiates MediaProjection.
+ * @param targetUid UID of the package that is captured if selected.
+ * @param captureBounds Updated bounds of the captured region.
+ */
+ public void logChangedCaptureBounds(
+ int contentToRecord, int hostUid, int targetUid, Rect captureBounds) {
+ final Point capturePosition = new Point(captureBounds.centerX(), captureBounds.centerY());
+ Log.d(TAG, "logChangedCaptureBounds: captureBounds= " + captureBounds + " position= "
+ + capturePosition);
+
+ writeTargetChanged(
+ mSessionIdGenerator.getCurrentSessionId(),
+ contentToRecordToTargetType(contentToRecord),
+ hostUid,
+ targetUid,
+ mPreviousTargetWindowingMode,
+ captureBounds.width(),
+ captureBounds.height(),
+ captureBounds.centerX(),
+ captureBounds.centerY(),
+ captureBoundsToTargetChangeType(captureBounds));
+ mPreviousTargetBounds.set(captureBounds);
+ }
+
+ private int captureBoundsToTargetChangeType(Rect captureBounds) {
+ final boolean hasChangedSize = captureBounds.width() != mPreviousTargetBounds.width()
+ && captureBounds.height() != mPreviousTargetBounds.height();
+
+ if (hasChangedSize) {
+ Log.d(TAG, "targetChangeType= changeBounds");
+ return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS;
+ }
+ Log.d(TAG, "targetChangeType= changePosition");
+ return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION;
}
@VisibleForTesting
@@ -231,45 +308,85 @@ public class MediaProjectionMetricsLogger {
};
}
+ @VisibleForTesting
+ public int stopReasonToSessionStopSource(@StopReason int stopReason) {
+ return switch (stopReason) {
+ case StopReason.STOP_HOST_APP ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+ case StopReason.STOP_TARGET_REMOVED ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+ case StopReason.STOP_DEVICE_LOCKED->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+ case StopReason.STOP_PRIVACY_CHIP ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+ case StopReason.STOP_QS_TILE ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+ case StopReason.STOP_USER_SWITCH ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
+ case StopReason.STOP_FOREGROUND_SERVICE_CHANGE ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+ case StopReason.STOP_NEW_PROJECTION ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+ case StopReason.STOP_NEW_MEDIA_ROUTE ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+ case StopReason.STOP_ERROR ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+ default ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
+ };
+ }
+
/**
* Logs that the capturing stopped, either normally or because of error.
*
* @param hostUid UID of the package that initiates MediaProjection.
* @param targetUid UID of the package that is captured if selected.
*/
- public void logStopped(int hostUid, int targetUid) {
+ public void logStopped(int hostUid, int targetUid, int stopReason) {
boolean wasCaptureInProgress =
- mPreviousState
+ mPreviousProjectionState
== MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
- Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress);
+ Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress +
+ " stopReason=" + stopReason);
writeStateChanged(
mSessionIdGenerator.getCurrentSessionId(),
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED,
hostUid,
targetUid,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ stopReasonToSessionStopSource(stopReason));
if (wasCaptureInProgress) {
mTimestampStore.registerActiveSessionEnded();
}
}
- public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
- writeStateChanged(hostUid, state, sessionCreationSource);
+ public void notifyProjectionStateChange(
+ int hostUid,
+ int state,
+ int sessionCreationSource,
+ int sessionStopSource
+ ) {
+ writeStateChanged(hostUid, state, sessionCreationSource, sessionStopSource);
}
- private void writeStateChanged(int hostUid, int state, int sessionCreationSource) {
+ private void writeStateChanged(
+ int hostUid,
+ int state,
+ int sessionCreationSource,
+ int sessionStopSource
+ ) {
mFrameworkStatsLogWrapper.writeStateChanged(
- /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
+ /* code */ MEDIA_PROJECTION_STATE_CHANGED,
/* session_id */ 123,
/* state */ state,
- /* previous_state */ FrameworkStatsLog
- .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
+ /* previous_state */ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
/* host_uid */ hostUid,
/* target_uid */ -1,
/* time_since_last_active */ 0,
- /* creation_source */ sessionCreationSource);
+ /* creation_source */ sessionCreationSource,
+ /* stop_source */ sessionStopSource);
}
private void writeStateChanged(
@@ -278,17 +395,19 @@ public class MediaProjectionMetricsLogger {
int hostUid,
int targetUid,
int timeSinceLastActive,
- int creationSource) {
+ int creationSource,
+ int stopSource) {
mFrameworkStatsLogWrapper.writeStateChanged(
- /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
+ /* code */ MEDIA_PROJECTION_STATE_CHANGED,
sessionId,
state,
- mPreviousState,
+ mPreviousProjectionState,
hostUid,
targetUid,
timeSinceLastActive,
- creationSource);
- mPreviousState = state;
+ creationSource,
+ stopSource);
+ mPreviousProjectionState = state;
}
private void writeTargetChanged(
@@ -296,13 +415,23 @@ public class MediaProjectionMetricsLogger {
int targetType,
int hostUid,
int targetUid,
- int targetWindowingMode) {
+ int targetWindowingMode,
+ int width,
+ int height,
+ int centerX,
+ int centerY,
+ int targetChangeType) {
mFrameworkStatsLogWrapper.writeTargetChanged(
- /* code */ FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED,
+ /* code */ MEDIA_PROJECTION_TARGET_CHANGED,
sessionId,
targetType,
hostUid,
targetUid,
- targetWindowingMode);
+ targetWindowingMode,
+ width,
+ height,
+ centerX,
+ centerY,
+ targetChangeType);
}
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java
new file mode 100644
index 000000000000..c018e6bc1dc7
--- /dev/null
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2024 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.media.projection;
+
+import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
+import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS;
+
+import android.app.AppOpsManager;
+import android.app.KeyguardManager;
+import android.app.role.RoleManager;
+import android.companion.AssociationRequest;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+import android.view.Display;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemConfig;
+
+import java.util.function.Consumer;
+
+/**
+ * Tracks events that should cause MediaProjection to stop
+ */
+public class MediaProjectionStopController {
+
+ private static final String TAG = "MediaProjectionStopController";
+ @VisibleForTesting
+ static final int STOP_REASON_UNKNOWN = 0;
+ @VisibleForTesting
+ static final int STOP_REASON_KEYGUARD = 1;
+ @VisibleForTesting
+ static final int STOP_REASON_CALL_END = 2;
+
+ private final TelephonyCallback mTelephonyCallback = new ProjectionTelephonyCallback();
+ private final Consumer<Integer> mStopReasonConsumer;
+ private final KeyguardManager mKeyguardManager;
+ private final TelecomManager mTelecomManager;
+ private final TelephonyManager mTelephonyManager;
+ private final AppOpsManager mAppOpsManager;
+ private final PackageManager mPackageManager;
+ private final RoleManager mRoleManager;
+ private final ContentResolver mContentResolver;
+
+ private boolean mIsInCall;
+ private long mLastCallStartTimeMillis;
+
+ public MediaProjectionStopController(Context context, Consumer<Integer> stopReasonConsumer) {
+ mStopReasonConsumer = stopReasonConsumer;
+ mKeyguardManager = context.getSystemService(KeyguardManager.class);
+ mTelecomManager = context.getSystemService(TelecomManager.class);
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mPackageManager = context.getPackageManager();
+ mRoleManager = context.getSystemService(RoleManager.class);
+ mContentResolver = context.getContentResolver();
+ }
+
+ /**
+ * Start tracking stop reasons that may interrupt a MediaProjection session.
+ */
+ public void startTrackingStopReasons(Context context) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mKeyguardManager.addKeyguardLockedStateListener(context.getMainExecutor(),
+ this::onKeyguardLockedStateChanged);
+ if (com.android.media.projection.flags.Flags.stopMediaProjectionOnCallEnd()) {
+ callStateChanged();
+ mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(),
+ mTelephonyCallback);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Checks whether the given projection grant is exempt from stopping restrictions.
+ */
+ public boolean isExemptFromStopping(
+ MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason) {
+ return isExempt(projectionGrant, stopReason, false);
+ }
+
+ /**
+ * Apps may disregard recording restrictions via MediaProjection for any stop reason if:
+ * - the "Disable Screenshare protections" developer option is enabled
+ * - the app is a holder of RECORD_SENSITIVE_CONTENT permission
+ * - the app holds the OP_PROJECT_MEDIA AppOp
+ * - the app holds the COMPANION_DEVICE_APP_STREAMING role
+ * - the app is one of the bugreport allowlisted packages
+ * - the current projection does not have an active VirtualDisplay associated with the
+ * MediaProjection session
+ */
+ private boolean isExempt(
+ MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason,
+ boolean forStart) {
+ if (projectionGrant == null || projectionGrant.packageName == null) {
+ return true;
+ }
+ boolean disableScreenShareProtections = Settings.Global.getInt(mContentResolver,
+ DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0;
+ if (disableScreenShareProtections) {
+ Slog.v(TAG, "Continuing MediaProjection as screenshare protections are disabled.");
+ return true;
+ }
+
+ if (mPackageManager.checkPermission(RECORD_SENSITIVE_CONTENT, projectionGrant.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ Slog.v(TAG,
+ "Continuing MediaProjection for package with RECORD_SENSITIVE_CONTENT "
+ + "permission");
+ return true;
+ }
+ if (AppOpsManager.MODE_ALLOWED == mAppOpsManager.noteOpNoThrow(
+ AppOpsManager.OP_PROJECT_MEDIA, projectionGrant.uid,
+ projectionGrant.packageName, /* attributionTag= */ null, "recording lockscreen")) {
+ // Some tools use media projection by granting the OP_PROJECT_MEDIA app
+ // op via a shell command.
+ Slog.v(TAG, "Continuing MediaProjection for package with OP_PROJECT_MEDIA AppOp ");
+ return true;
+ }
+ if (mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
+ projectionGrant.userHandle).contains(projectionGrant.packageName)) {
+ Slog.v(TAG, "Continuing MediaProjection for package holding app streaming role.");
+ return true;
+ }
+ if (SystemConfig.getInstance().getBugreportWhitelistedPackages().contains(
+ projectionGrant.packageName)) {
+ Slog.v(TAG, "Continuing MediaProjection for package allowlisted for bugreporting.");
+ return true;
+ }
+ if (!forStart && projectionGrant.getVirtualDisplayId() == Display.INVALID_DISPLAY) {
+ Slog.v(TAG, "Continuing MediaProjection as current projection has no VirtualDisplay.");
+ return true;
+ }
+
+ if (stopReason == STOP_REASON_CALL_END
+ && projectionGrant.getCreateTimeMillis() < mLastCallStartTimeMillis) {
+ Slog.v(TAG,
+ "Continuing MediaProjection as (phone) call started after MediaProjection was"
+ + " created.");
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return {@code true} if a MediaProjection session is currently in a restricted state.
+ */
+ public boolean isStartForbidden(
+ MediaProjectionManagerService.MediaProjection projectionGrant) {
+ if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
+ return false;
+ }
+
+ if (!mKeyguardManager.isKeyguardLocked()) {
+ return false;
+ }
+
+ if (isExempt(projectionGrant, STOP_REASON_UNKNOWN, true)) {
+ return false;
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
+ if (!isKeyguardLocked) return;
+ if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
+ return;
+ }
+ mStopReasonConsumer.accept(STOP_REASON_KEYGUARD);
+ }
+
+ @VisibleForTesting
+ void callStateChanged() {
+ if (!com.android.media.projection.flags.Flags.stopMediaProjectionOnCallEnd()) {
+ return;
+ }
+ boolean isInCall = mTelecomManager.isInCall();
+ if (isInCall) {
+ mLastCallStartTimeMillis = SystemClock.uptimeMillis();
+ }
+ if (isInCall == mIsInCall) {
+ return;
+ }
+
+ if (mIsInCall && !isInCall) {
+ mStopReasonConsumer.accept(STOP_REASON_CALL_END);
+ }
+ mIsInCall = isInCall;
+ }
+
+ /**
+ * @return a String representation of the stop reason interrupting MediaProjection.
+ */
+ public static String stopReasonToString(int stopReason) {
+ switch (stopReason) {
+ case STOP_REASON_KEYGUARD -> {
+ return "STOP_REASON_KEYGUARD";
+ }
+ case STOP_REASON_CALL_END -> {
+ return "STOP_REASON_CALL_END";
+ }
+ }
+ return "";
+ }
+
+ private final class ProjectionTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.CallStateListener {
+ @Override
+ public void onCallStateChanged(int state) {
+ callStateChanged();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityDbHelper.java b/services/core/java/com/android/server/media/quality/MediaQualityDbHelper.java
new file mode 100644
index 000000000000..04f6216694a9
--- /dev/null
+++ b/services/core/java/com/android/server/media/quality/MediaQualityDbHelper.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 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.media.quality;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.media.quality.MediaQualityContract.BaseParameters;
+
+public class MediaQualityDbHelper extends SQLiteOpenHelper {
+
+ private static final String TAG = "MediaQualityDbHelper";
+
+ static final int DATABASE_VERSION_1 = 1;
+ private static final String DATABASE_NAME = "media_quality.db";
+ public static final String PICTURE_QUALITY_TABLE_NAME = "picture_quality";
+ public static final String SOUND_QUALITY_TABLE_NAME = "sound_quality";
+ public static final String SETTINGS = "settings";
+
+ MediaQualityDbHelper(Context context) {
+ super(context, DATABASE_NAME, null, getDbVersion());
+ }
+
+ private static int getDbVersion() {
+ return DATABASE_VERSION_1;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(getTableCreateStatement(PICTURE_QUALITY_TABLE_NAME));
+ db.execSQL(getTableCreateStatement(SOUND_QUALITY_TABLE_NAME));
+ }
+
+ private String getTableCreateStatement(String tableName) {
+ return
+ "CREATE TABLE " + tableName + "("
+ + BaseParameters.PARAMETER_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ + BaseParameters.PARAMETER_TYPE + " INTEGER,"
+ + BaseParameters.PARAMETER_NAME + " STRING,"
+ + BaseParameters.PARAMETER_PACKAGE + " STRING,"
+ + BaseParameters.PARAMETER_INPUT_ID + " STRING,"
+ + SETTINGS + " TEXT)";
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // to do
+ }
+
+}
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 21ae1820f6f7..c7e00d3cbb24 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -16,20 +16,32 @@
package com.android.server.media.quality;
+import android.content.ContentValues;
import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
import android.media.quality.AmbientBacklightSettings;
import android.media.quality.IAmbientBacklightCallback;
import android.media.quality.IMediaQualityManager;
import android.media.quality.IPictureProfileCallback;
import android.media.quality.ISoundProfileCallback;
+import android.media.quality.MediaQualityContract;
import android.media.quality.ParamCapability;
import android.media.quality.PictureProfile;
+import android.media.quality.PictureProfileHandle;
import android.media.quality.SoundProfile;
+import android.os.PersistableBundle;
+import android.util.Log;
import com.android.server.SystemService;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
/**
* This service manage picture profile and sound profile for TV setting. Also communicates with the
@@ -40,10 +52,14 @@ public class MediaQualityService extends SystemService {
private static final boolean DEBUG = false;
private static final String TAG = "MediaQualityService";
private final Context mContext;
+ private final MediaQualityDbHelper mMediaQualityDbHelper;
public MediaQualityService(Context context) {
super(context);
mContext = context;
+ mMediaQualityDbHelper = new MediaQualityDbHelper(mContext);
+ mMediaQualityDbHelper.setWriteAheadLoggingEnabled(true);
+ mMediaQualityDbHelper.setIdleConnectionTimeout(30);
}
@Override
@@ -53,11 +69,23 @@ public class MediaQualityService extends SystemService {
// TODO: Add additional APIs. b/373951081
private final class BinderService extends IMediaQualityManager.Stub {
+
@Override
public PictureProfile createPictureProfile(PictureProfile pp) {
- // TODO: implement
- return pp;
+ SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+
+ ContentValues values = new ContentValues();
+ values.put(MediaQualityContract.BaseParameters.PARAMETER_TYPE, pp.getProfileType());
+ values.put(MediaQualityContract.BaseParameters.PARAMETER_NAME, pp.getName());
+ values.put(MediaQualityContract.BaseParameters.PARAMETER_PACKAGE, pp.getPackageName());
+ values.put(MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID, pp.getInputId());
+ values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(pp.getParameters()));
+
+ // id is auto-generated by SQLite upon successful insertion of row
+ long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, null, values);
+ return new PictureProfile.Builder(pp).setProfileId(Long.toString(id)).build();
}
+
@Override
public void updatePictureProfile(String id, PictureProfile pp) {
// TODO: implement
@@ -66,21 +94,164 @@ public class MediaQualityService extends SystemService {
public void removePictureProfile(String id) {
// TODO: implement
}
+
@Override
public PictureProfile getPictureProfile(int type, String name) {
- return null;
+ SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+
+ String selection = MediaQualityContract.BaseParameters.PARAMETER_TYPE + " = ? AND "
+ + MediaQualityContract.BaseParameters.PARAMETER_NAME + " = ?";
+ String[] selectionArguments = {Integer.toString(type), name};
+
+ try (
+ Cursor cursor = db.query(
+ mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+ getAllPictureProfileColumns(),
+ selection,
+ selectionArguments,
+ /*groupBy=*/ null,
+ /*having=*/ null,
+ /*orderBy=*/ null)
+ ) {
+ int count = cursor.getCount();
+ if (count == 0) {
+ return null;
+ }
+ if (count > 1) {
+ Log.wtf(TAG, String.format(Locale.US, "%d entries found for type=%d and name=%s"
+ + " in %s. Should only ever be 0 or 1.", count, type, name,
+ mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
+ return null;
+ }
+ cursor.moveToFirst();
+ return getPictureProfileFromCursor(cursor);
+ }
+ }
+
+ private String bundleToJson(PersistableBundle bundle) {
+ JSONObject jsonObject = new JSONObject();
+ if (bundle == null) {
+ return jsonObject.toString();
+ }
+ for (String key : bundle.keySet()) {
+ try {
+ jsonObject.put(key, bundle.getString(key));
+ } catch (JSONException e) {
+ Log.e(TAG, "Unable to serialize ", e);
+ }
+ }
+ return jsonObject.toString();
+ }
+
+ private PersistableBundle jsonToBundle(String jsonString) {
+ JSONObject jsonObject = null;
+ PersistableBundle bundle = new PersistableBundle();
+
+ try {
+ jsonObject = new JSONObject(jsonString);
+
+ Iterator<String> keys = jsonObject.keys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ Object value = jsonObject.get(key);
+
+ if (value instanceof String) {
+ bundle.putString(key, (String) value);
+ } else if (value instanceof Integer) {
+ bundle.putInt(key, (Integer) value);
+ } else if (value instanceof Boolean) {
+ bundle.putBoolean(key, (Boolean) value);
+ } else if (value instanceof Double) {
+ bundle.putDouble(key, (Double) value);
+ } else if (value instanceof Long) {
+ bundle.putLong(key, (Long) value);
+ }
+ }
+ } catch (JSONException e) {
+ throw new RuntimeException(e);
+ }
+
+ return bundle;
+ }
+
+ private String[] getAllPictureProfileColumns() {
+ return new String[]{
+ MediaQualityContract.BaseParameters.PARAMETER_ID,
+ MediaQualityContract.BaseParameters.PARAMETER_TYPE,
+ MediaQualityContract.BaseParameters.PARAMETER_NAME,
+ MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID,
+ MediaQualityContract.BaseParameters.PARAMETER_PACKAGE,
+ mMediaQualityDbHelper.SETTINGS
+ };
+ }
+
+ private PictureProfile getPictureProfileFromCursor(Cursor cursor) {
+ String returnId = cursor.getString(cursor.getColumnIndexOrThrow(
+ MediaQualityContract.BaseParameters.PARAMETER_ID));
+ int type = cursor.getInt(cursor.getColumnIndexOrThrow(
+ MediaQualityContract.BaseParameters.PARAMETER_TYPE));
+ String name = cursor.getString(cursor.getColumnIndexOrThrow(
+ MediaQualityContract.BaseParameters.PARAMETER_NAME));
+ String inputId = cursor.getString(cursor.getColumnIndexOrThrow(
+ MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID));
+ String packageName = cursor.getString(cursor.getColumnIndexOrThrow(
+ MediaQualityContract.BaseParameters.PARAMETER_PACKAGE));
+ String settings = cursor.getString(
+ cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
+ return new PictureProfile(returnId, type, name, inputId,
+ packageName, jsonToBundle(settings));
}
+
@Override
public List<PictureProfile> getPictureProfilesByPackage(String packageName) {
- return new ArrayList<>();
+ String selection = MediaQualityContract.BaseParameters.PARAMETER_PACKAGE + " = ?";
+ String[] selectionArguments = {packageName};
+ return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection,
+ selectionArguments);
}
+
@Override
public List<PictureProfile> getAvailablePictureProfiles() {
return new ArrayList<>();
}
+
@Override
public List<String> getPictureProfilePackageNames() {
- return new ArrayList<>();
+ String [] column = {MediaQualityContract.BaseParameters.PARAMETER_NAME};
+ List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column,
+ null, null);
+ List<String> packageNames = new ArrayList<>();
+ for (PictureProfile pictureProfile: pictureProfiles) {
+ packageNames.add(pictureProfile.getName());
+ }
+ return packageNames;
+ }
+
+ private List<PictureProfile> getPictureProfilesBasedOnConditions(String[] columns,
+ String selection, String[] selectionArguments) {
+ SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+
+ try (
+ Cursor cursor = db.query(
+ mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+ columns,
+ selection,
+ selectionArguments,
+ /*groupBy=*/ null,
+ /*having=*/ null,
+ /*orderBy=*/ null)
+ ) {
+ List<PictureProfile> pictureProfiles = new ArrayList<>();
+ while (cursor.moveToNext()) {
+ pictureProfiles.add(getPictureProfileFromCursor(cursor));
+ }
+ return pictureProfiles;
+ }
+ }
+
+ @Override
+ public PictureProfileHandle getPictureProfileHandle(String id) {
+ return null;
}
@Override
@@ -97,7 +268,7 @@ public class MediaQualityService extends SystemService {
// TODO: implement
}
@Override
- public SoundProfile getSoundProfileById(String id) {
+ public SoundProfile getSoundProfile(int type, String id) {
return null;
}
@Override
@@ -148,6 +319,15 @@ public class MediaQualityService extends SystemService {
}
@Override
+ public List<String> getSoundProfileAllowList() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public void setSoundProfileAllowList(List<String> packages) {
+ }
+
+ @Override
public boolean isSupported() {
return false;
}
@@ -178,5 +358,10 @@ public class MediaQualityService extends SystemService {
public boolean isAutoSoundQualityEnabled() {
return false;
}
+
+ @Override
+ public boolean isAmbientBacklightEnabled() {
+ return false;
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
index 925ba1752fe2..3e96afe9bee3 100644
--- a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
+++ b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
@@ -39,9 +39,11 @@ import android.service.notification.ZenModeConfig.ConfigOrigin;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.Keep;
/** Default implementation for {@link DeviceEffectsApplier}. */
-class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
+@Keep
+public class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
private static final String TAG = "DeviceEffectsApplier";
private static final String SUPPRESS_AMBIENT_DISPLAY_TOKEN =
"DefaultDeviceEffectsApplier:SuppressAmbientDisplay";
@@ -63,10 +65,10 @@ class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
@GuardedBy("mRegisterReceiverLock")
private boolean mIsScreenOffReceiverRegistered;
- private ZenDeviceEffects mLastAppliedEffects = new ZenDeviceEffects.Builder().build();
+ protected ZenDeviceEffects mLastAppliedEffects = new ZenDeviceEffects.Builder().build();
private boolean mPendingNightMode;
- DefaultDeviceEffectsApplier(Context context) {
+ public DefaultDeviceEffectsApplier(Context context) {
mContext = context;
mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
mKeyguardManager = context.getSystemService(KeyguardManager.class);
@@ -79,56 +81,69 @@ class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
@Override
public void apply(ZenDeviceEffects effects, @ConfigOrigin int origin) {
- Binder.withCleanCallingIdentity(() -> {
- if (mLastAppliedEffects.shouldSuppressAmbientDisplay()
- != effects.shouldSuppressAmbientDisplay()) {
- try {
- traceApplyDeviceEffect("suppressAmbientDisplay",
- effects.shouldSuppressAmbientDisplay());
- mPowerManager.suppressAmbientDisplay(SUPPRESS_AMBIENT_DISPLAY_TOKEN,
- effects.shouldSuppressAmbientDisplay());
- } catch (Exception e) {
- Slog.e(TAG, "Could not change AOD override", e);
- }
- }
+ Binder.withCleanCallingIdentity(
+ () -> {
+ maybeSuppressAmbientDisplay(effects.shouldSuppressAmbientDisplay());
+ maybeDisplayGrayscale(effects.shouldDisplayGrayscale());
+ maybeDimWallpaper(effects.shouldDimWallpaper());
+ maybeUseNightMode(effects.shouldUseNightMode(), origin);
+ });
- if (mLastAppliedEffects.shouldDisplayGrayscale() != effects.shouldDisplayGrayscale()) {
- if (mColorDisplayManager != null) {
- try {
- traceApplyDeviceEffect("displayGrayscale",
- effects.shouldDisplayGrayscale());
- mColorDisplayManager.setSaturationLevel(
- effects.shouldDisplayGrayscale() ? SATURATION_LEVEL_GRAYSCALE
- : SATURATION_LEVEL_FULL_COLOR);
- } catch (Exception e) {
- Slog.e(TAG, "Could not change grayscale override", e);
- }
- }
+ mLastAppliedEffects = effects;
+ }
+
+ protected void maybeSuppressAmbientDisplay(boolean shouldSuppressAmbientDisplay) {
+ if (mLastAppliedEffects.shouldSuppressAmbientDisplay() != shouldSuppressAmbientDisplay) {
+ try {
+ traceApplyDeviceEffect("suppressAmbientDisplay", shouldSuppressAmbientDisplay);
+ mPowerManager.suppressAmbientDisplay(
+ SUPPRESS_AMBIENT_DISPLAY_TOKEN, shouldSuppressAmbientDisplay);
+ } catch (Exception e) {
+ Slog.e(TAG, "Could not change AOD override", e);
}
+ }
+ }
- if (mLastAppliedEffects.shouldDimWallpaper() != effects.shouldDimWallpaper()) {
- if (mWallpaperManager != null) {
- try {
- traceApplyDeviceEffect("dimWallpaper", effects.shouldDimWallpaper());
- mWallpaperManager.setWallpaperDimAmount(
- effects.shouldDimWallpaper() ? WALLPAPER_DIM_AMOUNT_DIMMED
- : WALLPAPER_DIM_AMOUNT_NORMAL);
- } catch (Exception e) {
- Slog.e(TAG, "Could not change wallpaper override", e);
- }
+ protected void maybeDisplayGrayscale(boolean shouldDisplayGrayscale) {
+ if (mLastAppliedEffects.shouldDisplayGrayscale() != shouldDisplayGrayscale) {
+ if (mColorDisplayManager != null) {
+ try {
+ traceApplyDeviceEffect("displayGrayscale", shouldDisplayGrayscale);
+ mColorDisplayManager.setSaturationLevel(
+ shouldDisplayGrayscale
+ ? SATURATION_LEVEL_GRAYSCALE
+ : SATURATION_LEVEL_FULL_COLOR);
+ } catch (Exception e) {
+ Slog.e(TAG, "Could not change grayscale override", e);
}
}
+ }
+ }
- if (mLastAppliedEffects.shouldUseNightMode() != effects.shouldUseNightMode()) {
+ protected void maybeDimWallpaper(boolean shouldDimWallpaper) {
+ if (mLastAppliedEffects.shouldDimWallpaper() != shouldDimWallpaper) {
+ if (mWallpaperManager != null) {
try {
- updateOrScheduleNightMode(effects.shouldUseNightMode(), origin);
+ traceApplyDeviceEffect("dimWallpaper", shouldDimWallpaper);
+ mWallpaperManager.setWallpaperDimAmount(
+ shouldDimWallpaper
+ ? WALLPAPER_DIM_AMOUNT_DIMMED
+ : WALLPAPER_DIM_AMOUNT_NORMAL);
} catch (Exception e) {
- Slog.e(TAG, "Could not change dark theme override", e);
+ Slog.e(TAG, "Could not change wallpaper override", e);
}
}
- });
+ }
+ }
- mLastAppliedEffects = effects;
+ protected void maybeUseNightMode(boolean shouldUseNightMode, @ConfigOrigin int origin) {
+ if (mLastAppliedEffects.shouldUseNightMode() != shouldUseNightMode) {
+ try {
+ updateOrScheduleNightMode(shouldUseNightMode, origin);
+ } catch (Exception e) {
+ Slog.e(TAG, "Could not change dark theme override", e);
+ }
+ }
}
private void updateOrScheduleNightMode(boolean useNightMode, @ConfigOrigin int origin) {
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 5914dbe44b0b..f9145514a4e0 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -92,10 +92,16 @@ public class GroupHelper {
static final int REGROUP_REASON_CHANNEL_UPDATE = 0;
// Regrouping needed because of notification bundling
static final int REGROUP_REASON_BUNDLE = 1;
+ // Regrouping needed because of notification unbundling
+ static final int REGROUP_REASON_UNBUNDLE = 2;
+ // Regrouping needed because of notification unbundling + the original group summary exists
+ static final int REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP = 3;
@IntDef(prefix = { "REGROUP_REASON_" }, value = {
REGROUP_REASON_CHANNEL_UPDATE,
REGROUP_REASON_BUNDLE,
+ REGROUP_REASON_UNBUNDLE,
+ REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP,
})
@Retention(RetentionPolicy.SOURCE)
@interface RegroupingReason {}
@@ -103,7 +109,6 @@ public class GroupHelper {
private final Callback mCallback;
private final int mAutoGroupAtCount;
private final int mAutogroupSparseGroupsAtCount;
- private final int mAutoGroupRegroupingAtCount;
private final Context mContext;
private final PackageManager mPackageManager;
private boolean mIsTestHarnessExempted;
@@ -190,11 +195,6 @@ public class GroupHelper {
mContext = context;
mPackageManager = packageManager;
mAutogroupSparseGroupsAtCount = autoGroupSparseGroupsAtCount;
- if (notificationRegroupOnClassification()) {
- mAutoGroupRegroupingAtCount = 1;
- } else {
- mAutoGroupRegroupingAtCount = mAutoGroupAtCount;
- }
NOTIFICATION_SHADE_SECTIONS = getNotificationShadeSections();
}
@@ -755,36 +755,7 @@ public class GroupHelper {
Log.i(TAG, "isGroupChildWithoutSummary OR isGroupSummaryWithoutChild"
+ record);
}
-
- ArrayMap<String, NotificationAttributes> ungrouped =
- mUngroupedAbuseNotifications.getOrDefault(fullAggregateGroupKey,
- new ArrayMap<>());
- ungrouped.put(record.getKey(), new NotificationAttributes(
- record.getFlags(),
- record.getNotification().getSmallIcon(),
- record.getNotification().color,
- record.getNotification().visibility,
- record.getNotification().getGroupAlertBehavior(),
- record.getChannel().getId()));
- mUngroupedAbuseNotifications.put(fullAggregateGroupKey, ungrouped);
- // Create/update summary and group if >= mAutoGroupAtCount notifications
- // or if aggregate group exists
- boolean hasSummary = !mAggregatedNotifications.getOrDefault(fullAggregateGroupKey,
- new ArrayMap<>()).isEmpty();
- if (ungrouped.size() >= mAutoGroupAtCount || hasSummary) {
- if (DEBUG) {
- if (ungrouped.size() >= mAutoGroupAtCount) {
- Log.i(TAG,
- "Found >=" + mAutoGroupAtCount
- + " ungrouped notifications => force grouping");
- } else {
- Log.i(TAG, "Found aggregate summary => force grouping");
- }
- }
- aggregateUngroupedNotifications(fullAggregateGroupKey, sbn.getKey(),
- ungrouped, hasSummary, sectioner.mSummaryId);
- }
-
+ addToUngroupedAndMaybeAggregate(record, fullAggregateGroupKey, sectioner);
return;
}
@@ -797,7 +768,8 @@ public class GroupHelper {
Slog.v(TAG, "isGroupChildInDifferentBundleThanSummary: " + record);
}
moveNotificationsToNewSection(record.getUserId(), pkgName,
- List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey)));
+ List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey)),
+ REGROUP_REASON_BUNDLE);
return;
}
}
@@ -814,6 +786,38 @@ public class GroupHelper {
}
}
+ @GuardedBy("mAggregatedNotifications")
+ private void addToUngroupedAndMaybeAggregate(NotificationRecord record,
+ FullyQualifiedGroupKey fullAggregateGroupKey, NotificationSectioner sectioner) {
+ ArrayMap<String, NotificationAttributes> ungrouped =
+ mUngroupedAbuseNotifications.getOrDefault(fullAggregateGroupKey,
+ new ArrayMap<>());
+ ungrouped.put(record.getKey(), new NotificationAttributes(
+ record.getFlags(),
+ record.getNotification().getSmallIcon(),
+ record.getNotification().color,
+ record.getNotification().visibility,
+ record.getNotification().getGroupAlertBehavior(),
+ record.getChannel().getId()));
+ mUngroupedAbuseNotifications.put(fullAggregateGroupKey, ungrouped);
+ // Create/update summary and group if >= mAutoGroupAtCount notifications
+ // or if aggregate group exists
+ boolean hasSummary = !mAggregatedNotifications.getOrDefault(fullAggregateGroupKey,
+ new ArrayMap<>()).isEmpty();
+ if (ungrouped.size() >= mAutoGroupAtCount || hasSummary) {
+ if (DEBUG) {
+ if (ungrouped.size() >= mAutoGroupAtCount) {
+ Slog.i(TAG, "Found >=" + mAutoGroupAtCount
+ + " ungrouped notifications => force grouping");
+ } else {
+ Slog.i(TAG, "Found aggregate summary => force grouping");
+ }
+ }
+ aggregateUngroupedNotifications(fullAggregateGroupKey, record.getKey(),
+ ungrouped, hasSummary, sectioner.mSummaryId);
+ }
+ }
+
private static boolean isGroupChildBundled(final NotificationRecord record,
final Map<String, NotificationRecord> summaryByGroupKey) {
final StatusBarNotification sbn = record.getSbn();
@@ -896,6 +900,73 @@ public class GroupHelper {
}
}
+ /**
+ * Called when a child notification is removed, after some delay, so that this helper can
+ * trigger a forced grouping if the group has become sparse/singleton
+ * or only the summary is left.
+ *
+ * see also {@link #onNotificationPostedWithDelay(NotificationRecord, List, Map)}
+ *
+ * @param summaryRecord the group summary of the notification that was removed
+ * @param notificationList the full notification list from NotificationManagerService
+ * @param summaryByGroupKey the map of group summaries from NotificationManagerService
+ */
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING)
+ protected void onGroupedNotificationRemovedWithDelay(final NotificationRecord summaryRecord,
+ final List<NotificationRecord> notificationList,
+ final Map<String, NotificationRecord> summaryByGroupKey) {
+ final StatusBarNotification sbn = summaryRecord.getSbn();
+ if (!sbn.isAppGroup()) {
+ return;
+ }
+
+ if (summaryRecord.isCanceled) {
+ return;
+ }
+
+ if (mIsTestHarnessExempted) {
+ return;
+ }
+
+ final NotificationSectioner sectioner = getSection(summaryRecord);
+ if (sectioner == null) {
+ if (DEBUG) {
+ Slog.i(TAG,
+ "Skipping autogrouping for " + summaryRecord + " no valid section found.");
+ }
+ return;
+ }
+
+ final String pkgName = sbn.getPackageName();
+ final FullyQualifiedGroupKey fullAggregateGroupKey = new FullyQualifiedGroupKey(
+ summaryRecord.getUserId(), pkgName, sectioner);
+
+ // This notification is already aggregated
+ if (summaryRecord.getGroupKey().equals(fullAggregateGroupKey.toString())) {
+ return;
+ }
+
+ synchronized (mAggregatedNotifications) {
+ if (isGroupSummaryWithoutChildren(summaryRecord, notificationList)) {
+ if (DEBUG) {
+ Slog.i(TAG, "isGroupSummaryWithoutChild " + summaryRecord);
+ }
+ addToUngroupedAndMaybeAggregate(summaryRecord, fullAggregateGroupKey, sectioner);
+ return;
+ }
+
+ // Check if notification removal turned this group into a sparse/singleton group
+ if (Flags.notificationForceGroupSingletons()) {
+ try {
+ groupSparseGroups(summaryRecord, notificationList, summaryByGroupKey, sectioner,
+ fullAggregateGroupKey);
+ } catch (Throwable e) {
+ Slog.wtf(TAG, "Failed to group sparse groups", e);
+ }
+ }
+ }
+ }
+
private record NotificationMoveOp(NotificationRecord record, FullyQualifiedGroupKey oldGroup,
FullyQualifiedGroupKey newGroup) { }
@@ -945,6 +1016,27 @@ public class GroupHelper {
}
}
+ /**
+ * Called when a notification that was classified (bundled) is restored to its original channel.
+ * The notification will be restored to its original group, if any/if summary still exists.
+ * Otherwise it will be moved to the appropriate section as an ungrouped notification.
+ *
+ * @param record the notification which had its channel updated
+ * @param originalSummaryExists the original group summary exists
+ */
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING)
+ public void onNotificationUnbundled(final NotificationRecord record,
+ final boolean originalSummaryExists) {
+ synchronized (mAggregatedNotifications) {
+ ArrayMap<String, NotificationRecord> notificationsToCheck = new ArrayMap<>();
+ notificationsToCheck.put(record.getKey(), record);
+ regroupNotifications(record.getUserId(), record.getSbn().getPackageName(),
+ notificationsToCheck,
+ originalSummaryExists ? REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP
+ : REGROUP_REASON_UNBUNDLE);
+ }
+ }
+
@GuardedBy("mAggregatedNotifications")
private void regroupNotifications(int userId, String pkgName,
ArrayMap<String, NotificationRecord> notificationsToCheck,
@@ -973,7 +1065,7 @@ public class GroupHelper {
// Batch move to new section
if (!notificationsToMove.isEmpty()) {
- moveNotificationsToNewSection(userId, pkgName, notificationsToMove);
+ moveNotificationsToNewSection(userId, pkgName, notificationsToMove, regroupingReason);
}
}
@@ -1093,7 +1185,7 @@ public class GroupHelper {
@GuardedBy("mAggregatedNotifications")
private void moveNotificationsToNewSection(final int userId, final String pkgName,
- final List<NotificationMoveOp> notificationsToMove) {
+ final List<NotificationMoveOp> notificationsToMove, int regroupingReason) {
record GroupUpdateOp(FullyQualifiedGroupKey groupKey, NotificationRecord record,
boolean hasSummary) { }
// Bundled operations to apply to groups affected by the channel update
@@ -1111,7 +1203,8 @@ public class GroupHelper {
if (DEBUG) {
Log.i(TAG,
"moveNotificationToNewSection: " + record + " " + newFullAggregateGroupKey
- + " from: " + oldFullAggregateGroupKey);
+ + " from: " + oldFullAggregateGroupKey + " regroupingReason: "
+ + regroupingReason);
}
// Update/remove aggregate summary for old group
@@ -1140,28 +1233,35 @@ public class GroupHelper {
// Add moved notifications to the ungrouped list for new group and do grouping
// after all notifications have been handled
if (newFullAggregateGroupKey != null) {
- final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs =
+ if (notificationRegroupOnClassification()
+ && regroupingReason == REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP) {
+ // Just reset override group key, original summary exists
+ // => will be grouped back to its original group
+ record.setOverrideGroupKey(null);
+ } else {
+ final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs =
mAggregatedNotifications.getOrDefault(newFullAggregateGroupKey,
new ArrayMap<>());
- boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty();
- ArrayMap<String, NotificationAttributes> ungrouped =
+ boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty();
+ ArrayMap<String, NotificationAttributes> ungrouped =
mUngroupedAbuseNotifications.getOrDefault(newFullAggregateGroupKey,
new ArrayMap<>());
- ungrouped.put(record.getKey(), new NotificationAttributes(
+ ungrouped.put(record.getKey(), new NotificationAttributes(
record.getFlags(),
record.getNotification().getSmallIcon(),
record.getNotification().color,
record.getNotification().visibility,
record.getNotification().getGroupAlertBehavior(),
record.getChannel().getId()));
- mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped);
+ mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped);
- record.setOverrideGroupKey(null);
+ record.setOverrideGroupKey(null);
- // Only add once, for triggering notification
- if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) {
- groupsToUpdate.put(newFullAggregateGroupKey,
- new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary));
+ // Only add once, for triggering notification
+ if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) {
+ groupsToUpdate.put(newFullAggregateGroupKey,
+ new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary));
+ }
}
}
}
@@ -1176,7 +1276,7 @@ public class GroupHelper {
NotificationRecord triggeringNotification = groupsToUpdate.get(groupKey).record;
boolean hasSummary = groupsToUpdate.get(groupKey).hasSummary;
//Group needs to be created/updated
- if (ungrouped.size() >= mAutoGroupRegroupingAtCount
+ if (ungrouped.size() >= mAutoGroupAtCount
|| (hasSummary && !aggregatedNotificationsAttrs.isEmpty())) {
NotificationSectioner sectioner = getSection(triggeringNotification);
if (sectioner == null) {
@@ -1436,7 +1536,8 @@ public class GroupHelper {
}
}
- private ArrayMap<String, NotificationRecord> getSparseGroups(
+ @VisibleForTesting
+ protected ArrayMap<String, NotificationRecord> getSparseGroups(
final FullyQualifiedGroupKey fullAggregateGroupKey,
final List<NotificationRecord> notificationList,
final Map<String, NotificationRecord> summaryByGroupKey,
@@ -1448,8 +1549,8 @@ public class GroupHelper {
&& summary.getUserId() == fullAggregateGroupKey.userId
&& summary.getSbn().isAppGroup()
&& !summary.getGroupKey().equals(fullAggregateGroupKey.toString())) {
- int numChildren = getNumChildrenForGroup(summary.getSbn().getGroup(),
- notificationList);
+ int numChildren = getNumChildrenForGroupWithSection(summary.getSbn().getGroup(),
+ notificationList, sectioner);
if (numChildren > 0 && numChildren < MIN_CHILD_COUNT_TO_AVOID_FORCE_GROUPING) {
sparseGroups.put(summary.getGroupKey(), summary);
}
@@ -1459,6 +1560,43 @@ public class GroupHelper {
return sparseGroups;
}
+ /**
+ * Get the number of children of a group if all match a certain section.
+ * Used for force grouping sparse groups, where the summary may match a section but the
+ * child notifications do not: ie. conversations
+ *
+ * @param groupKey the group key (name)
+ * @param notificationList all notifications list
+ * @param sectioner the section to match
+ * @return number of children in that group or -1 if section does not match
+ */
+ private int getNumChildrenForGroupWithSection(final String groupKey,
+ final List<NotificationRecord> notificationList,
+ final NotificationSectioner sectioner) {
+ int numChildren = 0;
+ for (NotificationRecord r : notificationList) {
+ if (!r.getNotification().isGroupSummary() && groupKey.equals(r.getSbn().getGroup())) {
+ NotificationSectioner childSection = getSection(r);
+ if (childSection == null || childSection != sectioner) {
+ if (DEBUG) {
+ Slog.i(TAG,
+ "getNumChildrenForGroupWithSection skip because invalid section: "
+ + groupKey + " r: " + r);
+ }
+ return -1;
+ } else {
+ numChildren++;
+ }
+ }
+ }
+
+ if (DEBUG) {
+ Slog.i(TAG,
+ "getNumChildrenForGroupWithSection " + groupKey + " numChild: " + numChildren);
+ }
+ return numChildren;
+ }
+
@GuardedBy("mAggregatedNotifications")
private void cacheCanceledSummary(NotificationRecord record) {
final FullyQualifiedGroupKey groupKey = new FullyQualifiedGroupKey(record.getUserId(),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index d5d4070ee4c3..52ddb800fa40 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -22,8 +22,11 @@ import android.app.NotificationChannelGroup;
import android.app.backup.BackupRestoreEventLogger;
import android.service.notification.DeviceEffectsApplier;
+import com.android.internal.annotations.Keep;
+
import java.util.Set;
+@Keep
public interface NotificationManagerInternal {
NotificationChannel getNotificationChannel(String pkg, int uid, String channelId);
NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String channelId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4d0c7ec64317..15af36ba66af 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -26,6 +26,7 @@ import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
import static android.app.Flags.lifetimeExtensionRefactor;
+import static android.app.Flags.notificationClassificationUi;
import static android.app.Flags.sortSectionByTime;
import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
@@ -211,6 +212,7 @@ import android.app.RemoteServiceException.BadForegroundServiceNotificationExcept
import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException;
import android.app.StatsManager;
import android.app.UriGrantsManager;
+import android.app.ZenBypassingApp;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.backup.BackupManager;
import android.app.backup.BackupRestoreEventLogger;
@@ -238,7 +240,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.ModuleInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
@@ -3089,7 +3090,7 @@ public class NotificationManagerService extends SystemService {
migrateDefaultNAS();
maybeShowInitialReviewPermissionsNotification();
- if (android.app.Flags.modesApi()) {
+ if (android.app.Flags.modesApi() && !mZenModeHelper.hasDeviceEffectsApplier()) {
// Cannot be done earlier, as some services aren't ready until this point.
mZenModeHelper.setDeviceEffectsApplier(
new DefaultDeviceEffectsApplier(getContext()));
@@ -4043,7 +4044,7 @@ public class NotificationManagerService extends SystemService {
"canNotifyAsPackage for uid " + uid);
}
- return areNotificationsEnabledForPackageInt(pkg, uid);
+ return areNotificationsEnabledForPackageInt(uid);
}
/**
@@ -4225,6 +4226,22 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public @NonNull String[] getTypeAdjustmentDeniedPackages() {
+ checkCallerIsSystemOrSystemUiOrShell();
+ return mAssistants.getTypeAdjustmentDeniedPackages();
+ }
+
+ @Override
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+ checkCallerIsSystemOrSystemUiOrShell();
+ mAssistants.setTypeAdjustmentForPackageState(pkg, enabled);
+
+ handleSavePolicyFile();
+ }
+
+ @Override
@FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
public boolean appCanBePromoted(String pkg, int uid) {
checkCallerIsSystemOrSystemUiOrShell();
@@ -4864,30 +4881,20 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public List<String> getPackagesBypassingDnd(int userId,
- boolean includeConversationChannels) {
+ public ParceledListSlice<ZenBypassingApp> getPackagesBypassingDnd(int userId)
+ throws RemoteException {
checkCallerIsSystem();
- final ArraySet<String> packageNames = new ArraySet<>();
-
- List<PackageInfo> pkgs = mPackageManagerClient.getInstalledPackagesAsUser(0, userId);
- for (PackageInfo pi : pkgs) {
- String pkg = pi.packageName;
- // If any NotificationChannel for this package is bypassing, the
- // package is considered bypassing.
- for (NotificationChannel channel : getNotificationChannelsBypassingDnd(pkg,
- pi.applicationInfo.uid).getList()) {
- // Skips non-demoted conversation channels.
- if (!includeConversationChannels
- && !TextUtils.isEmpty(channel.getConversationId())
- && !channel.isDemoted()) {
- continue;
- }
- packageNames.add(pkg);
+ UserHandle user = UserHandle.of(userId);
+ ArrayList<ZenBypassingApp> bypassing =
+ mPreferencesHelper.getPackagesBypassingDnd(userId);
+ for (int i = bypassing.size() - 1; i >= 0; i--) {
+ String pkg = bypassing.get(i).getPkg();
+ if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) {
+ bypassing.remove(i);
}
}
-
- return new ArrayList<String>(packageNames);
+ return new ParceledListSlice<>(bypassing);
}
@Override
@@ -6590,6 +6597,14 @@ public class NotificationManagerService extends SystemService {
android.Manifest.permission.INTERACT_ACROSS_USERS,
"setNotificationListenerAccessGrantedForUser for user " + userId);
}
+ if (mUmInternal.isVisibleBackgroundFullUser(userId)) {
+ // The main use case for visible background users is the Automotive multi-display
+ // configuration where a passenger can use a secondary display while the driver is
+ // using the main display. NotificationListeners is designed only for the current
+ // user and work profile. We added a condition to prevent visible background users
+ // from updating the data managed within the NotificationListeners object.
+ return;
+ }
checkNotificationListenerAccess();
if (granted && listener.flattenToString().length()
> NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
@@ -7016,6 +7031,10 @@ public class NotificationManagerService extends SystemService {
if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) {
toRemove.add(potentialKey);
+ } else if (notificationClassificationUi()
+ && !mAssistants.isTypeAdjustmentAllowedForPackage(
+ r.getSbn().getPackageName())) {
+ toRemove.add(potentialKey);
}
}
}
@@ -7190,13 +7209,16 @@ public class NotificationManagerService extends SystemService {
Slog.i(TAG, "Removing app summary (all children bundled): "
+ groupSummary);
}
- canceledSummary = groupSummary;
- mSummaryByGroupKey.remove(oldGroupKey);
- cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(),
+ if (convertSummaryToNotificationLocked(groupSummary.getKey())) {
+ groupSummary.isCanceled = true;
+ canceledSummary = groupSummary;
+ mSummaryByGroupKey.remove(oldGroupKey);
+ cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(),
groupSummary.getSbn().getPackageName(),
groupSummary.getSbn().getTag(),
groupSummary.getSbn().getId(), 0, 0, false, groupSummary.getUserId(),
NotificationListenerService.REASON_GROUP_OPTIMIZATION, null);
+ }
}
}
}
@@ -7763,7 +7785,7 @@ public class NotificationManagerService extends SystemService {
@Override
public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
- return areNotificationsEnabledForPackageInt(pkg, uid);
+ return areNotificationsEnabledForPackageInt(uid);
}
@Override
@@ -8742,7 +8764,7 @@ public class NotificationManagerService extends SystemService {
}
// blocked apps
- boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid);
+ boolean isBlocked = !areNotificationsEnabledForPackageInt(uid);
synchronized (mNotificationLock) {
isBlocked |= isRecordBlockedLocked(r);
}
@@ -8792,7 +8814,7 @@ public class NotificationManagerService extends SystemService {
}
}
- private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
+ private boolean areNotificationsEnabledForPackageInt(int uid) {
return mPermissionHelper.hasPermission(uid);
}
@@ -9328,7 +9350,7 @@ public class NotificationManagerService extends SystemService {
* notifying all listeners to a background thread; false otherwise.
*/
private boolean postNotification() {
- boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid);
+ boolean appBanned = !areNotificationsEnabledForPackageInt(uid);
boolean isCallNotification = isCallNotification(pkg, uid);
boolean posted = false;
synchronized (NotificationManagerService.this.mNotificationLock) {
@@ -10507,6 +10529,27 @@ public class NotificationManagerService extends SystemService {
mGroupHelper.onNotificationRemoved(r, mNotificationList);
}
});
+
+ // Wait 3 seconds so that the app has a chance to cancel/post
+ // a group summary or children
+ final NotificationRecord groupSummary = mSummaryByGroupKey.get(r.getGroupKey());
+ if (groupSummary != null
+ && !GroupHelper.isAggregatedGroup(groupSummary)
+ && !groupSummary.getKey().equals(canceledKey)) {
+ // We only care about app-provided valid group summaries
+ final String summaryKey = groupSummary.getKey();
+ mHandler.removeCallbacksAndEqualMessages(summaryKey);
+ mHandler.postDelayed(() -> {
+ synchronized (mNotificationLock) {
+ NotificationRecord summaryRecord = mNotificationsByKey.get(
+ summaryKey);
+ if (summaryRecord != null) {
+ mGroupHelper.onGroupedNotificationRemovedWithDelay(
+ summaryRecord, mNotificationList, mSummaryByGroupKey);
+ }
+ }
+ }, summaryKey, DELAY_FORCE_REGROUP_TIME);
+ }
} else {
mHandler.post(new Runnable() {
@Override
@@ -11650,6 +11693,7 @@ public class NotificationManagerService extends SystemService {
private static final String ATT_DENIED = "denied_adjustments";
private static final String ATT_ENABLED_TYPES = "enabled_key_types";
private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
+ private static final String ATT_TYPES_DENIED_APPS = "types_denied_apps";
private final Object mLock = new Object();
@@ -11665,6 +11709,9 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mLock")
private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private Set<String> mClassificationTypeDeniedPackages = new ArraySet<>();
+
protected ComponentName mDefaultFromConfig = null;
@Override
@@ -11864,6 +11911,44 @@ public class NotificationManagerService extends SystemService {
}
}
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ protected @NonNull boolean isTypeAdjustmentAllowedForPackage(String pkg) {
+ synchronized (mLock) {
+ if (notificationClassificationUi()) {
+ return !mClassificationTypeDeniedPackages.contains(pkg);
+ }
+ }
+ return true;
+ }
+
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ protected @NonNull String[] getTypeAdjustmentDeniedPackages() {
+ synchronized (mLock) {
+ if (notificationClassificationUi()) {
+ return mClassificationTypeDeniedPackages.toArray(new String[0]);
+ }
+ }
+ return new String[]{};
+ }
+
+ /**
+ * Set whether a particular package can have its notification channels adjusted to have a
+ * different type by NotificationAssistants.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+ if (!notificationClassificationUi()) {
+ return;
+ }
+ synchronized (mLock) {
+ if (enabled) {
+ mClassificationTypeDeniedPackages.remove(pkg);
+ } else {
+ mClassificationTypeDeniedPackages.add(pkg);
+ }
+ }
+ }
+
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
ArrayList<String> keys = new ArrayList<>(records.size());
@@ -11947,18 +12032,23 @@ public class NotificationManagerService extends SystemService {
TrimCache trimCache = new TrimCache(sbn);
final INotificationListener assistant = (INotificationListener) info.service;
final StatusBarNotification sbnToPost = trimCache.ForListener(info);
- final StatusBarNotificationHolder sbnHolder =
- new StatusBarNotificationHolder(sbnToPost);
+ final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
+
try {
- if (debug) {
- Slog.v(TAG,
- "calling onNotificationEnqueuedWithChannel " + sbnHolder);
+ if (android.app.Flags.noSbnholder()) {
+ assistant.onNotificationEnqueuedWithChannelFull(sbnToPost,
+ r.getChannel(), update);
+ } else {
+ final StatusBarNotificationHolder sbnHolder =
+ new StatusBarNotificationHolder(sbnToPost);
+
+ assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(),
+ update);
}
- final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
- assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(),
- update);
+ } catch (DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify assistant (enqueued): " + info, ex);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (enqueued): " + info, ex);
}
}
}
@@ -11976,7 +12066,7 @@ public class NotificationManagerService extends SystemService {
r.getSbn(),
r.getNotificationType(),
true /* sameUserOnly */,
- (assistant, sbnHolder) -> {
+ (assistant, unused) -> {
try {
assistant.onNotificationVisibilityChanged(key, isVisible);
} catch (RemoteException ex) {
@@ -11996,7 +12086,7 @@ public class NotificationManagerService extends SystemService {
sbn,
notificationType,
true /* sameUserOnly */,
- (assistant, sbnHolder) -> {
+ (assistant, unused) -> {
try {
assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
} catch (RemoteException ex) {
@@ -12013,7 +12103,7 @@ public class NotificationManagerService extends SystemService {
r.getSbn(),
r.getNotificationType(),
true /* sameUserOnly */,
- (assistant, sbnHolder) -> {
+ (assistant, unused) -> {
try {
assistant.onNotificationDirectReply(key);
} catch (RemoteException ex) {
@@ -12031,7 +12121,7 @@ public class NotificationManagerService extends SystemService {
sbn,
notificationType,
true /* sameUserOnly */,
- (assistant, sbnHolder) -> {
+ (assistant, unused) -> {
try {
assistant.onSuggestedReplySent(
key,
@@ -12054,7 +12144,7 @@ public class NotificationManagerService extends SystemService {
r.getSbn(),
r.getNotificationType(),
true /* sameUserOnly */,
- (assistant, sbnHolder) -> {
+ (assistant, unused) -> {
try {
assistant.onActionClicked(
key,
@@ -12079,12 +12169,21 @@ public class NotificationManagerService extends SystemService {
r.getSbn(),
r.getNotificationType(),
true /* sameUserOnly */,
- (assistant, sbnHolder) -> {
+ (info, sbnToPost) -> {
try {
- assistant.onNotificationSnoozedUntilContext(
- sbnHolder, snoozeCriterionId);
+ if (android.app.Flags.noSbnholder()) {
+ info.onNotificationSnoozedUntilContextFull(
+ sbnToPost, snoozeCriterionId);
+ } else {
+ final StatusBarNotificationHolder sbnHolder =
+ new StatusBarNotificationHolder(sbnToPost);
+ info.onNotificationSnoozedUntilContext(
+ sbnHolder, snoozeCriterionId);
+ }
+ } catch (DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify assistant (snoozed): " + info, ex);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (snoozed): " + info, ex);
}
});
}
@@ -12096,7 +12195,7 @@ public class NotificationManagerService extends SystemService {
r.getSbn(),
r.getNotificationType(),
true /* sameUserOnly */,
- (assistant, sbnHolder) -> {
+ (assistant, unused) -> {
try {
assistant.onNotificationClicked(key);
} catch (RemoteException ex) {
@@ -12139,7 +12238,7 @@ public class NotificationManagerService extends SystemService {
final StatusBarNotification sbn,
int notificationType,
boolean sameUserOnly,
- BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
+ BiConsumer<INotificationListener, StatusBarNotification> callback) {
TrimCache trimCache = new TrimCache(sbn);
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
@@ -12161,9 +12260,7 @@ public class NotificationManagerService extends SystemService {
}
final INotificationListener assistant = (INotificationListener) info.service;
final StatusBarNotification sbnToPost = trimCache.ForListener(info);
- final StatusBarNotificationHolder sbnHolder =
- new StatusBarNotificationHolder(sbnToPost);
- mHandler.post(() -> callback.accept(assistant, sbnHolder));
+ mHandler.post(() -> callback.accept(assistant, sbnToPost));
}
}
@@ -12314,6 +12411,12 @@ public class NotificationManagerService extends SystemService {
out.attribute(null, ATT_TYPES,
TextUtils.join(",", mAllowedAdjustmentKeyTypes));
out.endTag(null, ATT_ENABLED_TYPES);
+ if (notificationClassificationUi()) {
+ out.startTag(null, ATT_TYPES_DENIED_APPS);
+ out.attribute(null, ATT_TYPES,
+ TextUtils.join(",", mClassificationTypeDeniedPackages));
+ out.endTag(null, ATT_TYPES_DENIED_APPS);
+ }
}
}
@@ -12345,6 +12448,14 @@ public class NotificationManagerService extends SystemService {
}
}
}
+ } else if (notificationClassificationUi() && ATT_TYPES_DENIED_APPS.equals(tag)) {
+ final String apps = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+ synchronized (mLock) {
+ mClassificationTypeDeniedPackages.clear();
+ if (!TextUtils.isEmpty(apps)) {
+ mClassificationTypeDeniedPackages.addAll(Arrays.asList(apps.split(",")));
+ }
+ }
}
}
@@ -12643,6 +12754,20 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void onUserUnlocked(int user) {
+ if (mUmInternal.isVisibleBackgroundFullUser(user)) {
+ // The main use case for visible background users is the Automotive
+ // multi-display configuration where a passenger can use a secondary
+ // display while the driver is using the main display.
+ // NotificationListeners is designed only for the current user and work
+ // profile. We added a condition to prevent visible background users from
+ // updating the data managed within the NotificationListeners object.
+ return;
+ }
+ super.onUserUnlocked(user);
+ }
+
+ @Override
protected boolean allowRebindForParentUser() {
return true;
}
@@ -13409,9 +13534,13 @@ public class NotificationManagerService extends SystemService {
private void notifyPosted(final ManagedServiceInfo info,
final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
final INotificationListener listener = (INotificationListener) info.service;
- StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
- listener.onNotificationPosted(sbnHolder, rankingUpdate);
+ if (android.app.Flags.noSbnholder()) {
+ listener.onNotificationPostedFull(sbn, rankingUpdate);
+ } else {
+ StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
+ listener.onNotificationPosted(sbnHolder, rankingUpdate);
+ }
} catch (DeadObjectException ex) {
Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex);
} catch (RemoteException ex) {
@@ -13422,7 +13551,6 @@ public class NotificationManagerService extends SystemService {
private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
final INotificationListener listener = (INotificationListener) info.service;
- StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
if (!CompatChanges.isChangeEnabled(NOTIFICATION_CANCELLATION_REASONS, info.uid)
&& (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) {
@@ -13434,7 +13562,12 @@ public class NotificationManagerService extends SystemService {
&& reason == REASON_ASSISTANT_CANCEL) {
reason = REASON_LISTENER_CANCEL;
}
- listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
+ if (android.app.Flags.noSbnholder()) {
+ listener.onNotificationRemovedFull(sbn, rankingUpdate, stats, reason);
+ } else {
+ StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
+ listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
+ }
} catch (DeadObjectException ex) {
Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex);
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 9f0b4b0b6299..749952e3336f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -57,6 +57,7 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.app.ZenBypassingApp;
import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -183,6 +184,7 @@ public class PreferencesHelper implements RankingConfig {
private static final boolean DEFAULT_SHOW_BADGE = true;
private static final boolean DEFAULT_APP_LOCKED_IMPORTANCE = false;
+ private static final boolean DEFAULT_CAN_HAVE_PROMOTED_NOTIFS = true;
static final boolean DEFAULT_BUBBLES_ENABLED = true;
@VisibleForTesting
@@ -368,8 +370,8 @@ public class PreferencesHelper implements RankingConfig {
null, ATT_USER_DEMOTED_INVALID_MSG_APP, false);
r.hasSentValidBubble = parser.getAttributeBoolean(null, ATT_SENT_VALID_BUBBLE, false);
if (android.app.Flags.uiRichOngoing()) {
- r.canHavePromotedNotifs =
- parser.getAttributeBoolean(null, ATT_PROMOTE_NOTIFS, false);
+ r.canHavePromotedNotifs = parser.getAttributeBoolean(null, ATT_PROMOTE_NOTIFS,
+ DEFAULT_CAN_HAVE_PROMOTED_NOTIFS);
}
final int innerDepth = parser.getDepth();
@@ -747,7 +749,7 @@ public class PreferencesHelper implements RankingConfig {
r.userDemotedMsgApp);
out.attributeBoolean(null, ATT_SENT_VALID_BUBBLE, r.hasSentValidBubble);
if (android.app.Flags.uiRichOngoing()) {
- if (r.canHavePromotedNotifs) {
+ if (r.canHavePromotedNotifs != DEFAULT_CAN_HAVE_PROMOTED_NOTIFS) {
out.attributeBoolean(null, ATT_PROMOTE_NOTIFS, r.canHavePromotedNotifs);
}
}
@@ -1950,6 +1952,35 @@ public class PreferencesHelper implements RankingConfig {
}
/**
+ * Gets all apps that can bypass DND, and a boolean indicating whether all (true) or some
+ * (false) of its notification channels can currently bypass.
+ */
+ public @NonNull ArrayList<ZenBypassingApp> getPackagesBypassingDnd(@UserIdInt int userId) {
+ ArrayList<ZenBypassingApp> bypassing = new ArrayList<>();
+ synchronized (mLock) {
+ for (PackagePreferences p : mPackagePreferences.values()) {
+ if (p.userId != userId) {
+ continue;
+ }
+ int totalChannelCount = p.channels.size();
+ int bypassingCount = 0;
+ if (totalChannelCount == 0) {
+ continue;
+ }
+ for (NotificationChannel channel : p.channels.values()) {
+ if (channelIsLiveLocked(p, channel) && channel.canBypassDnd()) {
+ bypassingCount++;
+ }
+ }
+ if (bypassingCount > 0) {
+ bypassing.add(new ZenBypassingApp(p.pkg, totalChannelCount == bypassingCount));
+ }
+ }
+ }
+ return bypassing;
+ }
+
+ /**
* True for pre-O apps that only have the default channel, or pre O apps that have no
* channels yet. This method will create the default channel for pre-O apps that don't have it.
* Should never be true for O+ targeting apps, but that's enforced on boot/when an app
@@ -2301,7 +2332,8 @@ public class PreferencesHelper implements RankingConfig {
pw.print(" fixedImportance=");
pw.print(r.fixedImportance);
}
- if (android.app.Flags.uiRichOngoing() && r.canHavePromotedNotifs) {
+ if (android.app.Flags.uiRichOngoing()
+ && r.canHavePromotedNotifs != DEFAULT_CAN_HAVE_PROMOTED_NOTIFS) {
pw.print(" promoted=");
pw.print(r.canHavePromotedNotifs);
}
@@ -3154,7 +3186,8 @@ public class PreferencesHelper implements RankingConfig {
long creationTime;
@FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
- boolean canHavePromotedNotifs = false;
+ // Until we enable the UI, we should return false.
+ boolean canHavePromotedNotifs = android.app.Flags.uiRichOngoing();
@UserIdInt int userId;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index cfeacdf2bb0d..dc173b124884 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -24,6 +24,8 @@ import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_UNKNOWN;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
+import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
+import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING;
import static android.service.notification.Condition.SOURCE_UNKNOWN;
import static android.service.notification.Condition.SOURCE_USER_ACTION;
import static android.service.notification.Condition.STATE_FALSE;
@@ -44,8 +46,6 @@ import static android.service.notification.ZenModeConfig.isImplicitRuleId;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import static com.android.internal.util.Preconditions.checkArgument;
-import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
-import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING;
import static java.util.Objects.requireNonNull;
@@ -303,6 +303,15 @@ public class ZenModeHelper {
}
/**
+ * @return whether a {@link DeviceEffectsApplier} has already been set or not
+ */
+ boolean hasDeviceEffectsApplier() {
+ synchronized (mConfigLock) {
+ return mDeviceEffectsApplier != null;
+ }
+ }
+
+ /**
* Set the {@link DeviceEffectsApplier} used to apply the consolidated effects.
*
* <p>Previously calculated effects (as loaded from the user's {@link ZenModeConfig}) will be
@@ -1006,7 +1015,13 @@ public class ZenModeHelper {
private static void applyConditionAndReconsiderOverride(ZenRule rule, Condition condition,
int origin) {
if (Flags.modesApi() && Flags.modesUi()) {
- if (origin == ORIGIN_USER_IN_SYSTEMUI && condition != null
+ if (isImplicitRuleId(rule.id)) {
+ // Implicit rules do not use overrides, and always apply conditions directly.
+ // This is compatible with the previous behavior (where the package set the
+ // interruption filter, and no "snoozing" took place if the user changed it later).
+ rule.condition = condition;
+ rule.resetConditionOverride();
+ } else if (origin == ORIGIN_USER_IN_SYSTEMUI && condition != null
&& condition.source == SOURCE_USER_ACTION) {
// Apply as override, instead of actual condition.
// If the new override is the reverse of a previous (still active) override, try
@@ -1926,7 +1941,17 @@ public class ZenModeHelper {
@Nullable
public Policy getNotificationPolicy(UserHandle user) {
synchronized (mConfigLock) {
- return getNotificationPolicy(getConfigLocked(user));
+ if (Flags.modesMultiuser()) {
+ // Return a fallback (default) policy for users without a zen config.
+ // Note that zen updates (setPolicy, setFilter) won't be applied, so this is mostly
+ // about preventing NPEs for careless callers.
+ ZenModeConfig config = getConfigLocked(user);
+ return config != null
+ ? getNotificationPolicy(config)
+ : getNotificationPolicy(mDefaultConfig);
+ } else {
+ return getNotificationPolicy(getConfigLocked(user));
+ }
}
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/InferenceInfoStore.java b/services/core/java/com/android/server/ondeviceintelligence/InferenceInfoStore.java
index b532d5a8f8fc..bef3f8048da1 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/InferenceInfoStore.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/InferenceInfoStore.java
@@ -20,8 +20,8 @@ import android.app.ondeviceintelligence.InferenceInfo;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService;
-import android.util.Slog;
import android.util.Base64;
+import android.util.Slog;
import java.io.IOException;
import java.util.Comparator;
@@ -36,12 +36,12 @@ public class InferenceInfoStore {
public InferenceInfoStore(long maxAgeMs) {
this.maxAgeMs = maxAgeMs;
this.inferenceInfos = new TreeSet<>(
- Comparator.comparingLong(InferenceInfo::getStartTimeMs));
+ Comparator.comparingLong(InferenceInfo::getStartTimeMillis));
}
public List<InferenceInfo> getLatestInferenceInfo(long startTimeEpochMillis) {
return inferenceInfos.stream().filter(
- info -> info.getStartTimeMs() > startTimeEpochMillis).toList();
+ info -> info.getStartTimeMillis() > startTimeEpochMillis).toList();
}
public void addInferenceInfoFromBundle(PersistableBundle pb) {
@@ -85,7 +85,7 @@ public class InferenceInfoStore {
private synchronized void add(com.android.server.ondeviceintelligence.nano.InferenceInfo info) {
while (!inferenceInfos.isEmpty()
- && System.currentTimeMillis() - inferenceInfos.first().getStartTimeMs()
+ && System.currentTimeMillis() - inferenceInfos.first().getStartTimeMillis()
> maxAgeMs) {
inferenceInfos.pollFirst();
}
@@ -94,8 +94,8 @@ public class InferenceInfoStore {
private static InferenceInfo toInferenceInfo(
com.android.server.ondeviceintelligence.nano.InferenceInfo info) {
- return new InferenceInfo.Builder().setUid(info.uid).setStartTimeMs(
- info.startTimeMs).setEndTimeMs(info.endTimeMs).setSuspendedTimeMs(
+ return new InferenceInfo.Builder(info.uid).setStartTimeMillis(
+ info.startTimeMs).setEndTimeMillis(info.endTimeMs).setSuspendedTimeMillis(
info.suspendedTimeMs).build();
}
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 9f4b9f1c1f24..6d54be84d5e5 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -58,6 +58,7 @@ import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.provider.DeviceConfig;
import android.stats.storage.StorageEnums;
+import android.text.TextUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
@@ -355,7 +356,8 @@ public final class BroadcastHelper {
@Nullable int[] userIds,
@Nullable int[] instantUserIds,
@Nullable SparseArray<int[]> broadcastAllowList,
- @NonNull AndroidPackage pkg) {
+ @NonNull AndroidPackage pkg,
+ @NonNull String[] sharedUidPackages) {
final boolean isForWholeApp = componentNames.contains(packageName);
if (isForWholeApp || !android.content.pm.Flags.reduceBroadcastsForComponentStateChanges()) {
sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames,
@@ -374,20 +376,36 @@ public final class BroadcastHelper {
exportedComponentNames.removeAll(notExportedComponentNames);
if (!notExportedComponentNames.isEmpty()) {
- // Limit sending of the PACKAGE_CHANGED broadcast to only the system and the
- // application itself when the component is not exported.
+ // Limit sending of the PACKAGE_CHANGED broadcast to only the system, the application
+ // itself and applications with the same UID when the component is not exported.
// First, send the PACKAGE_CHANGED broadcast to the system.
- sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
- notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
- broadcastAllowList, "android" /* targetPackageName */,
- new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
+ if (!TextUtils.equals(packageName, "android")) {
+ sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
+ notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
+ broadcastAllowList, "android" /* targetPackageName */,
+ new String[]{
+ PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
+ }
// Second, send the PACKAGE_CHANGED broadcast to the application itself.
sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
broadcastAllowList, packageName /* targetPackageName */,
null /* requiredPermissions */);
+
+ // Third, send the PACKAGE_CHANGED broadcast to the applications with the same UID.
+ for (int i = 0; i < sharedUidPackages.length; i++) {
+ final String sharedPackage = sharedUidPackages[i];
+ if (TextUtils.equals(packageName, sharedPackage)) {
+ continue;
+ }
+ sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
+ notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
+ broadcastAllowList, sharedPackage /* targetPackageName */,
+ null /* requiredPermissions */);
+ }
+
}
if (!exportedComponentNames.isEmpty()) {
@@ -936,7 +954,8 @@ public final class BroadcastHelper {
isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds);
mHandler.post(() -> sendPackageChangedBroadcastInternal(
packageName, dontKillApp, componentNames, packageUid, reason, userIds,
- instantUserIds, broadcastAllowList, setting.getPkg()));
+ instantUserIds, broadcastAllowList, setting.getPkg(),
+ snapshot.getSharedUserPackagesForPackage(packageName, userId)));
mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames,
packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler);
}
diff --git a/services/core/java/com/android/server/pm/InstallDependencyHelper.java b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
index 745665bab5b3..5bd2c994160c 100644
--- a/services/core/java/com/android/server/pm/InstallDependencyHelper.java
+++ b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
@@ -16,52 +16,386 @@
package com.android.server.pm;
+import static android.content.pm.PackageInstaller.ACTION_INSTALL_DEPENDENCY;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
+import static android.os.Process.SYSTEM_UID;
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.ResolveInfo;
import android.content.pm.SharedLibraryInfo;
+import android.content.pm.dependencyinstaller.DependencyInstallerCallback;
+import android.content.pm.dependencyinstaller.IDependencyInstallerCallback;
+import android.content.pm.dependencyinstaller.IDependencyInstallerService;
import android.content.pm.parsing.PackageLite;
+import android.os.Handler;
import android.os.OutcomeReceiver;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
+
+import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/**
* Helper class to interact with SDK Dependency Installer service.
*/
public class InstallDependencyHelper {
+ private static final String TAG = InstallDependencyHelper.class.getSimpleName();
+ private static final boolean DEBUG = true;
+ // The maximum amount of time to wait before the system unbinds from the verifier.
+ private static final long UNBIND_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(6);
+ private static final long REQUEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(1);
+
+ private final Context mContext;
private final SharedLibrariesImpl mSharedLibraries;
+ private final PackageInstallerService mPackageInstallerService;
+ private final Object mRemoteServiceLock = new Object();
+ @GuardedBy("mTrackers")
+ private final List<DependencyInstallTracker> mTrackers = new ArrayList<>();
+
+ @GuardedBy("mRemoteServiceLock")
+ private ServiceConnector<IDependencyInstallerService> mRemoteService = null;
- InstallDependencyHelper(SharedLibrariesImpl sharedLibraries) {
+ InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries,
+ PackageInstallerService packageInstallerService) {
+ mContext = context;
mSharedLibraries = sharedLibraries;
+ mPackageInstallerService = packageInstallerService;
}
- void resolveLibraryDependenciesIfNeeded(PackageLite pkg,
- OutcomeReceiver<Void, PackageManagerException> callback) {
- final List<SharedLibraryInfo> missing;
+ void resolveLibraryDependenciesIfNeeded(PackageLite pkg, Computer snapshot, int userId,
+ Handler handler, OutcomeReceiver<Void, PackageManagerException> origCallback) {
+ CallOnceProxy callback = new CallOnceProxy(handler, origCallback);
try {
- missing = mSharedLibraries.collectMissingSharedLibraryInfos(pkg);
+ resolveLibraryDependenciesIfNeededInternal(pkg, snapshot, userId, handler, callback);
} catch (PackageManagerException e) {
callback.onError(e);
- return;
+ } catch (Exception e) {
+ onError(callback, e.getMessage());
}
+ }
+
+
+ private void resolveLibraryDependenciesIfNeededInternal(PackageLite pkg, Computer snapshot,
+ int userId, Handler handler, CallOnceProxy callback) throws PackageManagerException {
+ final List<SharedLibraryInfo> missing =
+ mSharedLibraries.collectMissingSharedLibraryInfos(pkg);
if (missing.isEmpty()) {
+ if (DEBUG) {
+ Slog.i(TAG, "No missing dependency for " + pkg);
+ }
// No need for dependency resolution. Move to installation directly.
callback.onResult(null);
return;
}
- try {
- bindToDependencyInstaller();
- } catch (Exception e) {
- PackageManagerException pe = new PackageManagerException(
- INSTALL_FAILED_MISSING_SHARED_LIBRARY, e.getMessage());
- callback.onError(pe);
+ if (!bindToDependencyInstallerIfNeeded(userId, handler, snapshot)) {
+ onError(callback, "Dependency Installer Service not found");
+ return;
+ }
+
+ IDependencyInstallerCallback serviceCallback =
+ new DependencyInstallerCallbackCallOnce(handler, callback);
+ boolean scheduleSuccess;
+ synchronized (mRemoteServiceLock) {
+ scheduleSuccess = mRemoteService.run(service -> {
+ service.onDependenciesRequired(missing,
+ new DependencyInstallerCallback(serviceCallback.asBinder()));
+ });
+ }
+ if (!scheduleSuccess) {
+ onError(callback, "Failed to schedule job on Dependency Installer Service");
}
}
- private void bindToDependencyInstaller() {
- throw new IllegalStateException("Failed to bind to Dependency Installer");
+ void notifySessionComplete(int sessionId, boolean success) {
+ if (DEBUG) {
+ Slog.i(TAG, "Session complete for " + sessionId + " result: " + success);
+ }
+ synchronized (mTrackers) {
+ List<DependencyInstallTracker> completedTrackers = new ArrayList<>();
+ for (DependencyInstallTracker tracker: mTrackers) {
+ if (!tracker.onSessionComplete(sessionId, success)) {
+ completedTrackers.add(tracker);
+ }
+ }
+ mTrackers.removeAll(completedTrackers);
+ }
}
+ private static void onError(CallOnceProxy callback, String msg) {
+ PackageManagerException pe = new PackageManagerException(
+ INSTALL_FAILED_MISSING_SHARED_LIBRARY, msg);
+ callback.onError(pe);
+ if (DEBUG) {
+ Slog.i(TAG, "Orig session error: " + msg);
+ }
+ }
+
+ private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler,
+ Computer snapshot) {
+ synchronized (mRemoteServiceLock) {
+ if (mRemoteService != null) {
+ if (DEBUG) {
+ Slog.i(TAG, "DependencyInstallerService already bound");
+ }
+ return true;
+ }
+ }
+
+ Intent serviceIntent = new Intent(ACTION_INSTALL_DEPENDENCY);
+ // TODO(b/372862145): Use RoleManager to find the package name
+ List<ResolveInfo> resolvedIntents = snapshot.queryIntentServicesInternal(
+ serviceIntent, /*resolvedType=*/ null, /*flags=*/0,
+ userId, SYSTEM_UID, Process.INVALID_PID,
+ /*includeInstantApps*/ false, /*resolveForStart*/ false);
+
+ if (resolvedIntents.isEmpty()) {
+ return false;
+ }
+
+
+ ResolveInfo resolveInfo = resolvedIntents.getFirst();
+ ComponentName componentName = resolveInfo.getComponentInfo().getComponentName();
+ serviceIntent.setComponent(componentName);
+
+ ServiceConnector<IDependencyInstallerService> serviceConnector =
+ new ServiceConnector.Impl<IDependencyInstallerService>(mContext, serviceIntent,
+ Context.BIND_AUTO_CREATE, userId,
+ IDependencyInstallerService.Stub::asInterface) {
+ @Override
+ protected Handler getJobHandler() {
+ return handler;
+ }
+
+ @Override
+ protected long getRequestTimeoutMs() {
+ return REQUEST_TIMEOUT_MILLIS;
+ }
+
+ @Override
+ protected long getAutoDisconnectTimeoutMs() {
+ return UNBIND_TIMEOUT_MILLIS;
+ }
+ };
+
+
+ synchronized (mRemoteServiceLock) {
+ // Some other thread managed to connect to the service first
+ if (mRemoteService != null) {
+ return true;
+ }
+ mRemoteService = serviceConnector;
+ mRemoteService.setServiceLifecycleCallbacks(
+ new ServiceConnector.ServiceLifecycleCallbacks<>() {
+ @Override
+ public void onDisconnected(@NonNull IDependencyInstallerService service) {
+ Slog.w(TAG,
+ "DependencyInstallerService " + componentName + " is disconnected");
+ destroy();
+ }
+
+ @Override
+ public void onBinderDied() {
+ Slog.w(TAG, "DependencyInstallerService " + componentName + " has died");
+ destroy();
+ }
+
+ private void destroy() {
+ synchronized (mRemoteServiceLock) {
+ if (mRemoteService != null) {
+ mRemoteService.unbind();
+ mRemoteService = null;
+ }
+ }
+ }
+
+ });
+ AndroidFuture<IDependencyInstallerService> unusedFuture = mRemoteService.connect();
+ }
+ return true;
+ }
+ /**
+ * Ensure we call one of the outcomes only once, on the right handler.
+ *
+ * Repeated calls will be no-op.
+ */
+ private static class CallOnceProxy implements OutcomeReceiver<Void, PackageManagerException> {
+ private final Handler mHandler;
+ private final OutcomeReceiver<Void, PackageManagerException> mCallback;
+ @GuardedBy("this")
+ private boolean mCalled = false;
+
+ CallOnceProxy(Handler handler, OutcomeReceiver<Void, PackageManagerException> callback) {
+ mHandler = handler;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResult(Void result) {
+ synchronized (this) {
+ if (!mCalled) {
+ mHandler.post(() -> {
+ mCallback.onResult(null);
+ });
+ mCalled = true;
+ }
+ }
+ }
+
+ @Override
+ public void onError(@NonNull PackageManagerException error) {
+ synchronized (this) {
+ if (!mCalled) {
+ mHandler.post(() -> {
+ mCallback.onError(error);
+ });
+ mCalled = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensure we call one of the outcomes only once, on the right handler.
+ *
+ * Repeated calls will be no-op.
+ */
+ private class DependencyInstallerCallbackCallOnce extends IDependencyInstallerCallback.Stub {
+
+ private final Handler mHandler;
+ private final CallOnceProxy mCallback;
+
+ @GuardedBy("this")
+ private boolean mCalled = false;
+
+ DependencyInstallerCallbackCallOnce(Handler handler, CallOnceProxy callback) {
+ mHandler = handler;
+ mCallback = callback;
+ }
+
+ // TODO(b/372862145): Consider turning the binder call to two-way so that we can
+ // throw IllegalArgumentException
+ @Override
+ public void onAllDependenciesResolved(int[] sessionIds) throws RemoteException {
+ synchronized (this) {
+ if (mCalled) {
+ return;
+ }
+ mCalled = true;
+ }
+
+ ArraySet<Integer> set = new ArraySet<>();
+ for (int i = 0; i < sessionIds.length; i++) {
+ if (DEBUG) {
+ Slog.i(TAG, "onAllDependenciesResolved called with " + sessionIds[i]);
+ }
+ set.add(sessionIds[i]);
+ }
+
+ DependencyInstallTracker tracker = new DependencyInstallTracker(mCallback, set);
+ synchronized (mTrackers) {
+ mTrackers.add(tracker);
+ }
+
+ // In case any of the session ids have already been installed, check if they
+ // are valid.
+ mHandler.post(() -> {
+ if (DEBUG) {
+ Slog.i(TAG, "onAllDependenciesResolved cleaning up invalid sessions");
+ }
+
+ for (int i = 0; i < sessionIds.length; i++) {
+ int sessionId = sessionIds[i];
+ SessionInfo sessionInfo = mPackageInstallerService.getSessionInfo(sessionId);
+
+ // Continue waiting if session exists and hasn't passed or failed yet.
+ if (sessionInfo != null && !sessionInfo.isSessionApplied
+ && !sessionInfo.isSessionFailed) {
+ continue;
+ }
+
+ if (DEBUG) {
+ Slog.i(TAG, "onAllDependenciesResolved cleaning up finished"
+ + " session: " + sessionId);
+ }
+
+ // If session info is null, we assume it to be success.
+ // TODO(b/372862145): Check historical sessions to be more precise.
+ boolean success = sessionInfo == null || sessionInfo.isSessionApplied;
+
+ notifySessionComplete(sessionId, /*success=*/success);
+ }
+ });
+ }
+
+ @Override
+ public void onFailureToResolveAllDependencies() throws RemoteException {
+ synchronized (this) {
+ if (mCalled) {
+ return;
+ }
+ onError(mCallback, "Failed to resolve all dependencies automatically");
+ mCalled = true;
+ }
+ }
+ }
+
+ /**
+ * Tracks a list of session ids against a particular callback.
+ *
+ * If all the sessions completes successfully, it invokes the positive flow. If any of the
+ * sessions fails, it invokes the failure flow immediately.
+ */
+ // TODO(b/372862145): Determine and add support for rebooting while dependency is being resolved
+ private static class DependencyInstallTracker {
+ private final CallOnceProxy mCallback;
+ private final ArraySet<Integer> mPendingSessionIds;
+
+ DependencyInstallTracker(CallOnceProxy callback, ArraySet<Integer> pendingSessionIds) {
+ mCallback = callback;
+ mPendingSessionIds = pendingSessionIds;
+ }
+
+ /**
+ * Process a session complete event.
+ *
+ * Returns true if we still need to continue tracking.
+ */
+ public boolean onSessionComplete(int sessionId, boolean success) {
+ synchronized (this) {
+ if (!mPendingSessionIds.contains(sessionId)) {
+ // This had no impact on tracker, so continue tracking
+ return true;
+ }
+
+ if (!success) {
+ // If one of the dependency fails, the orig session would fail too.
+ onError(mCallback, "Failed to install all dependencies");
+ // TODO(b/372862145): Abandon the rest of the pending sessions.
+ return false; // No point in tracking anymore
+ }
+
+ mPendingSessionIds.remove(sessionId);
+ if (mPendingSessionIds.isEmpty()) {
+ mCallback.onResult(null);
+ return false; // Nothing to track anymore
+ }
+ return true; // Keep on tracking
+ }
+ }
+
+ }
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index d9e76966892c..e5e274450655 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -229,6 +229,7 @@ final class InstallPackageHelper {
private final SharedLibrariesImpl mSharedLibraries;
private final PackageManagerServiceInjector mInjector;
private final UpdateOwnershipHelper mUpdateOwnershipHelper;
+ private final InstallDependencyHelper mInstallDependencyHelper;
private final Object mInternalLock = new Object();
@GuardedBy("mInternalLock")
@@ -239,7 +240,8 @@ final class InstallPackageHelper {
AppDataHelper appDataHelper,
RemovePackageHelper removePackageHelper,
DeletePackageHelper deletePackageHelper,
- BroadcastHelper broadcastHelper) {
+ BroadcastHelper broadcastHelper,
+ InstallDependencyHelper installDependencyHelper) {
mPm = pm;
mInjector = pm.mInjector;
mAppDataHelper = appDataHelper;
@@ -253,6 +255,7 @@ final class InstallPackageHelper {
mPackageAbiHelper = pm.mInjector.getAbiHelper();
mSharedLibraries = pm.mInjector.getSharedLibrariesImpl();
mUpdateOwnershipHelper = pm.mInjector.getUpdateOwnershipHelper();
+ mInstallDependencyHelper = installDependencyHelper;
}
/**
@@ -1029,12 +1032,14 @@ final class InstallPackageHelper {
if (reconciledPackages == null) {
return;
}
- if (Flags.improveInstallFreeze()) {
- prepPerformDexoptIfNeeded(reconciledPackages);
- }
- if (renameAndUpdatePaths(requests)
- && commitInstallPackages(reconciledPackages)) {
- success = true;
+ if (renameAndUpdatePaths(requests)) {
+ // rename before dexopt because art will encoded the path in the odex/vdex file
+ if (Flags.improveInstallFreeze()) {
+ prepPerformDexoptIfNeeded(reconciledPackages);
+ }
+ if (commitInstallPackages(reconciledPackages)) {
+ success = true;
+ }
}
}
} finally {
@@ -1362,6 +1367,10 @@ final class InstallPackageHelper {
}
}
}
+
+ for (InstallRequest request : requests) {
+ mInstallDependencyHelper.notifySessionComplete(request.getSessionId(), success);
+ }
}
@GuardedBy("mPm.mInstallLock")
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 2c0942337b1f..286333cb83a9 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -96,7 +96,6 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IInterface;
-import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteCallbackList;
@@ -2667,6 +2666,7 @@ public class LauncherAppsService extends SystemService {
}
final String[] packagesNullExtras = packagesWithoutExtras.toArray(
new String[packagesWithoutExtras.size()]);
+
final int n = mListeners.beginBroadcast();
try {
for (int i = 0; i < n; i++) {
@@ -2852,7 +2852,7 @@ public class LauncherAppsService extends SystemService {
class SecureSettingsObserver extends ContentObserver {
SecureSettingsObserver() {
- super(new Handler(Looper.getMainLooper()));
+ super(mCallbackHandler);
}
@Override
@@ -2866,32 +2866,29 @@ public class LauncherAppsService extends SystemService {
if (privateProfile.getIdentifier() == UserHandle.USER_NULL) {
return;
}
-
final int n = mListeners.beginBroadcast();
try {
for (int i = 0; i < n; i++) {
- final IOnAppsChangedListener listener =
- mListeners.getBroadcastItem(i);
+ final IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
final BroadcastCookie cookie =
- (BroadcastCookie) mListeners.getBroadcastCookie(
- i);
+ (BroadcastCookie) mListeners.getBroadcastCookie(i);
if (!isEnabledProfileOf(cookie, privateProfile,
"onSecureSettingsChange")) {
Log.d(TAG, "onSecureSettingsChange: Skipping - profile not enabled"
+ " or not accessible for package=" + cookie.packageName
+ ", packageUid=" + cookie.callingUid);
- } else {
- try {
- Log.d(TAG,
- "onUserConfigChanged: triggering onUserConfigChanged");
- listener.onUserConfigChanged(
- mUserManagerInternal.getLauncherUserInfo(
- privateProfile.getIdentifier()));
- } catch (RemoteException re) {
- Slog.d(TAG, "onUserConfigChanged: Callback failed ", re);
- }
+ continue;
+ }
+ try {
+ Log.d(TAG, "onUserConfigChanged: triggering onUserConfigChanged");
+ listener.onUserConfigChanged(
+ mUserManagerInternal.getLauncherUserInfo(
+ privateProfile.getIdentifier()));
+ } catch (RemoteException re) {
+ Slog.d(TAG, "onUserConfigChanged: Callback failed ", re);
}
}
+
} finally {
mListeners.finishBroadcast();
}
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index e8fc577d9f0f..62b89f3252e6 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -38,19 +38,19 @@ per-file SELinuxMMAC* = alanstokes@google.com, cbrubaker@google.com, jeffv@googl
per-file SaferIntentUtils.java = topjohnwu@google.com
# shortcuts
-per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShareTargetInfo.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutBitmapSaver.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutDumpFiles.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutLauncher.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutNonPersistentUser.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutPackage.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutPackageInfo.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutPackageItem.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutParser.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutRequestPinProcessor.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutService.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
-per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
+per-file LauncherAppsService.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShareTargetInfo.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutBitmapSaver.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutDumpFiles.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutLauncher.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutNonPersistentUser.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutPackage.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutPackageInfo.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutPackageItem.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutParser.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutRequestPinProcessor.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutService.java = pinyaoting@google.com, sunnygoyal@google.com
+per-file ShortcutUser.java = pinyaoting@google.com, sunnygoyal@google.com
# background install control service
-per-file BackgroundInstall* = file:BACKGROUND_INSTALL_OWNERS \ No newline at end of file
+per-file BackgroundInstall* = file:BACKGROUND_INSTALL_OWNERS
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 76ea0b963036..4690e020b12a 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -880,7 +880,8 @@ public class PackageArchiver {
PackageInstaller.STATUS_PENDING_USER_ACTION);
broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent);
broadcastIntent.putExtra(Intent.EXTRA_USER, user);
- sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent);
+ mPm.mHandler.post(
+ () -> sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent));
}
private void verifyUninstallPermissions() {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java b/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java
index 99eac37b0933..ea37d8e5d3c9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java
@@ -79,8 +79,6 @@ public final class PackageInstallerHistoricalSession {
private final String mSessionErrorMessage;
private final String mPreVerifiedDomains;
private final String mPackageName;
- private final int mInitialVerificationPolicy;
- private final int mCurrentVerificationPolicy;
PackageInstallerHistoricalSession(int sessionId, int userId, int originalInstallerUid,
String originalInstallerPackageName, InstallSource installSource, int installerUid,
@@ -92,8 +90,7 @@ public final class PackageInstallerHistoricalSession {
int[] childSessionIds, boolean sessionApplied, boolean sessionFailed,
boolean sessionReady, int sessionErrorCode, String sessionErrorMessage,
PreapprovalDetails preapprovalDetails, DomainSet preVerifiedDomains,
- String packageNameFromApk, int initialVerificationPolicy,
- int currentVerificationPolicy) {
+ String packageNameFromApk) {
this.sessionId = sessionId;
this.userId = userId;
this.mOriginalInstallerUid = originalInstallerUid;
@@ -143,8 +140,6 @@ public final class PackageInstallerHistoricalSession {
this.mPackageName = preapprovalDetails != null ? preapprovalDetails.getPackageName()
: packageNameFromApk != null ? packageNameFromApk : params.appPackageName;
- this.mInitialVerificationPolicy = initialVerificationPolicy;
- this.mCurrentVerificationPolicy = currentVerificationPolicy;
}
void dump(IndentingPrintWriter pw) {
@@ -189,8 +184,6 @@ public final class PackageInstallerHistoricalSession {
pw.printPair("mPreapprovalDetails", mPreapprovalDetails);
pw.printPair("mPreVerifiedDomains", mPreVerifiedDomains);
pw.printPair("mAppPackageName", mPackageName);
- pw.printPair("mInitialVerificationPolicy", mInitialVerificationPolicy);
- pw.printPair("mCurrentVerificationPolicy", mCurrentVerificationPolicy);
pw.println();
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index eb70748918b6..47b785040d44 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -25,22 +25,18 @@ import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_NO_CONNECTIVI
import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_USER_ACTION_NEEDED;
import static android.content.pm.PackageInstaller.UNARCHIVAL_GENERIC_ERROR;
import static android.content.pm.PackageInstaller.UNARCHIVAL_OK;
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN;
import static android.content.pm.PackageManager.DELETE_ARCHIVE;
import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
-import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.pm.PackageArchiver.isArchivingEnabled;
-import static com.android.server.pm.PackageInstallerSession.isValidVerificationPolicy;
import static com.android.server.pm.PackageManagerService.SHELL_PACKAGE_NAME;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
-import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -89,7 +85,6 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelableException;
-import android.os.PermissionEnforcer;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
@@ -131,7 +126,6 @@ import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.utils.RequestThrottle;
-import com.android.server.pm.verify.pkg.VerifierController;
import libcore.io.IoUtils;
@@ -219,7 +213,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private final StagingManager mStagingManager;
private AppOpsManager mAppOps;
- private final VerifierController mVerifierController;
private final InstallDependencyHelper mInstallDependencyHelper;
private final HandlerThread mInstallThread;
@@ -281,14 +274,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
};
- /**
- * Default verification policy for incoming installation sessions, mapped from userId to policy.
- */
- @GuardedBy("mVerificationPolicyPerUser")
- private final SparseIntArray mVerificationPolicyPerUser = new SparseIntArray(1);
- // TODO(b/360129657): update the default policy.
- private static final int DEFAULT_VERIFICATION_POLICY = VERIFICATION_POLICY_BLOCK_FAIL_WARN;
-
private static final class Lifecycle extends SystemService {
private final PackageInstallerService mPackageInstallerService;
@@ -318,8 +303,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
public PackageInstallerService(Context context, PackageManagerService pm,
Supplier<PackageParser2> apexParserSupplier) {
- super(PermissionEnforcer.fromContext(context));
-
mContext = context;
mPm = pm;
@@ -343,12 +326,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mGentleUpdateHelper = new GentleUpdateHelper(
context, mInstallThread.getLooper(), new AppStateHelper(context));
mPackageArchiver = new PackageArchiver(mContext, mPm);
- mVerifierController = new VerifierController(mContext, mInstallHandler);
- synchronized (mVerificationPolicyPerUser) {
- mVerificationPolicyPerUser.put(USER_SYSTEM, DEFAULT_VERIFICATION_POLICY);
- }
- mInstallDependencyHelper = new InstallDependencyHelper(
- mPm.mInjector.getSharedLibrariesImpl());
+ mInstallDependencyHelper = new InstallDependencyHelper(mContext,
+ mPm.mInjector.getSharedLibrariesImpl(), this);
LocalServices.getService(SystemServiceManager.class).startService(
new Lifecycle(context, this));
@@ -358,6 +337,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
return mStagingManager;
}
+ InstallDependencyHelper getInstallDependencyHelper() {
+ return mInstallDependencyHelper;
+ }
+
boolean okToSendBroadcasts() {
return mOkToSendBroadcasts;
}
@@ -546,7 +529,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
session = PackageInstallerSession.readFromXml(in, mInternalCallback,
mContext, mPm, mInstallThread.getLooper(), mStagingManager,
mSessionsDir, this, mSilentUpdatePolicy,
- mVerifierController, mInstallDependencyHelper);
+ mInstallDependencyHelper);
} catch (Exception e) {
Slog.e(TAG, "Could not read session", e);
continue;
@@ -1058,17 +1041,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
InstallSource installSource = InstallSource.create(installerPackageName,
originatingPackageName, requestedInstallerPackageName, requestedInstallerPackageUid,
requestedInstallerPackageName, installerAttributionTag, params.packageSource);
- final int verificationPolicy;
- synchronized (mVerificationPolicyPerUser) {
- verificationPolicy = mVerificationPolicyPerUser.get(
- userId, DEFAULT_VERIFICATION_POLICY);
- }
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,
userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,
null, null, false, false, false, false, null, SessionInfo.INVALID_ID,
false, false, false, PackageManager.INSTALL_UNKNOWN, "", null,
- mVerifierController, verificationPolicy, verificationPolicy,
mInstallDependencyHelper);
synchronized (mSessions) {
@@ -1079,7 +1056,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mCallbacks.notifySessionCreated(session.sessionId, session.userId);
mSettingsWriteRequest.schedule();
-
if (LOGD) {
Slog.d(TAG, "Created session id=" + sessionId + " staged=" + params.isStaged);
}
@@ -1893,58 +1869,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
- @Override
- @EnforcePermission(android.Manifest.permission.VERIFICATION_AGENT)
- public @PackageInstaller.VerificationPolicy int getVerificationPolicy(int userId) {
- getVerificationPolicy_enforcePermission();
- synchronized (mVerificationPolicyPerUser) {
- if (mVerificationPolicyPerUser.indexOfKey(userId) < 0) {
- throw new IllegalStateException(
- "Verification policy for user " + userId + " does not exist."
- + " Does the user exist?");
- }
- return mVerificationPolicyPerUser.get(userId);
- }
- }
-
- @Override
- @EnforcePermission(android.Manifest.permission.VERIFICATION_AGENT)
- public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy,
- int userId) {
- setVerificationPolicy_enforcePermission();
- final int callingUid = getCallingUid();
- // Only the verifier currently bound by the system can change the policy, except for Shell
- if (!PackageManagerServiceUtils.isRootOrShell(callingUid)) {
- mVerifierController.assertCallerIsCurrentVerifier(callingUid);
- }
- if (!isValidVerificationPolicy(policy)) {
- return false;
- }
- synchronized (mVerificationPolicyPerUser) {
- if (mVerificationPolicyPerUser.indexOfKey(userId) < 0) {
- throw new IllegalStateException(
- "Verification policy for user " + userId + " does not exist."
- + " Does the user exist?");
- }
- if (policy != mVerificationPolicyPerUser.get(userId)) {
- mVerificationPolicyPerUser.put(userId, policy);
- }
- }
- return true;
- }
-
- void onUserAdded(int userId) {
- synchronized (mVerificationPolicyPerUser) {
- mVerificationPolicyPerUser.put(userId, DEFAULT_VERIFICATION_POLICY);
- }
- }
-
- void onUserRemoved(int userId) {
- synchronized (mVerificationPolicyPerUser) {
- mVerificationPolicyPerUser.delete(userId);
- }
- }
-
private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
int installerUid) {
int count = 0;
@@ -2341,9 +2265,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
mSilentUpdatePolicy.dump(pw);
mGentleUpdateHelper.dump(pw);
- synchronized (mVerificationPolicyPerUser) {
- pw.printPair("VerificationPolicyPerUser", mVerificationPolicyPerUser.toString());
- }
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index e156b31c19e1..8f8802e66004 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -21,17 +21,9 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_INSTA
import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO;
import static android.content.pm.DataLoaderType.INCREMENTAL;
import static android.content.pm.DataLoaderType.STREAMING;
-import static android.content.pm.PackageInstaller.EXTRA_VERIFICATION_FAILURE_REASON;
import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
import static android.content.pm.PackageInstaller.UNARCHIVAL_OK;
import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET;
-import static android.content.pm.PackageInstaller.VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE;
-import static android.content.pm.PackageInstaller.VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED;
-import static android.content.pm.PackageInstaller.VERIFICATION_FAILED_REASON_UNKNOWN;
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_OPEN;
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN;
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_NONE;
import static android.content.pm.PackageItemInfo.MAX_SAFE_LABEL_LENGTH;
import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
@@ -46,7 +38,6 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_VERIFICATION_FAIL
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
-import static android.content.pm.verify.pkg.VerificationSession.VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE;
import static android.os.Process.INVALID_UID;
import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
import static android.system.OsConstants.O_CREAT;
@@ -117,9 +108,7 @@ import android.content.pm.PackageInstaller.UserActionReason;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
-import android.content.pm.SigningInfo;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.parsing.ApkLite;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -127,7 +116,6 @@ import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.pm.verify.domain.DomainSet;
-import android.content.pm.verify.pkg.VerificationStatus;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -135,7 +123,6 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.icu.util.ULocale;
-import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -148,7 +135,6 @@ import android.os.Message;
import android.os.OutcomeReceiver;
import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
-import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
@@ -206,7 +192,6 @@ import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.verify.pkg.VerifierController;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -321,8 +306,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT =
"applicationEnabledSettingPersistent";
private static final String ATTR_DOMAIN = "domain";
- private static final String ATTR_INITIAL_VERIFICATION_POLICY = "initialVerificationPolicy";
- private static final String ATTR_CURRENT_VERIFICATION_POLICY = "currentVerificationPolicy";
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
@@ -420,19 +403,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private final PackageSessionProvider mSessionProvider;
private final SilentUpdatePolicy mSilentUpdatePolicy;
/**
- * The initial verification policy assigned to this session when it was first created.
- */
- private final int mInitialVerificationPolicy;
- /**
- * The active verification policy, which might be different from the initial verification policy
- * assigned to this session or the default policy currently used by the system.
- */
- private final AtomicInteger mCurrentVerificationPolicy;
- /**
* Note all calls must be done outside {@link #mLock} to prevent lock inversion.
*/
private final StagingManager mStagingManager;
- @NonNull private final VerifierController mVerifierController;
private final InstallDependencyHelper mInstallDependencyHelper;
@@ -812,8 +785,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (errorMsg != null) {
Slog.e(TAG, "verifySession error: " + errorMsg);
setSessionFailed(INSTALL_FAILED_INTERNAL_ERROR, errorMsg);
- onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, errorMsg,
- /* extras= */ null);
+ onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, errorMsg);
return false;
}
return true;
@@ -1092,6 +1064,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final boolean isInstallDpcPackagesPermissionGranted = (snapshot.checkUidPermission(
android.Manifest.permission.INSTALL_DPC_PACKAGES, mInstallerUid)
== PackageManager.PERMISSION_GRANTED);
+ boolean isInstallDependencyPackagesPermissionGranted = false;
+ if (Flags.sdkDependencyInstaller()) {
+ isInstallDependencyPackagesPermissionGranted = (snapshot.checkUidPermission(
+ android.Manifest.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES, mInstallerUid)
+ == PackageManager.PERMISSION_GRANTED);
+ }
// Also query the package uid for archived packages, so that the user confirmation
// dialog can be displayed for updating archived apps.
final int targetPackageUid = snapshot.getPackageUid(packageName,
@@ -1113,10 +1091,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final boolean isSelfUpdate = targetPackageUid == mInstallerUid;
final boolean isEmergencyInstall =
isEmergencyInstallerEnabled(packageName, snapshot, userId, mInstallerUid);
+ boolean isSdkOrStaticLibraryInstall = false;
+ synchronized (mLock) {
+ if (mPackageLite != null) {
+ isSdkOrStaticLibraryInstall =
+ mPackageLite.isIsSdkLibrary() || mPackageLite.isIsStaticLibrary();
+ }
+ }
final boolean isPermissionGranted = isInstallPermissionGranted
|| (isUpdatePermissionGranted && isUpdate)
|| (isSelfUpdatePermissionGranted && isSelfUpdate)
- || (isInstallDpcPackagesPermissionGranted && hasDeviceAdminReceiver);
+ || (isInstallDpcPackagesPermissionGranted && hasDeviceAdminReceiver)
+ || (isInstallDependencyPackagesPermissionGranted && isSdkOrStaticLibraryInstall);
final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
@@ -1189,9 +1175,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
boolean isFailed, boolean isApplied, int sessionErrorCode,
String sessionErrorMessage, DomainSet preVerifiedDomains,
- @NonNull VerifierController verifierController,
- @PackageInstaller.VerificationPolicy int initialVerificationPolicy,
- @PackageInstaller.VerificationPolicy int currentVerificationPolicy,
InstallDependencyHelper installDependencyHelper) {
mCallback = callback;
mContext = context;
@@ -1201,9 +1184,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mSilentUpdatePolicy = silentUpdatePolicy;
mHandler = new Handler(looper, mHandlerCallback);
mStagingManager = stagingManager;
- mVerifierController = verifierController;
- mInitialVerificationPolicy = initialVerificationPolicy;
- mCurrentVerificationPolicy = new AtomicInteger(currentVerificationPolicy);
mInstallDependencyHelper = installDependencyHelper;
this.sessionId = sessionId;
@@ -1289,14 +1269,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"Archived installation can only use Streaming System DataLoader.");
}
}
-
- if (shouldUseVerificationService()) {
- // Start binding to the verification service, if not bound already.
- mVerifierController.bindToVerifierServiceIfNeeded(mPm::snapshotComputer, userId);
- if (!TextUtils.isEmpty(params.appPackageName)) {
- mVerifierController.notifyPackageNameAvailable(params.appPackageName);
- }
- }
}
PackageInstallerHistoricalSession createHistoricalSession() {
@@ -1314,8 +1286,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mStageDirInUse, mDestroyed, mFds.size(), mBridges.size(), mFinalStatus,
mFinalMessage, params, mParentSessionId, getChildSessionIdsLocked(),
mSessionApplied, mSessionFailed, mSessionReady, mSessionErrorCode,
- mSessionErrorMessage, mPreapprovalDetails, mPreVerifiedDomains, mPackageName,
- mInitialVerificationPolicy, mCurrentVerificationPolicy.get());
+ mSessionErrorMessage, mPreapprovalDetails, mPreVerifiedDomains, mPackageName);
}
}
@@ -2610,10 +2581,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
dispatchSessionFinished(error, detailMessage, null);
}
- private void onSessionVerificationFailure(int error, String msg, Bundle extras) {
+ private void onSessionVerificationFailure(int error, String msg) {
Slog.e(TAG, "Failed to verify session " + sessionId);
// Dispatch message to remove session from PackageInstallerService.
- dispatchSessionFinished(error, msg, extras);
+ dispatchSessionFinished(error, msg, null);
maybeFinishChildSessions(error, msg);
}
@@ -2893,60 +2864,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg);
setSessionFailed(e.error, errorMsg);
- onSessionVerificationFailure(e.error, errorMsg, /* extras= */ null);
- }
- if (shouldUseVerificationService()) {
- final SigningInfo signingInfo;
- final List<SharedLibraryInfo> declaredLibraries;
- synchronized (mLock) {
- signingInfo = new SigningInfo(mSigningDetails);
- declaredLibraries =
- mPackageLite == null ? null : mPackageLite.getDeclaredLibraries();
- }
- // Send the request to the verifier and wait for its response before the rest of
- // the installation can proceed.
- final VerifierCallback verifierCallback = new VerifierCallback();
- if (!mVerifierController.startVerificationSession(mPm::snapshotComputer, userId,
- sessionId, getPackageName(), Uri.fromFile(stageDir), signingInfo,
- declaredLibraries, mCurrentVerificationPolicy.get(),
- /* extensionParams= */ null, verifierCallback, /* retry= */ false)) {
- // A verifier is installed but cannot be connected.
- verifierCallback.onConnectionFailed();
- }
- } else {
- // No need to check with verifier. Proceed with the rest of the verification.
- resumeVerify();
- }
- }
-
- private boolean shouldUseVerificationService() {
- if (!Flags.verificationService()) {
- // Feature is not enabled.
- return false;
- }
- if ((params.installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
- // adb installs are exempted from verification unless explicitly requested
- if (!params.forceVerification) {
- return false;
- }
- }
- final String verifierPackageName = mVerifierController.getVerifierPackageName(
- mPm::snapshotComputer, userId);
- if (verifierPackageName == null) {
- // Feature is enabled but no verifier installed.
- return false;
+ onSessionVerificationFailure(e.error, errorMsg);
}
- synchronized (mLock) {
- if (verifierPackageName.equals(mPackageName)) {
- // The verifier itself is being updated. Skip.
- Slog.w(TAG, "Skipping verification service because the verifier is being updated");
- return false;
- }
- }
- return true;
- }
- private void resumeVerify() {
if (mVerificationInProgress) {
Slog.w(TAG, "Verification is already in progress for session " + sessionId);
return;
@@ -2975,143 +2895,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg);
setSessionFailed(e.error, errorMsg);
- onSessionVerificationFailure(e.error, errorMsg, /* extras= */ null);
- }
- }
-
- /**
- * Used for the VerifierController to report status back.
- */
- public class VerifierCallback {
- /**
- * Called by the VerifierController when the verifier requests to get the current
- * verification policy for this session.
- */
- public @PackageInstaller.VerificationPolicy int getVerificationPolicy() {
- return mCurrentVerificationPolicy.get();
- }
- /**
- * Called by the VerifierController when the verifier requests to change the verification
- * policy for this session.
- */
- public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) {
- if (!isValidVerificationPolicy(policy)) {
- return false;
- }
- mCurrentVerificationPolicy.set(policy);
- return true;
- }
- /**
- * Called by the VerifierController when the connection has failed.
- */
- public void onConnectionFailed() {
- // TODO(b/360129657): prompt user on fail warning
- handleNonPackageBlockedFailure(
- /* onFailWarning= */ PackageInstallerSession.this::resumeVerify,
- /* onFailClosed= */ () -> {
- Bundle bundle = new Bundle();
- bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON,
- VERIFICATION_FAILED_REASON_UNKNOWN);
- onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE,
- "A verifier agent is available on device but cannot be connected.",
- bundle);
- });
- }
- /**
- * Called by the VerifierController when the verification request has timed out.
- */
- public void onTimeout() {
- // Always notify the verifier, regardless of the policy.
- mVerifierController.notifyVerificationTimeout(sessionId);
- // TODO(b/360129657): prompt user on fail warning
- handleNonPackageBlockedFailure(
- /* onFailWarning= */ PackageInstallerSession.this::resumeVerify,
- /* onFailClosed= */ () -> {
- Bundle bundle = new Bundle();
- bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON,
- VERIFICATION_FAILED_REASON_UNKNOWN);
- onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE,
- "Verification timed out; missing a response from the verifier"
- + " within the time limit", bundle);
- });
- }
- /**
- * Called by the VerifierController when the verification request has received a complete
- * response.
- */
- public void onVerificationCompleteReceived(@NonNull VerificationStatus statusReceived,
- @Nullable PersistableBundle extensionResponse) {
- // TODO: handle extension response
- mHandler.post(() -> {
- if (statusReceived.isVerified()
- || mCurrentVerificationPolicy.get() == VERIFICATION_POLICY_NONE) {
- // Continue with the rest of the verification and installation.
- resumeVerify();
- return;
- }
- // Package is blocked.
- StringBuilder sb = new StringBuilder("Verifier rejected the installation");
- if (!TextUtils.isEmpty(statusReceived.getFailureMessage())) {
- sb.append(" with message: ").append(statusReceived.getFailureMessage());
- }
- Bundle bundle = new Bundle();
- bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON,
- VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED);
- onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE,
- sb.toString(), bundle);
- });
- }
- /**
- * Called by the VerifierController when the verification request has received an incomplete
- * response.
- */
- public void onVerificationIncompleteReceived(int incompleteReason) {
- // TODO(b/360129657): prompt user on fail warning
- handleNonPackageBlockedFailure(
- /* onFailWarning= */ PackageInstallerSession.this::resumeVerify,
- /* onFailClosed= */ () -> {
- final int failureReason;
- StringBuilder sb = new StringBuilder(
- "Verification cannot be completed because of ");
- if (incompleteReason == VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE) {
- failureReason = VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE;
- sb.append("unavailable network.");
- } else {
- failureReason = VERIFICATION_FAILED_REASON_UNKNOWN;
- sb.append("unknown reasons.");
- }
- Bundle bundle = new Bundle();
- bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON, failureReason);
- onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE,
- sb.toString(), bundle);
- });
- }
-
- private void handleNonPackageBlockedFailure(Runnable onFailWarning, Runnable onFailClosed) {
- final Runnable r = switch (mCurrentVerificationPolicy.get()) {
- case VERIFICATION_POLICY_NONE, VERIFICATION_POLICY_BLOCK_FAIL_OPEN ->
- PackageInstallerSession.this::resumeVerify;
- case VERIFICATION_POLICY_BLOCK_FAIL_WARN -> onFailWarning;
- case VERIFICATION_POLICY_BLOCK_FAIL_CLOSED -> onFailClosed;
- default -> {
- Log.wtf(TAG, "Unknown verification policy: "
- + mCurrentVerificationPolicy.get());
- yield onFailClosed;
- }
- };
- mHandler.post(r);
+ onSessionVerificationFailure(e.error, errorMsg);
}
}
- /**
- * Returns whether a policy is a valid verification policy.
- */
- public static boolean isValidVerificationPolicy(
- @PackageInstaller.VerificationPolicy int policy) {
- return policy >= VERIFICATION_POLICY_NONE
- && policy <= VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
- }
-
private IntentSender getRemoteStatusReceiver() {
synchronized (mLock) {
return mRemoteStatusReceiver;
@@ -3287,7 +3074,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (error == INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
- onSessionVerificationFailure(error, msg, /* extras= */ null);
+ onSessionVerificationFailure(error, msg);
}
});
});
@@ -3428,8 +3215,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private void resolveLibraryDependenciesIfNeeded() {
synchronized (mLock) {
- // TODO(b/372862145): Callback should be called on a handler passed as parameter
mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(mPackageLite,
+ mPm.snapshotComputer(), userId, mHandler,
new OutcomeReceiver<>() {
@Override
@@ -5486,23 +5273,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- /**
- * @return the initial policy for the verification request assigned to the session when created.
- */
- @VisibleForTesting
- public @PackageInstaller.VerificationPolicy int getInitialVerificationPolicy() {
- assertCallerIsOwnerOrRoot();
- return mInitialVerificationPolicy;
- }
-
- /**
- * @return the current policy for the verification request associated with this session.
- */
- @VisibleForTesting
- public @PackageInstaller.VerificationPolicy int getCurrentVerificationPolicy() {
- assertCallerIsOwnerOrRoot();
- return mCurrentVerificationPolicy.get();
- }
void setSessionReady() {
synchronized (mLock) {
@@ -5673,14 +5443,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
} catch (InstallerException ignored) {
}
- if (shouldUseVerificationService()
- && !TextUtils.isEmpty(params.appPackageName)
- && !isCommitted()) {
- // Only notify for the cancellation if the verification request has not
- // been sent out, which happens right after commit() is called.
- mVerifierController.notifyVerificationCancelled(
- params.appPackageName);
- }
}
void dump(IndentingPrintWriter pw) {
@@ -5741,8 +5503,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (mPreVerifiedDomains != null) {
pw.printPair("mPreVerifiedDomains", mPreVerifiedDomains);
}
- pw.printPair("mInitialVerificationPolicy", mInitialVerificationPolicy);
- pw.printPair("mCurrentVerificationPolicy", mCurrentVerificationPolicy.get());
pw.println();
pw.decreaseIndent();
@@ -5808,10 +5568,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (!ArrayUtils.isEmpty(warnings)) {
fillIn.putStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS, warnings);
}
- if (extras.containsKey(EXTRA_VERIFICATION_FAILURE_REASON)) {
- fillIn.putExtra(EXTRA_VERIFICATION_FAILURE_REASON,
- extras.getInt(EXTRA_VERIFICATION_FAILURE_REASON));
- }
}
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
@@ -5967,9 +5723,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
out.attributeInt(null, ATTR_INSTALL_REASON, params.installReason);
writeBooleanAttribute(out, ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT,
params.applicationEnabledSettingPersistent);
- out.attributeInt(null, ATTR_INITIAL_VERIFICATION_POLICY, mInitialVerificationPolicy);
- out.attributeInt(null, ATTR_CURRENT_VERIFICATION_POLICY,
- mCurrentVerificationPolicy.get());
final boolean isDataLoader = params.dataLoaderParams != null;
writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
@@ -6090,7 +5843,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@NonNull StagingManager stagingManager, @NonNull File sessionsDir,
@NonNull PackageSessionProvider sessionProvider,
@NonNull SilentUpdatePolicy silentUpdatePolicy,
- @NonNull VerifierController verifierController,
@NonNull InstallDependencyHelper installDependencyHelper)
throws IOException, XmlPullParserException {
final int sessionId = in.getAttributeInt(null, ATTR_SESSION_ID);
@@ -6121,10 +5873,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final boolean sealed = in.getAttributeBoolean(null, ATTR_SEALED, false);
final int parentSessionId = in.getAttributeInt(null, ATTR_PARENT_SESSION_ID,
SessionInfo.INVALID_ID);
- final int initialVerificationPolicy = in.getAttributeInt(null,
- ATTR_INITIAL_VERIFICATION_POLICY, VERIFICATION_POLICY_NONE);
- final int currentVerificationPolicy = in.getAttributeInt(null,
- ATTR_CURRENT_VERIFICATION_POLICY, VERIFICATION_POLICY_NONE);
final SessionParams params = new SessionParams(
SessionParams.MODE_INVALID);
@@ -6299,7 +6047,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
installerUid, installSource, params, createdMillis, committedMillis, stageDir,
stageCid, fileArray, checksumsMap, prepared, committed, destroyed, sealed,
childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied,
- sessionErrorCode, sessionErrorMessage, preVerifiedDomains, verifierController,
- initialVerificationPolicy, currentVerificationPolicy, installDependencyHelper);
+ sessionErrorCode, sessionErrorMessage, preVerifiedDomains,
+ installDependencyHelper);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9d48efe954bb..715633410575 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2118,7 +2118,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mBroadcastHelper);
mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper, mRemovePackageHelper,
- mDeletePackageHelper, mBroadcastHelper);
+ mDeletePackageHelper, mBroadcastHelper,
+ injector.getPackageInstallerService().getInstallDependencyHelper());
mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager,
mInjector.getUserManagerInternal(), mDeletePackageHelper);
@@ -4421,7 +4422,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mPendingBroadcasts.remove(userId);
mAppsFilter.onUserDeleted(snapshotComputer(), userId);
mPermissionManager.onUserRemoved(userId);
- mInstallerService.onUserRemoved(userId);
}
mInstantAppRegistry.onUserRemoved(userId);
mPackageMonitorCallbackHelper.onUserRemoved(userId);
@@ -4472,7 +4472,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mLegacyPermissionManager.grantDefaultPermissions(userId);
mPermissionManager.setDefaultPermissionGrantFingerprint(Build.FINGERPRINT, userId);
mDomainVerificationManager.clearUser(userId);
- mInstallerService.onUserAdded(userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 7ef35829a46e..aa235c2258ac 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -399,10 +399,6 @@ class PackageManagerShellCommand extends ShellCommand {
return runUnarchive();
case "get-domain-verification-agent":
return runGetDomainVerificationAgent();
- case "get-verification-policy":
- return runGetVerificationPolicy();
- case "set-verification-policy":
- return runSetVerificationPolicy();
default: {
if (ART_SERVICE_COMMANDS.contains(cmd)) {
return runArtServiceCommand();
@@ -3603,8 +3599,12 @@ class PackageManagerShellCommand extends ShellCommand {
.setCompilerFilter(sessionParams.dexoptCompilerFilter)
.build();
break;
- case "--force-verification":
- sessionParams.setForceVerification();
+ case "--disable-auto-install-dependencies":
+ if (Flags.sdkDependencyInstaller()) {
+ sessionParams.setAutoInstallDependenciesEnabled(false);
+ } else {
+ throw new IllegalArgumentException("Unknown option " + opt);
+ }
break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
@@ -4649,87 +4649,6 @@ class PackageManagerShellCommand extends ShellCommand {
return 0;
}
- private int runGetVerificationPolicy() throws RemoteException {
- final PrintWriter pw = getOutPrintWriter();
- int userId = UserHandle.USER_ALL;
-
- String opt;
- while ((opt = getNextOption()) != null) {
- if (opt.equals("--user")) {
- userId = UserHandle.parseUserArg(getNextArgRequired());
- if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
- UserManagerInternal umi =
- LocalServices.getService(UserManagerInternal.class);
- UserInfo userInfo = umi.getUserInfo(userId);
- if (userInfo == null) {
- pw.println("Failure [user " + userId + " doesn't exist]");
- return 1;
- }
- }
- } else {
- pw.println("Error: Unknown option: " + opt);
- return 1;
- }
- }
- final int translatedUserId =
- translateUserId(userId, UserHandle.USER_SYSTEM, "runGetVerificationPolicy");
- try {
- final IPackageInstaller installer = mInterface.getPackageInstaller();
- // TODO(b/360129657): global verification policy should be per user
- final int policy = installer.getVerificationPolicy(translatedUserId);
- pw.println(policy);
- } catch (Exception e) {
- pw.println("Failure [" + e.getMessage() + "]");
- return 1;
- }
- return 0;
- }
-
- private int runSetVerificationPolicy() throws RemoteException {
- final PrintWriter pw = getOutPrintWriter();
- int userId = UserHandle.USER_ALL;
-
- String opt;
- while ((opt = getNextOption()) != null) {
- if (opt.equals("--user")) {
- userId = UserHandle.parseUserArg(getNextArgRequired());
- if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
- UserManagerInternal umi =
- LocalServices.getService(UserManagerInternal.class);
- UserInfo userInfo = umi.getUserInfo(userId);
- if (userInfo == null) {
- pw.println("Failure [user " + userId + " doesn't exist]");
- return 1;
- }
- }
- } else {
- pw.println("Error: Unknown option: " + opt);
- return 1;
- }
- }
- final String policyStr = getNextArg();
- if (policyStr == null) {
- pw.println("Error: policy not specified");
- return 1;
- }
- final int translatedUserId =
- translateUserId(userId, UserHandle.USER_SYSTEM, "runSetVerificationPolicy");
- try {
- final IPackageInstaller installer = mInterface.getPackageInstaller();
- // TODO(b/360129657): global verification policy should be per user
- final boolean success = installer.setVerificationPolicy(Integer.parseInt(policyStr),
- translatedUserId);
- if (!success) {
- pw.println("Failure setting verification policy.");
- return 1;
- }
- } catch (Exception e) {
- pw.println("Failure [" + e.getMessage() + "]");
- return 1;
- }
- return 0;
- }
-
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -4893,7 +4812,10 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" https://source.android.com/docs/core/runtime/configure"
+ "#compiler_filters");
pw.println(" or 'skip'");
- pw.println(" --force-verification: if set, enable the verification for this install");
+ if (Flags.sdkDependencyInstaller()) {
+ pw.println(" --disable-auto-install-dependencies: if set, any missing shared");
+ pw.println(" library dependencies will not be auto-installed");
+ }
pw.println("");
pw.println(" install-existing [--user USER_ID|all|current]");
pw.println(" [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE");
@@ -5158,14 +5080,6 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" --user: return the agent of the given user (SYSTEM_USER if unspecified)");
pw.println(" get-package-storage-stats [--user <USER_ID>] <PACKAGE>");
pw.println(" Return the storage stats for the given app, if present");
- pw.println(" get-verification-policy [--user USER_ID]");
- pw.println(" Display current verification enforcement policy which will be applied to");
- pw.println(" all the future installation sessions");
- pw.println(" --user: show the policy of the given user (SYSTEM_USER if unspecified)");
- pw.println(" set-verification-policy POLICY [--user USER_ID]");
- pw.println(" Sets the verification policy of all the future installation sessions.");
- pw.println(" --user: set the policy of the given user (SYSTEM_USER if unspecified)");
- pw.println("");
pw.println("");
printArtServiceHelp();
pw.println("");
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index fc54f6864db0..17d7a14d9129 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -1017,10 +1017,11 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable
boolean isSdkOrStatic = libraryType.equals(LIBRARY_TYPE_SDK)
|| libraryType.equals(LIBRARY_TYPE_STATIC);
if (isSdkOrStatic && outMissingSharedLibraryInfos != null) {
- // TODO(b/372862145): Pass the CertDigest too
// If Dependency Installation is supported, try that instead of failing.
+ final List<String> libCertDigests = Arrays.asList(requiredCertDigests[i]);
SharedLibraryInfo missingLibrary = new SharedLibraryInfo(
- libName, libVersion, SharedLibraryInfo.TYPE_SDK_PACKAGE
+ libName, libVersion, SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ libCertDigests
);
outMissingSharedLibraryInfos.add(missingLibrary);
} else {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 5518bfae8277..1052c94d7799 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1022,7 +1022,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Close.
file.finishWrite(outs);
} catch (IOException e) {
- Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+ Slog.w(TAG, "Failed to write to file " + file.getBaseFile(), e);
file.failWrite(outs);
}
}
@@ -1055,7 +1055,7 @@ public class ShortcutService extends IShortcutService.Stub {
final String tag = parser.getName();
if (depth == 1) {
if (!TAG_ROOT.equals(tag)) {
- Slog.e(TAG, "Invalid root tag: " + tag);
+ Slog.v(TAG, "Invalid root tag: " + tag);
return;
}
continue;
@@ -1066,7 +1066,7 @@ public class ShortcutService extends IShortcutService.Stub {
mRawLastResetTime.set(parseLongAttribute(parser, ATTR_VALUE));
break;
default:
- Slog.e(TAG, "Invalid tag: " + tag);
+ Slog.v(TAG, "Invalid tag: " + tag);
break;
}
}
@@ -1113,7 +1113,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Remove all dangling bitmap files.
cleanupDanglingBitmapDirectoriesLocked(userId);
} catch (XmlPullParserException | IOException e) {
- Slog.e(TAG, "Failed to write to file " + file, e);
+ Slog.w(TAG, "Failed to write to file " + file, e);
file.failWrite(os);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 06e29c2c1408..b2b8aaf7dd2a 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4984,7 +4984,10 @@ public class UserManagerService extends IUserManager.Stub {
res.getValue(com.android.internal.R.string.owner_name, mOwnerNameTypedValue, true);
final CharSequence ownerName = mOwnerNameTypedValue.coerceToString();
mOwnerName.set(ownerName != null ? ownerName.toString() : null);
+ // Invalidate when owners name changes due to config change.
+ UserManager.invalidateCacheOnUserDataChanged();
}
+
}
private void scheduleWriteUserList() {
@@ -4997,6 +5000,8 @@ public class UserManagerService extends IUserManager.Stub {
Message msg = mHandler.obtainMessage(WRITE_USER_LIST_MSG);
mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
}
+ // Invalidate cache when {@link UserData} changed, but write was scheduled for later.
+ UserManager.invalidateCacheOnUserDataChanged();
}
private void scheduleWriteUser(@UserIdInt int userId) {
@@ -5009,6 +5014,8 @@ public class UserManagerService extends IUserManager.Stub {
Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userId);
mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
}
+ // Invalidate cache when {@link Data} changed, but write was scheduled for later.
+ UserManager.invalidateCacheOnUserDataChanged();
}
private ResilientAtomicFile getUserFile(int userId) {
@@ -5032,6 +5039,9 @@ public class UserManagerService extends IUserManager.Stub {
if (DBG) {
debug("writeUserLP " + userData);
}
+ // invalidate caches related to any {@link UserData} change.
+ UserManager.invalidateCacheOnUserDataChanged();
+
try (ResilientAtomicFile userFile = getUserFile(userData.info.id)) {
FileOutputStream fos = null;
try {
@@ -5196,6 +5206,8 @@ public class UserManagerService extends IUserManager.Stub {
if (DBG) {
debug("writeUserList");
}
+ // invalidate caches related to any {@link UserData} change.
+ UserManager.invalidateCacheOnUserDataChanged();
try (ResilientAtomicFile file = getUserListFile()) {
FileOutputStream fos = null;
@@ -7958,7 +7970,7 @@ public class UserManagerService extends IUserManager.Stub {
Settings.Secure.getIntForUser(mContext.getContentResolver(),
HIDE_PRIVATESPACE_ENTRY_POINT, parentId) == 1);
} catch (Settings.SettingNotFoundException e) {
- throw new RuntimeException(e);
+ config.putBoolean(PRIVATE_SPACE_ENTRYPOINT_HIDDEN, false);
}
}
return new LauncherUserInfo.Builder(userDetails.getName(),
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 7469c9293e22..09feb18d07bf 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -36,6 +36,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
+import android.health.connect.HealthPermissions;
import android.media.RingtoneManager;
import android.media.midi.MidiManager;
import android.net.Uri;
@@ -48,6 +49,7 @@ import android.os.Process;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.permission.PermissionManager;
+import android.permission.flags.Flags;
import android.print.PrintManager;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
@@ -214,8 +216,13 @@ final class DefaultPermissionGrantPolicy {
private static final Set<String> SENSORS_PERMISSIONS = new ArraySet<>();
static {
- SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
- SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
+ if (Flags.replaceBodySensorPermissionEnabled()) {
+ SENSORS_PERMISSIONS.add(HealthPermissions.READ_HEART_RATE);
+ SENSORS_PERMISSIONS.add(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND);
+ } else {
+ SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
+ SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
+ }
}
private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
diff --git a/services/core/java/com/android/server/pm/verify/pkg/VerificationStatusTracker.java b/services/core/java/com/android/server/pm/verify/pkg/VerificationStatusTracker.java
deleted file mode 100644
index 67ac2a7572d8..000000000000
--- a/services/core/java/com/android/server/pm/verify/pkg/VerificationStatusTracker.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2024 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.verify.pkg;
-
-import android.annotation.CurrentTimeMillisLong;
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * This class keeps record of the current timeout status of a verification request.
- */
-public final class VerificationStatusTracker {
- private final @CurrentTimeMillisLong long mStartTime;
- private @CurrentTimeMillisLong long mTimeoutTime;
- private final @CurrentTimeMillisLong long mMaxTimeoutTime;
- @NonNull
- private final VerifierController.Injector mInjector;
-
- /**
- * By default, the timeout time is the default timeout duration plus the current time (when
- * the timer starts for a verification request). Both the default timeout time and the max
- * timeout time cannot be changed after the timer has started, but the actual timeout time
- * can be extended via {@link #extendTimeRemaining} to the maximum allowed.
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
- public VerificationStatusTracker(long defaultTimeoutMillis, long maxExtendedTimeoutMillis,
- @NonNull VerifierController.Injector injector) {
- mStartTime = injector.getCurrentTimeMillis();
- mTimeoutTime = mStartTime + defaultTimeoutMillis;
- mMaxTimeoutTime = mStartTime + maxExtendedTimeoutMillis;
- mInjector = injector;
- }
-
- /**
- * Used by the controller to inform the verifier agent about the timestamp when the verification
- * request will timeout.
- */
- public @CurrentTimeMillisLong long getTimeoutTime() {
- return mTimeoutTime;
- }
-
- /**
- * Used by the controller to decide when to check for timeout again.
- * @return 0 if the timeout time has been reached, otherwise the remaining time in milliseconds
- * before the timeout is reached.
- */
- public @CurrentTimeMillisLong long getRemainingTime() {
- final long remainingTime = mTimeoutTime - mInjector.getCurrentTimeMillis();
- if (remainingTime < 0) {
- return 0;
- }
- return remainingTime;
- }
-
- /**
- * Used by the controller to extend the timeout duration of the verification request, upon
- * receiving the callback from the verifier agent.
- * @return the amount of time in millis that the timeout has been extended, subject to the max
- * amount allowed.
- */
- public long extendTimeRemaining(@CurrentTimeMillisLong long additionalMs) {
- if (mTimeoutTime + additionalMs > mMaxTimeoutTime) {
- additionalMs = mMaxTimeoutTime - mTimeoutTime;
- }
- mTimeoutTime += additionalMs;
- return additionalMs;
- }
-
- /**
- * Used by the controller to get the timeout status of the request.
- * @return False if the request still has some time left before timeout, otherwise return True.
- */
- public boolean isTimeout() {
- return mInjector.getCurrentTimeMillis() >= mTimeoutTime;
- }
-}
diff --git a/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java b/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java
deleted file mode 100644
index 78849d286ebe..000000000000
--- a/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * Copyright (C) 2024 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.verify.pkg;
-
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-import static android.os.Process.INVALID_UID;
-import static android.os.Process.SYSTEM_UID;
-import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningInfo;
-import android.content.pm.verify.pkg.IVerificationSessionInterface;
-import android.content.pm.verify.pkg.IVerifierService;
-import android.content.pm.verify.pkg.VerificationSession;
-import android.content.pm.verify.pkg.VerificationStatus;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Handler;
-import android.os.PersistableBundle;
-import android.os.Process;
-import android.os.UserHandle;
-import android.provider.DeviceConfig;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.infra.ServiceConnector;
-import com.android.server.pm.Computer;
-import com.android.server.pm.PackageInstallerSession;
-import com.android.server.pm.pkg.PackageStateInternal;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-
-/**
- * This class manages the bind to the verifier agent installed on the device that implements
- * {@link android.content.pm.verify.pkg.VerifierService} and handles all its interactions.
- */
-public class VerifierController {
- private static final String TAG = "VerifierController";
- private static final boolean DEBUG = false;
-
- /**
- * Configurable maximum amount of time in milliseconds to wait for a verifier to respond to
- * a verification request.
- * Flag type: {@code long}
- * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
- */
- private static final String PROPERTY_VERIFICATION_REQUEST_TIMEOUT_MILLIS =
- "verification_request_timeout_millis";
- // Default duration to wait for a verifier to respond to a verification request.
- private static final long DEFAULT_VERIFICATION_REQUEST_TIMEOUT_MILLIS =
- TimeUnit.MINUTES.toMillis(1);
- /**
- * Configurable maximum amount of time in milliseconds that the verifier can request to extend
- * the verification request timeout duration to. This is the maximum amount of time the system
- * can wait for a request before it times out.
- * Flag type: {@code long}
- * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
- */
- private static final String PROPERTY_MAX_VERIFICATION_REQUEST_EXTENDED_TIMEOUT_MILLIS =
- "max_verification_request_extended_timeout_millis";
- // Max duration allowed to wait for a verifier to respond to a verification request.
- private static final long DEFAULT_MAX_VERIFICATION_REQUEST_EXTENDED_TIMEOUT_MILLIS =
- TimeUnit.MINUTES.toMillis(10);
- /**
- * Configurable maximum amount of time in milliseconds for the system to wait from the moment
- * when the installation session requires a verification, till when the request is delivered to
- * the verifier, pending the connection to be established. If the request has not been delivered
- * to the verifier within this amount of time, e.g., because the verifier has crashed or ANR'd,
- * the controller then sends a failure status back to the installation session.
- * Flag type: {@code long}
- * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
- */
- private static final String PROPERTY_VERIFIER_CONNECTION_TIMEOUT_MILLIS =
- "verifier_connection_timeout_millis";
- // The maximum amount of time to wait from the moment when the session requires a verification,
- // till when the request is delivered to the verifier, pending the connection to be established.
- private static final long DEFAULT_VERIFIER_CONNECTION_TIMEOUT_MILLIS =
- TimeUnit.SECONDS.toMillis(10);
-
- // The maximum amount of time to wait before the system unbinds from the verifier.
- private static final long UNBIND_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(6);
-
- private final Context mContext;
- private final Handler mHandler;
- // Guards the remote service object, as well as the verifier name and UID, which should all be
- // changed at the same time.
- private final Object mLock = new Object();
- @Nullable
- @GuardedBy("mLock")
- private ServiceConnector<IVerifierService> mRemoteService;
- @Nullable
- @GuardedBy("mLock")
- private ComponentName mRemoteServiceComponentName;
- @GuardedBy("mLock")
- private int mRemoteServiceUid = INVALID_UID;
- @NonNull
- private Injector mInjector;
-
- // Repository of active verification sessions and their status, mapping from id to status.
- @NonNull
- @GuardedBy("mVerificationStatus")
- private final SparseArray<VerificationStatusTracker> mVerificationStatus = new SparseArray<>();
-
- public VerifierController(@NonNull Context context, @NonNull Handler handler) {
- this(context, handler, new Injector());
- }
-
- @VisibleForTesting
- public VerifierController(@NonNull Context context, @NonNull Handler handler,
- @NonNull Injector injector) {
- mContext = context;
- mHandler = handler;
- mInjector = injector;
- }
-
- /**
- * Used by the installation session to get the package name of the installed verifier.
- */
- @Nullable
- public String getVerifierPackageName(Supplier<Computer> snapshotSupplier, int userId) {
- synchronized (mLock) {
- if (isVerifierConnectedLocked()) {
- // Verifier is connected or is being connected, so it must be installed.
- return mRemoteServiceComponentName.getPackageName();
- }
- }
- // Verifier has been disconnected, or it hasn't been connected. Check if it's installed.
- return mInjector.getVerifierPackageName(snapshotSupplier.get(), userId);
- }
-
- /**
- * Called to start querying and binding to a qualified verifier agent.
- *
- * @return False if a qualified verifier agent doesn't exist on device, so that the system can
- * handle this situation immediately after the call.
- * <p>
- * Notice that since this is an async call, even if this method returns true, it doesn't
- * necessarily mean that the binding connection was successful. However, the system will only
- * try to bind once per installation session, so that it doesn't waste resource by repeatedly
- * trying to bind if the verifier agent isn't available during a short amount of time.
- * <p>
- * If the verifier agent exists but cannot be started for some reason, all the notify* methods
- * in this class will fail asynchronously and quietly. The system will learn about the failure
- * after receiving the failure from
- * {@link PackageInstallerSession.VerifierCallback#onConnectionFailed}.
- */
- public boolean bindToVerifierServiceIfNeeded(Supplier<Computer> snapshotSupplier, int userId) {
- if (DEBUG) {
- Slog.i(TAG, "Requesting to bind to the verifier service.");
- }
- if (mRemoteService != null) {
- // Already connected
- if (DEBUG) {
- Slog.i(TAG, "Verifier service is already connected.");
- }
- return true;
- }
- Computer snapshot = snapshotSupplier.get();
- Pair<ServiceConnector<IVerifierService>, ComponentName> result =
- mInjector.getRemoteService(snapshot, mContext, userId, mHandler);
- if (result == null || result.first == null) {
- if (DEBUG) {
- Slog.i(TAG, "Unable to find a qualified verifier.");
- }
- return false;
- }
- final int verifierUid = snapshot.getPackageUidInternal(
- result.second.getPackageName(), 0, userId, /* callingUid= */ SYSTEM_UID);
- if (verifierUid == INVALID_UID) {
- if (DEBUG) {
- Slog.i(TAG, "Unable to find the UID of the qualified verifier.");
- }
- return false;
- }
- synchronized (mLock) {
- mRemoteService = result.first;
- mRemoteServiceComponentName = result.second;
- mRemoteServiceUid = verifierUid;
- }
-
- if (DEBUG) {
- Slog.i(TAG, "Connecting to a qualified verifier: " + mRemoteServiceComponentName);
- }
- mRemoteService.setServiceLifecycleCallbacks(
- new ServiceConnector.ServiceLifecycleCallbacks<>() {
- @Override
- public void onConnected(@NonNull IVerifierService service) {
- Slog.i(TAG, "Verifier " + mRemoteServiceComponentName + " is connected");
- }
-
- @Override
- public void onDisconnected(@NonNull IVerifierService service) {
- Slog.w(TAG,
- "Verifier " + mRemoteServiceComponentName + " is disconnected");
- destroy();
- }
-
- @Override
- public void onBinderDied() {
- Slog.w(TAG, "Verifier " + mRemoteServiceComponentName + " has died");
- destroy();
- }
-
- private void destroy() {
- synchronized (mLock) {
- if (isVerifierConnectedLocked()) {
- mRemoteService.unbind();
- mRemoteService = null;
- mRemoteServiceComponentName = null;
- mRemoteServiceUid = INVALID_UID;
- }
- }
- }
- });
- AndroidFuture<IVerifierService> unusedFuture = mRemoteService.connect();
- return true;
- }
-
- @GuardedBy("mLock")
- private boolean isVerifierConnectedLocked() {
- return mRemoteService != null && mRemoteServiceComponentName != null;
- }
-
- /**
- * Called to notify the bound verifier agent that a package name is available and will soon be
- * requested for verification.
- */
- public void notifyPackageNameAvailable(@NonNull String packageName) {
- synchronized (mLock) {
- if (!isVerifierConnectedLocked()) {
- if (DEBUG) {
- Slog.i(TAG, "Verifier is not connected. Not notifying package name available");
- }
- return;
- }
- // Best effort. We don't check for the result.
- mRemoteService.run(service -> {
- if (DEBUG) {
- Slog.i(TAG, "Notifying package name available for " + packageName);
- }
- service.onPackageNameAvailable(packageName);
- });
- }
- }
-
- /**
- * Called to notify the bound verifier agent that a package previously notified via
- * {@link android.content.pm.verify.pkg.VerifierService#onPackageNameAvailable(String)}
- * will no longer be requested for verification, possibly because the installation is canceled.
- */
- public void notifyVerificationCancelled(@NonNull String packageName) {
- synchronized (mLock) {
- if (!isVerifierConnectedLocked()) {
- if (DEBUG) {
- Slog.i(TAG, "Verifier is not connected. Not notifying verification cancelled");
- }
- return;
- }
- // Best effort. We don't check for the result.
- mRemoteService.run(service -> {
- if (DEBUG) {
- Slog.i(TAG, "Notifying verification cancelled for " + packageName);
- }
- service.onVerificationCancelled(packageName);
- });
- }
- }
-
- /**
- * Called to notify the bound verifier agent that a package that's pending installation needs
- * to be verified right now.
- * <p>The verification request must be sent to the verifier as soon as the verifier is
- * connected. If the connection cannot be made within the specified time limit from
- * when the request is sent out, we consider the verification to be failed and notify the
- * installation session.</p>
- * <p>If a response is not returned from the verifier agent within a timeout duration from the
- * time the request is sent to the verifier, the verification will be considered a failure.</p>
- *
- * @param retry whether this request is for retrying a previously incomplete verification.
- */
- public boolean startVerificationSession(Supplier<Computer> snapshotSupplier, int userId,
- int installationSessionId, String packageName,
- Uri stagedPackageUri, SigningInfo signingInfo,
- List<SharedLibraryInfo> declaredLibraries,
- @PackageInstaller.VerificationPolicy int verificationPolicy,
- PersistableBundle extensionParams, PackageInstallerSession.VerifierCallback callback,
- boolean retry) {
- // Try connecting to the verifier if not already connected
- if (!bindToVerifierServiceIfNeeded(snapshotSupplier, userId)) {
- return false;
- }
- // For now, the verification id is the same as the installation session id.
- final int verificationId = installationSessionId;
- synchronized (mLock) {
- if (!isVerifierConnectedLocked()) {
- if (DEBUG) {
- Slog.i(TAG, "Verifier is not connected. Not notifying verification required");
- }
- // Normally this should not happen because we just tried to bind. But if the
- // verifier just crashed or just became unavailable, we should notify the
- // installation session so it can finish with a verification failure.
- return false;
- }
- final VerificationSession session = new VerificationSession(
- /* id= */ verificationId,
- /* installSessionId= */ installationSessionId,
- packageName, stagedPackageUri, signingInfo, declaredLibraries, extensionParams,
- verificationPolicy, new VerificationSessionInterface(callback));
- AndroidFuture<Void> unusedFuture = mRemoteService.post(service -> {
- if (!retry) {
- if (DEBUG) {
- Slog.i(TAG, "Notifying verification required for session "
- + verificationId);
- }
- service.onVerificationRequired(session);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Notifying verification retry for session "
- + verificationId);
- }
- service.onVerificationRetry(session);
- }
- }).orTimeout(mInjector.getVerifierConnectionTimeoutMillis(), TimeUnit.MILLISECONDS)
- .whenComplete((res, err) -> {
- if (err != null) {
- Slog.e(TAG, "Error notifying verification request for session "
- + verificationId, err);
- // Notify the installation session so it can finish with verification
- // failure.
- callback.onConnectionFailed();
- }
- });
- }
- // Keep track of the session status with the ID. Start counting down the session timeout.
- final long defaultTimeoutMillis = mInjector.getVerificationRequestTimeoutMillis();
- final long maxExtendedTimeoutMillis = mInjector.getMaxVerificationExtendedTimeoutMillis();
- final VerificationStatusTracker tracker = new VerificationStatusTracker(
- defaultTimeoutMillis, maxExtendedTimeoutMillis, mInjector);
- synchronized (mVerificationStatus) {
- mVerificationStatus.put(verificationId, tracker);
- }
- startTimeoutCountdown(verificationId, tracker, callback, defaultTimeoutMillis);
- return true;
- }
-
- private void startTimeoutCountdown(int verificationId, VerificationStatusTracker tracker,
- PackageInstallerSession.VerifierCallback callback, long delayMillis) {
- mHandler.postDelayed(() -> {
- if (DEBUG) {
- Slog.i(TAG, "Checking request timeout for " + verificationId);
- }
- if (!tracker.isTimeout()) {
- if (DEBUG) {
- Slog.i(TAG, "Timeout is not met for " + verificationId + "; check later.");
- }
- // If the current session is not timed out yet, check again later.
- startTimeoutCountdown(verificationId, tracker, callback,
- /* delayMillis= */ tracker.getRemainingTime());
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Request " + verificationId + " has timed out.");
- }
- // The request has timed out. Notify the installation session.
- callback.onTimeout();
- // Remove status tracking and stop the timeout countdown
- removeStatusTracker(verificationId);
- }
- }, /* token= */ tracker, delayMillis);
- }
-
- /**
- * Called to notify the bound verifier agent that a verification request has timed out.
- */
- public void notifyVerificationTimeout(int verificationId) {
- synchronized (mLock) {
- if (!isVerifierConnectedLocked()) {
- if (DEBUG) {
- Slog.i(TAG,
- "Verifier is not connected. Not notifying timeout for "
- + verificationId);
- }
- return;
- }
- AndroidFuture<Void> unusedFuture = mRemoteService.post(service -> {
- if (DEBUG) {
- Slog.i(TAG, "Notifying timeout for " + verificationId);
- }
- service.onVerificationTimeout(verificationId);
- }).whenComplete((res, err) -> {
- if (err != null) {
- Slog.e(TAG, "Error notifying VerificationTimeout for session "
- + verificationId, err);
- }
- });
- }
- }
-
- /**
- * Remove a status tracker after it's no longer needed.
- */
- private void removeStatusTracker(int verificationId) {
- if (DEBUG) {
- Slog.i(TAG, "Removing status tracking for verification " + verificationId);
- }
- synchronized (mVerificationStatus) {
- VerificationStatusTracker tracker = mVerificationStatus.removeReturnOld(verificationId);
- // Cancel the timeout counters if there's any
- if (tracker != null) {
- mInjector.stopTimeoutCountdown(mHandler, tracker);
- }
- }
- }
-
- /**
- * Assert that the calling UID is the same as the UID of the currently connected verifier.
- */
- public void assertCallerIsCurrentVerifier(int callingUid) {
- synchronized (mLock) {
- if (!isVerifierConnectedLocked()) {
- throw new IllegalStateException(
- "Unable to proceed because the verifier has been disconnected.");
- }
- if (callingUid != mRemoteServiceUid) {
- throw new IllegalStateException(
- "Calling uid " + callingUid + " is not the current verifier.");
- }
- }
- }
-
- // This class handles requests from the remote verifier
- private class VerificationSessionInterface extends IVerificationSessionInterface.Stub {
- private final PackageInstallerSession.VerifierCallback mCallback;
-
- VerificationSessionInterface(PackageInstallerSession.VerifierCallback callback) {
- mCallback = callback;
- }
-
- @Override
- public long getTimeoutTime(int verificationId) {
- assertCallerIsCurrentVerifier(getCallingUid());
- synchronized (mVerificationStatus) {
- final VerificationStatusTracker tracker = mVerificationStatus.get(verificationId);
- if (tracker == null) {
- throw new IllegalStateException("Verification session " + verificationId
- + " doesn't exist or has finished");
- }
- return tracker.getTimeoutTime();
- }
- }
-
- @Override
- public long extendTimeRemaining(int verificationId, long additionalMs) {
- assertCallerIsCurrentVerifier(getCallingUid());
- synchronized (mVerificationStatus) {
- final VerificationStatusTracker tracker = mVerificationStatus.get(verificationId);
- if (tracker == null) {
- throw new IllegalStateException("Verification session " + verificationId
- + " doesn't exist or has finished");
- }
- return tracker.extendTimeRemaining(additionalMs);
- }
- }
-
- @Override
- public boolean setVerificationPolicy(int verificationId,
- @PackageInstaller.VerificationPolicy int policy) {
- assertCallerIsCurrentVerifier(getCallingUid());
- synchronized (mVerificationStatus) {
- final VerificationStatusTracker tracker = mVerificationStatus.get(verificationId);
- if (tracker == null) {
- throw new IllegalStateException("Verification session " + verificationId
- + " doesn't exist or has finished");
- }
- }
- return mCallback.setVerificationPolicy(policy);
- }
-
- @Override
- public void reportVerificationIncomplete(int id, int reason) {
- assertCallerIsCurrentVerifier(getCallingUid());
- final VerificationStatusTracker tracker;
- synchronized (mVerificationStatus) {
- tracker = mVerificationStatus.get(id);
- if (tracker == null) {
- throw new IllegalStateException("Verification session " + id
- + " doesn't exist or has finished");
- }
- }
- mCallback.onVerificationIncompleteReceived(reason);
- // Remove status tracking and stop the timeout countdown
- removeStatusTracker(id);
- }
-
- @Override
- public void reportVerificationComplete(int id, VerificationStatus verificationStatus,
- @Nullable PersistableBundle extensionResponse) {
- assertCallerIsCurrentVerifier(getCallingUid());
- final VerificationStatusTracker tracker;
- synchronized (mVerificationStatus) {
- tracker = mVerificationStatus.get(id);
- if (tracker == null) {
- throw new IllegalStateException("Verification session " + id
- + " doesn't exist or has finished");
- }
- }
- mCallback.onVerificationCompleteReceived(verificationStatus, extensionResponse);
- // Remove status tracking and stop the timeout countdown
- removeStatusTracker(id);
- }
- }
-
- @VisibleForTesting
- public static class Injector {
- /**
- * Mock this method to inject the remote service to enable unit testing.
- */
- @Nullable
- public Pair<ServiceConnector<IVerifierService>, ComponentName> getRemoteService(
- @NonNull Computer snapshot, @NonNull Context context, int userId,
- @NonNull Handler handler) {
- final ComponentName verifierComponent = resolveVerifierComponentName(snapshot, userId);
- if (verifierComponent == null) {
- return null;
- }
- final Intent intent = new Intent(PackageManager.ACTION_VERIFY_PACKAGE);
- intent.setComponent(verifierComponent);
- return new Pair<>(new ServiceConnector.Impl<IVerifierService>(
- context, intent, Context.BIND_AUTO_CREATE, userId,
- IVerifierService.Stub::asInterface) {
- @Override
- protected Handler getJobHandler() {
- return handler;
- }
-
- @Override
- protected long getRequestTimeoutMs() {
- return getVerificationRequestTimeoutMillis();
- }
-
- @Override
- protected long getAutoDisconnectTimeoutMs() {
- return UNBIND_TIMEOUT_MILLIS;
- }
- }, verifierComponent);
- }
-
- /**
- * Return the package name of the verifier installed on this device.
- */
- @Nullable
- public String getVerifierPackageName(Computer snapshot, int userId) {
- final ComponentName componentName = resolveVerifierComponentName(snapshot, userId);
- if (componentName == null) {
- return null;
- }
- return componentName.getPackageName();
- }
-
- /**
- * Find the ComponentName of the verifier service agent, using the intent action.
- * If multiple qualified verifier services are present, the one with the highest intent
- * filter priority will be chosen.
- */
- private static @Nullable ComponentName resolveVerifierComponentName(Computer snapshot,
- int userId) {
- final Intent intent = new Intent(PackageManager.ACTION_VERIFY_PACKAGE);
- final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
- final List<ResolveInfo> matchedServices = snapshot.queryIntentServicesInternal(
- intent, null,
- resolveFlags, userId, SYSTEM_UID, Process.INVALID_PID,
- /*includeInstantApps*/ false, /*resolveForStart*/ false);
- if (matchedServices.isEmpty()) {
- Slog.w(TAG,
- "Failed to find any matching verifier service agent");
- return null;
- }
- ResolveInfo best = null;
- int numMatchedServices = matchedServices.size();
- for (int i = 0; i < numMatchedServices; i++) {
- ResolveInfo cur = matchedServices.get(i);
- if (!isQualifiedVerifier(snapshot, cur, userId)) {
- continue;
- }
- if (best == null || cur.priority > best.priority) {
- best = cur;
- }
- }
- if (best != null) {
- Slog.i(TAG, "Found verifier service agent: "
- + best.getComponentInfo().getComponentName().toShortString());
- return best.getComponentInfo().getComponentName();
- }
- Slog.w(TAG, "Didn't find any qualified verifier service agent.");
- return null;
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private static boolean isQualifiedVerifier(Computer snapshot, ResolveInfo ri, int userId) {
- // Basic null checks
- if (ri.getComponentInfo() == null) {
- return false;
- }
- final ApplicationInfo applicationInfo = ri.getComponentInfo().applicationInfo;
- if (applicationInfo == null) {
- return false;
- }
- // Check for installed state
- PackageStateInternal ps = snapshot.getPackageStateInternal(
- ri.getComponentInfo().packageName, SYSTEM_UID);
- if (ps == null || !ps.getUserStateOrDefault(userId).isInstalled()) {
- return false;
- }
- // Check for enabled state
- if (!snapshot.isComponentEffectivelyEnabled(ri.getComponentInfo(),
- UserHandle.of(userId))) {
- return false;
- }
- // Allow binding to a non-privileged app on an ENG build
- // TODO: think of a better way to test it on non-eng builds
- if (Build.IS_ENG) {
- return true;
- }
- // Check if the app is platform-signed or is privileged
- if (!applicationInfo.isSignedWithPlatformKey() && !applicationInfo.isPrivilegedApp()) {
- return false;
- }
- // Check for permission
- return (snapshot.checkUidPermission(
- android.Manifest.permission.VERIFICATION_AGENT, applicationInfo.uid)
- != PackageManager.PERMISSION_GRANTED);
- }
-
- /**
- * This is added so we can mock timeouts in the unit tests.
- */
- public long getCurrentTimeMillis() {
- return System.currentTimeMillis();
- }
-
- /**
- * This is added so that we don't need to mock Handler.removeCallbacksAndEqualMessages
- * which is final.
- */
- public void stopTimeoutCountdown(Handler handler, Object token) {
- handler.removeCallbacksAndEqualMessages(token);
- }
-
- /**
- * This is added so that we can mock the verification request timeout duration without
- * calling into DeviceConfig.
- */
- public long getVerificationRequestTimeoutMillis() {
- return getVerificationRequestTimeoutMillisFromDeviceConfig();
- }
-
- /**
- * This is added so that we can mock the maximum request timeout duration without
- * calling into DeviceConfig.
- */
- public long getMaxVerificationExtendedTimeoutMillis() {
- return getMaxVerificationExtendedTimeoutMillisFromDeviceConfig();
- }
-
- /**
- * This is added so that we can mock the maximum connection timeout duration without
- * calling into DeviceConfig.
- */
- public long getVerifierConnectionTimeoutMillis() {
- return getVerifierConnectionTimeoutMillisFromDeviceConfig();
- }
-
- private static long getVerificationRequestTimeoutMillisFromDeviceConfig() {
- return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE,
- PROPERTY_VERIFICATION_REQUEST_TIMEOUT_MILLIS,
- DEFAULT_VERIFICATION_REQUEST_TIMEOUT_MILLIS);
- }
-
- private static long getMaxVerificationExtendedTimeoutMillisFromDeviceConfig() {
- return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE,
- PROPERTY_MAX_VERIFICATION_REQUEST_EXTENDED_TIMEOUT_MILLIS,
- DEFAULT_MAX_VERIFICATION_REQUEST_EXTENDED_TIMEOUT_MILLIS);
- }
-
- private static long getVerifierConnectionTimeoutMillisFromDeviceConfig() {
- return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE,
- PROPERTY_VERIFIER_CONNECTION_TIMEOUT_MILLIS,
- DEFAULT_VERIFIER_CONNECTION_TIMEOUT_MILLIS);
- }
- }
-}
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index 453c6ef41437..e75f852eb437 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -137,6 +137,8 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
"com.android.server.policy.PROPERTY_FEATURE_REAR_DISPLAY";
private static final String PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT =
"com.android.server.policy.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT";
+ private static final String PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT =
+ "com.android.server.policy.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT";
@@ -281,6 +283,9 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
case PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT:
systemProperties.add(DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT);
break;
+ case PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT:
+ systemProperties.add(DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT);
+ break;
default:
Slog.w(TAG, "Parsed unknown flag with name: " + propertyString);
break;
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index 4f67318faddb..c9f66eb5ccb2 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Icon;
import android.hardware.input.AppLaunchData;
@@ -65,6 +66,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -84,6 +86,7 @@ public class ModifierShortcutManager {
private static final String ATTRIBUTE_PACKAGE = "package";
private static final String ATTRIBUTE_CLASS = "class";
private static final String ATTRIBUTE_SHORTCUT = "shortcut";
+ private static final String ATTRIBUTE_KEYCODE = "keycode";
private static final String ATTRIBUTE_CATEGORY = "category";
private static final String ATTRIBUTE_SHIFT = "shift";
private static final String ATTRIBUTE_ROLE = "role";
@@ -167,6 +170,9 @@ public class ModifierShortcutManager {
}, UserHandle.ALL);
mCurrentUser = currentUser;
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+ }
+
+ void onSystemReady() {
loadShortcuts();
}
@@ -335,6 +341,7 @@ public class ModifierShortcutManager {
try {
XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks);
XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
+ KeyCharacterMap virtualKcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
while (true) {
XmlUtils.nextElement(parser);
@@ -353,15 +360,36 @@ public class ModifierShortcutManager {
String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE);
+ final int keycode;
+ final int modifierState;
+ TypedArray a = mContext.getResources().obtainAttributes(parser,
+ R.styleable.Bookmark);
+ try {
+ keycode = a.getInt(R.styleable.Bookmark_keycode, KeyEvent.KEYCODE_UNKNOWN);
+ modifierState = a.getInt(R.styleable.Bookmark_modifierState, 0);
+ } finally {
+ a.recycle();
+ }
+ if (TextUtils.isEmpty(shortcutName) && keycode != KeyEvent.KEYCODE_UNKNOWN) {
+ // Try to find shortcutChar using keycode
+ shortcutName = String.valueOf(virtualKcm.getDisplayLabel(keycode)).toLowerCase(
+ Locale.ROOT);
+ }
if (TextUtils.isEmpty(shortcutName)) {
Log.w(TAG, "Shortcut required for bookmark with category=" + categoryName
+ " packageName=" + packageName + " className=" + className
- + " role=" + roleName + "shiftName=" + shiftName);
+ + " role=" + roleName + " shiftName=" + shiftName + " keycode= "
+ + keycode + " modifierState= " + modifierState);
continue;
}
- final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
+ final boolean isShiftShortcut;
+ if (!TextUtils.isEmpty(shiftName)) {
+ isShiftShortcut = shiftName.equals("true");
+ } else {
+ isShiftShortcut = (modifierState & KeyEvent.META_SHIFT_ON) != 0;
+ }
if (modifierShortcutManagerRefactor()) {
final char shortcutChar = shortcutName.charAt(0);
@@ -376,7 +404,7 @@ public class ModifierShortcutManager {
bookmark = new RoleBookmark(shortcutChar, isShiftShortcut, roleName);
}
if (bookmark != null) {
- Log.d(TAG, "adding shortcut " + bookmark + "shift="
+ Log.d(TAG, "adding shortcut " + bookmark + " shift="
+ isShiftShortcut + " char=" + shortcutChar);
mBookmarks.put(new Pair<>(shortcutChar, isShiftShortcut), bookmark);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dda5bcf24d07..8e7302322d47 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -85,6 +85,7 @@ import static android.view.contentprotection.flags.Flags.createAccessibilityOver
import static com.android.hardware.input.Flags.enableNew25q2Keycodes;
import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures;
+import static com.android.hardware.input.Flags.inputManagerLifecycleSupport;
import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
import static com.android.hardware.input.Flags.modifierShortcutDump;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
@@ -6610,6 +6611,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// In normal flow, systemReady is called before other system services are ready.
// So it is better not to bind keyguard here.
mKeyguardDelegate.onSystemReady();
+ mModifierShortcutManager.onSystemReady();
mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
if (mVrManagerInternal != null) {
@@ -7105,7 +7107,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (modifierShortcutManagerMultiuser()) {
mModifierShortcutManager.setCurrentUser(UserHandle.of(newUserId));
}
- mInputManagerInternal.setCurrentUser(newUserId);
+ if (!inputManagerLifecycleSupport()) {
+ mInputManagerInternal.setCurrentUser(newUserId);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 0acfe92f578d..c573293cbf48 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -625,14 +625,6 @@ public final class PowerManagerService extends SystemService
boolean mIsFaceDown = false;
private long mLastFlipTime = 0L;
- // The screen brightness setting override from the window manager
- // to allow the current foreground activity to override the brightness.
- private float mScreenBrightnessOverrideFromWindowManager =
- PowerManager.BRIGHTNESS_INVALID_FLOAT;
-
- // Tag identifying the window/activity that requested the brightness override.
- private CharSequence mScreenBrightnessOverrideFromWmTag = null;
-
// The window manager has determined the user to be inactive via other means.
// Set this to false to disable.
private boolean mUserInactiveOverrideFromWindowManager;
@@ -2332,6 +2324,8 @@ public final class PowerManagerService extends SystemService
Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName);
try {
// Phase 2: Handle wakefulness change and bookkeeping.
+ // Under lock, invalidate before set ensures caches won't return stale values.
+ mInjector.invalidateIsInteractiveCaches();
mWakefulnessRaw = newWakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
@@ -2429,7 +2423,6 @@ public final class PowerManagerService extends SystemService
void onPowerGroupEventLocked(int event, PowerGroup powerGroup) {
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
- mInjector.invalidateIsInteractiveCaches();
final int groupId = powerGroup.getGroupId();
if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED) {
mPowerGroups.delete(groupId);
@@ -3662,9 +3655,7 @@ public final class PowerManagerService extends SystemService
// Keep the brightness steady during boot. This requires the
// bootloader brightness and the default brightness to be identical.
screenBrightnessOverride = mScreenBrightnessDefault;
- } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
- screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
- overrideTag = mScreenBrightnessOverrideFromWmTag;
+ overrideTag = "boot";
} else {
screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
@@ -4448,19 +4439,6 @@ public final class PowerManagerService extends SystemService
}
}
- private void setScreenBrightnessOverrideFromWindowManagerInternal(
- float brightness, CharSequence tag) {
- synchronized (mLock) {
- if (!BrightnessSynchronizer.floatEquals(mScreenBrightnessOverrideFromWindowManager,
- brightness)) {
- mScreenBrightnessOverrideFromWindowManager = brightness;
- mScreenBrightnessOverrideFromWmTag = tag;
- mDirty |= DIRTY_SETTINGS;
- updatePowerStateLocked();
- }
- }
- }
-
private void setUserInactiveOverrideFromWindowManagerInternal() {
synchronized (mLock) {
mUserInactiveOverrideFromWindowManager = true;
@@ -4799,10 +4777,6 @@ public final class PowerManagerService extends SystemService
+ mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced="
+ isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")");
pw.println(" mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting);
- pw.println(" mScreenBrightnessOverrideFromWindowManager="
- + mScreenBrightnessOverrideFromWindowManager);
- pw.println(" mScreenBrightnessOverrideFromWmTag="
- + mScreenBrightnessOverrideFromWmTag);
pw.println(" mUserActivityTimeoutOverrideFromWindowManager="
+ mUserActivityTimeoutOverrideFromWindowManager);
pw.println(" mUserInactiveOverrideFromWindowManager="
@@ -5192,10 +5166,6 @@ public final class PowerManagerService extends SystemService
proto.write(
PowerServiceSettingsAndConfigurationDumpProto
- .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER,
- mScreenBrightnessOverrideFromWindowManager);
- proto.write(
- PowerServiceSettingsAndConfigurationDumpProto
.USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS,
mUserActivityTimeoutOverrideFromWindowManager);
proto.write(
@@ -7135,17 +7105,6 @@ public final class PowerManagerService extends SystemService
@VisibleForTesting
final class LocalService extends PowerManagerInternal {
@Override
- public void setScreenBrightnessOverrideFromWindowManager(
- float screenBrightness, CharSequence tag) {
- if (screenBrightness < PowerManager.BRIGHTNESS_MIN
- || screenBrightness > PowerManager.BRIGHTNESS_MAX) {
- screenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- tag = null;
- }
- setScreenBrightnessOverrideFromWindowManagerInternal(screenBrightness, tag);
- }
-
- @Override
public void setDozeOverrideFromDreamManager(
int screenState, int reason, float screenBrightnessFloat, int screenBrightnessInt,
boolean useNormalBrightnessForDoze) {
diff --git a/services/core/java/com/android/server/power/hint/Android.bp b/services/core/java/com/android/server/power/hint/Android.bp
index 6dadf8f16390..da594048da44 100644
--- a/services/core/java/com/android/server/power/hint/Android.bp
+++ b/services/core/java/com/android/server/power/hint/Android.bp
@@ -7,6 +7,15 @@ aconfig_declarations {
],
}
+aconfig_declarations {
+ name: "adpf_flags",
+ package: "android.adpf",
+ container: "system",
+ srcs: [
+ "adpf_flags.aconfig",
+ ],
+}
+
java_aconfig_library {
name: "power_hint_flags_lib",
aconfig_declarations: "power_hint_flags",
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 2c0ce252df18..71f67d82dbec 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -33,11 +33,15 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.hardware.power.ChannelConfig;
+import android.hardware.power.CpuHeadroomParams;
+import android.hardware.power.GpuHeadroomParams;
import android.hardware.power.IPower;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
import android.hardware.power.WorkDuration;
import android.os.Binder;
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParamsInternal;
import android.os.Handler;
import android.os.IBinder;
import android.os.IHintManager;
@@ -48,6 +52,7 @@ import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SessionCreationConfig;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -66,6 +71,7 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.power.hint.HintManagerService.AppHintSession.SessionModes;
import com.android.server.utils.Slogf;
import java.io.FileDescriptor;
@@ -90,10 +96,16 @@ public final class HintManagerService extends SystemService {
private static final int EVENT_CLEAN_UP_UID = 3;
@VisibleForTesting static final int CLEAN_UP_UID_DELAY_MILLIS = 1000;
+ private static final int DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS = 1000;
+ private static final int DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS = 1000;
+ private static final int HEADROOM_INTERVAL_UNSUPPORTED = -1;
+ @VisibleForTesting static final int DEFAULT_HEADROOM_PID = -1;
@VisibleForTesting final long mHintSessionPreferredRate;
+ @VisibleForTesting static final int MAX_GRAPHICS_PIPELINE_THREADS_COUNT = 5;
+
// Multi-level map storing all active AppHintSessions.
// First level is keyed by the UID of the client process creating the session.
// Second level is keyed by an IBinder passed from client process. This is used to observe
@@ -121,6 +133,14 @@ public final class HintManagerService extends SystemService {
@GuardedBy("mSessionSnapshotMapLock")
private ArrayMap<Integer, ArrayMap<Integer, AppHintSessionSnapshot>> mSessionSnapshotMap;
+ /*
+ * App UID to Thread mapping.
+ * Thread is a sub class bookkeeping TID, thread mode (especially graphics pipeline mode)
+ * This is to bookkeep and track the thread usage.
+ */
+ @GuardedBy("mThreadsUsageObject")
+ private ArrayMap<Integer, ArraySet<ThreadUsageTracker>> mThreadsUsageMap;
+
/** Lock to protect mActiveSessions and the UidObserver. */
private final Object mLock = new Object();
@@ -136,6 +156,9 @@ public final class HintManagerService extends SystemService {
*/
private final Object mSessionSnapshotMapLock = new Object();
+ /** Lock to protect mThreadsUsageMap. */
+ private final Object mThreadsUsageObject = new Object();
+
@GuardedBy("mNonIsolatedTidsLock")
private final Map<Integer, Set<Long>> mNonIsolatedTids;
@@ -160,10 +183,76 @@ public final class HintManagerService extends SystemService {
private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";
+ private static final String PROPERTY_USE_HAL_HEADROOMS = "persist.hms.use_hal_headrooms";
private Boolean mFMQUsesIntegratedEventFlag = false;
- @VisibleForTesting final IHintManager.Stub mService = new BinderService();
+ private final Object mCpuHeadroomLock = new Object();
+
+ private static class CpuHeadroomCacheItem {
+ long mExpiredTimeMillis;
+ CpuHeadroomParamsInternal mParams;
+ float[] mHeadroom;
+ long mPid;
+
+ CpuHeadroomCacheItem(long expiredTimeMillis, CpuHeadroomParamsInternal params,
+ float[] headroom, long pid) {
+ mExpiredTimeMillis = expiredTimeMillis;
+ mParams = params;
+ mPid = pid;
+ mHeadroom = headroom;
+ }
+
+ private boolean match(CpuHeadroomParamsInternal params, long pid) {
+ if (mParams == null && params == null) return true;
+ if (mParams != null) {
+ return mParams.equals(params) && pid == mPid;
+ }
+ return false;
+ }
+
+ private boolean isExpired() {
+ return System.currentTimeMillis() > mExpiredTimeMillis;
+ }
+ }
+
+ @GuardedBy("mCpuHeadroomLock")
+ private final List<CpuHeadroomCacheItem> mCpuHeadroomCache;
+ private final long mCpuHeadroomIntervalMillis;
+
+ private final Object mGpuHeadroomLock = new Object();
+
+ private static class GpuHeadroomCacheItem {
+ long mExpiredTimeMillis;
+ GpuHeadroomParamsInternal mParams;
+ float mHeadroom;
+
+ GpuHeadroomCacheItem(long expiredTimeMillis, GpuHeadroomParamsInternal params,
+ float headroom) {
+ mExpiredTimeMillis = expiredTimeMillis;
+ mParams = params;
+ mHeadroom = headroom;
+ }
+
+ private boolean match(GpuHeadroomParamsInternal params) {
+ if (mParams == null && params == null) return true;
+ if (mParams != null) {
+ return mParams.equals(params);
+ }
+ return false;
+ }
+
+ private boolean isExpired() {
+ return System.currentTimeMillis() > mExpiredTimeMillis;
+ }
+ }
+
+ @GuardedBy("mGpuHeadroomLock")
+ private final List<GpuHeadroomCacheItem> mGpuHeadroomCache;
+ private final long mGpuHeadroomIntervalMillis;
+
+ @VisibleForTesting
+ final IHintManager.Stub mService = new BinderService();
public HintManagerService(Context context) {
this(context, new Injector());
@@ -188,6 +277,7 @@ public final class HintManagerService extends SystemService {
mActiveSessions = new ArrayMap<>();
mChannelMap = new ArrayMap<>();
mSessionSnapshotMap = new ArrayMap<>();
+ mThreadsUsageMap = new ArrayMap<>();
mNativeWrapper = injector.createNativeWrapper();
mNativeWrapper.halInit();
mHintSessionPreferredRate = mNativeWrapper.halGetHintSessionPreferredRate();
@@ -197,13 +287,72 @@ public final class HintManagerService extends SystemService {
mPowerHal = injector.createIPower();
mPowerHalVersion = 0;
mUsesFmq = false;
+ long cpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED;
+ long gpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED;
if (mPowerHal != null) {
try {
mPowerHalVersion = mPowerHal.getInterfaceVersion();
+ if (mPowerHal.getInterfaceVersion() >= 6) {
+ if (SystemProperties.getBoolean(PROPERTY_USE_HAL_HEADROOMS, true)) {
+ cpuHeadroomIntervalMillis = checkCpuHeadroomSupport();
+ gpuHeadroomIntervalMillis = checkGpuHeadroomSupport();
+ }
+ }
} catch (RemoteException e) {
throw new IllegalStateException("Could not contact PowerHAL!", e);
}
}
+ mCpuHeadroomIntervalMillis = cpuHeadroomIntervalMillis;
+ mGpuHeadroomIntervalMillis = gpuHeadroomIntervalMillis;
+ if (mCpuHeadroomIntervalMillis > 0) {
+ mCpuHeadroomCache = new ArrayList<>(4);
+ } else {
+ mCpuHeadroomCache = null;
+ }
+ if (mGpuHeadroomIntervalMillis > 0) {
+ mGpuHeadroomCache = new ArrayList<>(2);
+ } else {
+ mGpuHeadroomCache = null;
+ }
+ }
+
+ private long checkCpuHeadroomSupport() {
+ try {
+ synchronized (mCpuHeadroomLock) {
+ final CpuHeadroomParams defaultParams = new CpuHeadroomParams();
+ defaultParams.pid = Process.myPid();
+ float[] ret = mPowerHal.getCpuHeadroom(defaultParams);
+ if (ret != null && ret.length > 0) {
+ return Math.max(
+ DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS,
+ mPowerHal.getCpuHeadroomMinIntervalMillis());
+ }
+ }
+
+ } catch (UnsupportedOperationException e) {
+ Slog.w(TAG, "getCpuHeadroom HAL API is not supported", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API", e);
+ }
+ return HEADROOM_INTERVAL_UNSUPPORTED;
+ }
+
+ private long checkGpuHeadroomSupport() {
+ try {
+ synchronized (mGpuHeadroomLock) {
+ float ret = mPowerHal.getGpuHeadroom(new GpuHeadroomParams());
+ if (!Float.isNaN(ret)) {
+ return Math.max(
+ DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS,
+ mPowerHal.getGpuHeadroomMinIntervalMillis());
+ }
+ }
+ } catch (UnsupportedOperationException e) {
+ Slog.w(TAG, "getGpuHeadroom HAL API is not supported", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API", e);
+ }
+ return HEADROOM_INTERVAL_UNSUPPORTED;
}
private ServiceThread createCleanUpThread() {
@@ -224,6 +373,36 @@ public final class HintManagerService extends SystemService {
}
}
+ private static class ThreadUsageTracker {
+ /*
+ * Thread object for tracking thread usage per UID
+ */
+ int mTid;
+ boolean mIsGraphicsPipeline;
+
+ ThreadUsageTracker(int tid) {
+ mTid = tid;
+ mIsGraphicsPipeline = false;
+ }
+
+ ThreadUsageTracker(int tid, boolean isGraphicsPipeline) {
+ mTid = tid;
+ mIsGraphicsPipeline = isGraphicsPipeline;
+ }
+
+ public int getTid() {
+ return mTid;
+ }
+
+ public boolean isGraphicsPipeline() {
+ return mIsGraphicsPipeline;
+ }
+
+ public void setGraphicsPipeline(boolean isGraphicsPipeline) {
+ mIsGraphicsPipeline = isGraphicsPipeline;
+ }
+ }
+
private class AppHintSessionSnapshot {
/*
* Per-Uid and Per-SessionTag snapshot that tracks metrics including
@@ -235,6 +414,7 @@ public final class HintManagerService extends SystemService {
int mMaxConcurrentSession;
int mMaxThreadCount;
int mPowerEfficientSessionCount;
+ int mGraphicsPipelineSessionCount;
final int mTargetDurationNsCountPQSize = 100;
PriorityQueue<TargetDurationRecord> mTargetDurationNsCountPQ;
@@ -292,6 +472,7 @@ public final class HintManagerService extends SystemService {
mMaxConcurrentSession = 0;
mMaxThreadCount = 0;
mPowerEfficientSessionCount = 0;
+ mGraphicsPipelineSessionCount = 0;
mTargetDurationNsCountPQ = new PriorityQueue<>(1);
}
@@ -310,6 +491,10 @@ public final class HintManagerService extends SystemService {
mPowerEfficientSessionCount += 1;
}
+ void logGraphicsPipelineSession() {
+ mGraphicsPipelineSessionCount += 1;
+ }
+
void updateThreadCount(int threadCount) {
mMaxThreadCount = Math.max(mMaxThreadCount, threadCount);
}
@@ -340,6 +525,10 @@ public final class HintManagerService extends SystemService {
return mPowerEfficientSessionCount;
}
+ int getGraphicsPipelineSessionCount() {
+ return mGraphicsPipelineSessionCount;
+ }
+
long[] targetDurationNsList() {
final int listSize = 5;
long[] targetDurations = new long[listSize];
@@ -738,7 +927,7 @@ public final class HintManagerService extends SystemService {
mLinked = false;
}
if (mConfig != null) {
- try {
+ try {
mPowerHal.closeSessionChannel(mTgid, mUid);
} catch (RemoteException e) {
throw new IllegalStateException("Failed to close session channel!", e);
@@ -982,13 +1171,13 @@ public final class HintManagerService extends SystemService {
}
// returns the first invalid tid or null if not found
- private Integer checkTidValid(int uid, int tgid, int [] tids, IntArray nonIsolated) {
+ private Integer checkTidValid(int uid, int tgid, int[] tids, IntArray nonIsolated) {
// Make sure all tids belongs to the same UID (including isolated UID),
// tids can belong to different application processes.
List<Integer> isolatedPids = null;
for (int i = 0; i < tids.length; i++) {
int tid = tids[i];
- final String[] procStatusKeys = new String[] {
+ final String[] procStatusKeys = new String[]{
"Uid:",
"Tgid:"
};
@@ -1030,24 +1219,40 @@ public final class HintManagerService extends SystemService {
+ " doesn't belong to the calling application " + callingUid;
}
+ private boolean contains(final int[] array, final int target) {
+ for (int element : array) {
+ if (element == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@VisibleForTesting
final class BinderService extends IHintManager.Stub {
@Override
public IHintSession createHintSessionWithConfig(@NonNull IBinder token,
- @NonNull int[] tids, long durationNanos, @SessionTag int tag,
- SessionConfig config) {
+ @SessionTag int tag, SessionCreationConfig creationConfig,
+ SessionConfig config) {
if (!isHalSupported()) {
throw new UnsupportedOperationException("PowerHAL is not supported!");
}
java.util.Objects.requireNonNull(token);
- java.util.Objects.requireNonNull(tids);
+ java.util.Objects.requireNonNull(creationConfig.tids);
+
+ final int[] tids = creationConfig.tids;
Preconditions.checkArgument(tids.length != 0, "tids should"
+ " not be empty.");
+
final int callingUid = Binder.getCallingUid();
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final long identity = Binder.clearCallingIdentity();
+ final long durationNanos = creationConfig.targetWorkDurationNanos;
+
+ Preconditions.checkArgument(checkGraphicsPipelineValid(creationConfig, callingUid),
+ "not enough of available graphics pipeline thread.");
try {
final IntArray nonIsolated = powerhintThreadCleanup() ? new IntArray(tids.length)
: null;
@@ -1058,7 +1263,7 @@ public final class HintManagerService extends SystemService {
Slogf.w(TAG, errMsg);
throw new SecurityException(errMsg);
}
- if (resetOnForkEnabled()){
+ if (resetOnForkEnabled()) {
try {
for (int tid : tids) {
int policy = Process.getThreadScheduler(tid);
@@ -1141,8 +1346,9 @@ public final class HintManagerService extends SystemService {
.computeIfAbsent(tag, k -> new AppHintSessionSnapshot())
.updateUponSessionCreation(tids.length, durationNanos);
}
+ AppHintSession hs = null;
synchronized (mLock) {
- AppHintSession hs = new AppHintSession(callingUid, callingTgid, tag, tids,
+ hs = new AppHintSession(callingUid, callingTgid, tag, tids,
token, halSessionPtr, durationNanos);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
mActiveSessions.get(callingUid);
@@ -1157,9 +1363,29 @@ public final class HintManagerService extends SystemService {
}
sessionSet.add(hs);
mUsesFmq = mUsesFmq || hasChannel(callingTgid, callingUid);
+ }
- return hs;
+ if (hs != null) {
+ boolean isGraphicsPipeline = false;
+ if (creationConfig.modesToEnable != null) {
+ for (int sessionMode : creationConfig.modesToEnable) {
+ if (sessionMode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ isGraphicsPipeline = true;
+ }
+ hs.setMode(sessionMode, true);
+ }
+ }
+
+ synchronized (mThreadsUsageObject) {
+ mThreadsUsageMap.computeIfAbsent(callingUid, k -> new ArraySet<>());
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
+ for (int i = 0; i < tids.length; ++i) {
+ threadsSet.add(new ThreadUsageTracker(tids[i], isGraphicsPipeline));
+ }
+ }
}
+
+ return hs;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1202,6 +1428,11 @@ public final class HintManagerService extends SystemService {
}
@Override
+ public int getMaxGraphicsPipelineThreadsCount() {
+ return MAX_GRAPHICS_PIPELINE_THREADS_COUNT;
+ }
+
+ @Override
public void setHintSessionThreads(@NonNull IHintSession hintSession, @NonNull int[] tids) {
AppHintSession appHintSession = (AppHintSession) hintSession;
appHintSession.setThreads(tids);
@@ -1214,11 +1445,130 @@ public final class HintManagerService extends SystemService {
}
@Override
+ public float[] getCpuHeadroom(@Nullable CpuHeadroomParamsInternal params) {
+ if (mCpuHeadroomIntervalMillis <= 0) {
+ throw new UnsupportedOperationException();
+ }
+ CpuHeadroomParams halParams = new CpuHeadroomParams();
+ halParams.pid = Binder.getCallingPid();
+ if (params != null) {
+ halParams.calculationType = params.calculationType;
+ halParams.selectionType = params.selectionType;
+ if (params.usesDeviceHeadroom) {
+ halParams.pid = DEFAULT_HEADROOM_PID;
+ }
+ }
+ synchronized (mCpuHeadroomLock) {
+ while (!mCpuHeadroomCache.isEmpty()) {
+ if (mCpuHeadroomCache.getFirst().isExpired()) {
+ mCpuHeadroomCache.removeFirst();
+ } else {
+ break;
+ }
+ }
+ for (int i = 0; i < mCpuHeadroomCache.size(); ++i) {
+ final CpuHeadroomCacheItem item = mCpuHeadroomCache.get(i);
+ if (item.match(params, halParams.pid)) {
+ item.mExpiredTimeMillis =
+ System.currentTimeMillis() + mCpuHeadroomIntervalMillis;
+ mCpuHeadroomCache.remove(i);
+ mCpuHeadroomCache.add(item);
+ return item.mHeadroom;
+ }
+ }
+ }
+ // return from HAL directly
+ try {
+ float[] headroom = mPowerHal.getCpuHeadroom(halParams);
+ if (headroom == null || headroom.length == 0) {
+ Slog.wtf(TAG,
+ "CPU headroom from Power HAL is invalid: " + Arrays.toString(headroom));
+ return new float[]{Float.NaN};
+ }
+ synchronized (mCpuHeadroomLock) {
+ mCpuHeadroomCache.add(new CpuHeadroomCacheItem(
+ System.currentTimeMillis() + mCpuHeadroomIntervalMillis,
+ params, headroom, halParams.pid
+ ));
+ }
+ return headroom;
+
+ } catch (RemoteException e) {
+ return new float[]{Float.NaN};
+ }
+ }
+
+ @Override
+ public float getGpuHeadroom(@Nullable GpuHeadroomParamsInternal params) {
+ if (mGpuHeadroomIntervalMillis <= 0) {
+ throw new UnsupportedOperationException();
+ }
+ GpuHeadroomParams halParams = new GpuHeadroomParams();
+ if (params != null) {
+ halParams.calculationType = params.calculationType;
+ }
+ synchronized (mGpuHeadroomLock) {
+ while (!mGpuHeadroomCache.isEmpty()) {
+ if (mGpuHeadroomCache.getFirst().isExpired()) {
+ mGpuHeadroomCache.removeFirst();
+ } else {
+ break;
+ }
+ }
+ for (int i = 0; i < mGpuHeadroomCache.size(); ++i) {
+ final GpuHeadroomCacheItem item = mGpuHeadroomCache.get(i);
+ if (item.match(params)) {
+ item.mExpiredTimeMillis =
+ System.currentTimeMillis() + mGpuHeadroomIntervalMillis;
+ mGpuHeadroomCache.remove(i);
+ mGpuHeadroomCache.add(item);
+ return item.mHeadroom;
+ }
+ }
+ }
+ // return from HAL directly
+ try {
+ float headroom = mPowerHal.getGpuHeadroom(halParams);
+ if (Float.isNaN(headroom)) {
+ Slog.wtf(TAG,
+ "GPU headroom from Power HAL is NaN");
+ return Float.NaN;
+ }
+ synchronized (mGpuHeadroomLock) {
+ mGpuHeadroomCache.add(new GpuHeadroomCacheItem(
+ System.currentTimeMillis() + mGpuHeadroomIntervalMillis,
+ params, headroom
+ ));
+ }
+ return headroom;
+ } catch (RemoteException e) {
+ return Float.NaN;
+ }
+ }
+
+ @Override
+ public long getCpuHeadroomMinIntervalMillis() throws RemoteException {
+ if (mCpuHeadroomIntervalMillis <= 0) {
+ throw new UnsupportedOperationException();
+ }
+ return mCpuHeadroomIntervalMillis;
+ }
+
+ @Override
+ public long getGpuHeadroomMinIntervalMillis() throws RemoteException {
+ if (mGpuHeadroomIntervalMillis <= 0) {
+ throw new UnsupportedOperationException();
+ }
+ return mGpuHeadroomIntervalMillis;
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
}
pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate);
+ pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT);
pw.println("HAL Support: " + isHalSupported());
pw.println("Active Sessions:");
synchronized (mLock) {
@@ -1235,6 +1585,64 @@ public final class HintManagerService extends SystemService {
}
}
}
+ pw.println("CPU Headroom Interval: " + mCpuHeadroomIntervalMillis);
+ pw.println("GPU Headroom Interval: " + mGpuHeadroomIntervalMillis);
+ try {
+ CpuHeadroomParamsInternal params = new CpuHeadroomParamsInternal();
+ params.selectionType = CpuHeadroomParams.SelectionType.ALL;
+ params.usesDeviceHeadroom = true;
+ pw.println("CPU headroom: " + Arrays.toString(getCpuHeadroom(params)));
+ params = new CpuHeadroomParamsInternal();
+ params.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
+ params.usesDeviceHeadroom = true;
+ pw.println("CPU headroom per core: " + Arrays.toString(getCpuHeadroom(params)));
+ } catch (Exception e) {
+ pw.println("CPU headroom: N/A");
+ }
+ try {
+ pw.println("GPU headroom: " + getGpuHeadroom(null));
+ } catch (Exception e) {
+ pw.println("GPU headroom: N/A");
+ }
+ }
+
+ private boolean checkGraphicsPipelineValid(SessionCreationConfig creationConfig, int uid) {
+ if (creationConfig.modesToEnable == null) {
+ return true;
+ }
+ boolean setGraphicsPipeline = false;
+ for (int modeToEnable : creationConfig.modesToEnable) {
+ if (modeToEnable == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ setGraphicsPipeline = true;
+ }
+ }
+ if (!setGraphicsPipeline) {
+ return true;
+ }
+
+ synchronized (mThreadsUsageObject) {
+ // count used graphics pipeline threads for the calling UID
+ // consider the case that new tids are overlapping with in session tids
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(uid);
+ if (threadsSet == null) {
+ return true;
+ }
+
+ final int newThreadCount = creationConfig.tids.length;
+ int graphicsPipelineThreadCount = 0;
+ for (ThreadUsageTracker t : threadsSet) {
+ // count graphics pipeline threads in use
+ // and exclude overlapping ones
+ if (t.isGraphicsPipeline()) {
+ graphicsPipelineThreadCount++;
+ if (contains(creationConfig.tids, t.getTid())) {
+ graphicsPipelineThreadCount--;
+ }
+ }
+ }
+ return graphicsPipelineThreadCount + newThreadCount
+ <= MAX_GRAPHICS_PIPELINE_THREADS_COUNT;
+ }
}
private void logPerformanceHintSessionAtom(int uid, long sessionId,
@@ -1267,11 +1675,14 @@ public final class HintManagerService extends SystemService {
protected boolean mUpdateAllowedByProcState;
protected int[] mNewThreadIds;
protected boolean mPowerEfficient;
+ protected boolean mGraphicsPipeline;
protected boolean mHasBeenPowerEfficient;
+ protected boolean mHasBeenGraphicsPipeline;
protected boolean mShouldForcePause;
- private enum SessionModes {
+ enum SessionModes {
POWER_EFFICIENCY,
+ GRAPHICS_PIPELINE,
};
protected AppHintSession(
@@ -1286,7 +1697,9 @@ public final class HintManagerService extends SystemService {
mTargetDurationNanos = durationNanos;
mUpdateAllowedByProcState = true;
mPowerEfficient = false;
+ mGraphicsPipeline = false;
mHasBeenPowerEfficient = false;
+ mHasBeenGraphicsPipeline = false;
mShouldForcePause = false;
final boolean allowed = mUidObserver.isUidForeground(mUid);
updateHintAllowedByProcState(allowed);
@@ -1407,6 +1820,25 @@ public final class HintManagerService extends SystemService {
}
sessionSnapshot.updateUponSessionClose();
}
+
+ if (mGraphicsPipeline) {
+ synchronized (mThreadsUsageObject) {
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(mUid);
+ if (threadsSet == null) {
+ Slogf.w(TAG, "Threads Set is null for uid " + mUid);
+ return;
+ }
+ // remove all tids associated with this session
+ for (int i = 0; i < threadsSet.size(); ++i) {
+ if (contains(mThreadIds, threadsSet.valueAt(i).getTid())) {
+ threadsSet.removeAt(i);
+ }
+ }
+ if (threadsSet.isEmpty()) {
+ mThreadsUsageMap.remove(mUid);
+ }
+ }
+ }
if (powerhintThreadCleanup()) {
synchronized (mNonIsolatedTidsLock) {
final int[] tids = getTidsInternal();
@@ -1443,6 +1875,33 @@ public final class HintManagerService extends SystemService {
throw new IllegalArgumentException("Thread id list can't be empty.");
}
+
+ final int callingUid = Binder.getCallingUid();
+ if (mGraphicsPipeline) {
+ synchronized (mThreadsUsageObject) {
+ // replace original tids with new tids
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
+ int graphicsPipelineThreadCount = 0;
+ if (threadsSet != null) {
+ // We count the graphics pipeline threads that are
+ // *not* in this session, since those in this session
+ // will be replaced. Then if the count plus the new tids
+ // is over max available graphics pipeline threads we raise
+ // an exception.
+ for (ThreadUsageTracker t : threadsSet) {
+ if (t.isGraphicsPipeline() && !contains(mThreadIds, t.getTid())) {
+ graphicsPipelineThreadCount++;
+ }
+ }
+ if (graphicsPipelineThreadCount + tids.length
+ > MAX_GRAPHICS_PIPELINE_THREADS_COUNT) {
+ throw new IllegalArgumentException(
+ "Not enough available graphics pipeline threads.");
+ }
+ }
+ }
+ }
+
synchronized (this) {
if (mHalSessionPtr == 0) {
return;
@@ -1454,7 +1913,6 @@ public final class HintManagerService extends SystemService {
return;
}
if (checkTid) {
- final int callingUid = Binder.getCallingUid();
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final IntArray nonIsolated = powerhintThreadCleanup() ? new IntArray() : null;
final long identity = Binder.clearCallingIdentity();
@@ -1467,7 +1925,7 @@ public final class HintManagerService extends SystemService {
Slogf.w(TAG, errMsg);
throw new SecurityException(errMsg);
}
- if (resetOnForkEnabled()){
+ if (resetOnForkEnabled()) {
try {
for (int tid : tids) {
int policy = Process.getThreadScheduler(tid);
@@ -1500,6 +1958,23 @@ public final class HintManagerService extends SystemService {
}
}
mNativeWrapper.halSetThreads(mHalSessionPtr, tids);
+
+ synchronized (mThreadsUsageObject) {
+ // replace old tids with new ones
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
+ if (threadsSet == null) {
+ mThreadsUsageMap.put(callingUid, new ArraySet<ThreadUsageTracker>());
+ threadsSet = mThreadsUsageMap.get(callingUid);
+ }
+ for (int i = 0; i < threadsSet.size(); ++i) {
+ if (contains(mThreadIds, threadsSet.valueAt(i).getTid())) {
+ threadsSet.removeAt(i);
+ }
+ }
+ for (int tid : tids) {
+ threadsSet.add(new ThreadUsageTracker(tid, mGraphicsPipeline));
+ }
+ }
mThreadIds = tids;
mNewThreadIds = null;
// if the update is allowed but the session is force paused by tid clean up, then
@@ -1561,26 +2036,49 @@ public final class HintManagerService extends SystemService {
+ " greater than zero.");
if (mode == SessionModes.POWER_EFFICIENCY.ordinal()) {
mPowerEfficient = enabled;
+ } else if (mode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ mGraphicsPipeline = enabled;
}
mNativeWrapper.halSetMode(mHalSessionPtr, mode, enabled);
}
- if (enabled && (mode == SessionModes.POWER_EFFICIENCY.ordinal())) {
- if (!mHasBeenPowerEfficient) {
- mHasBeenPowerEfficient = true;
- synchronized (mSessionSnapshotMapLock) {
- ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
- mSessionSnapshotMap.get(mUid);
- if (sessionSnapshots == null) {
- Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
- return;
+ if (enabled) {
+ if (mode == SessionModes.POWER_EFFICIENCY.ordinal()) {
+ if (!mHasBeenPowerEfficient) {
+ mHasBeenPowerEfficient = true;
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid
+ + " and tag " + mTag);
+ return;
+ }
+ sessionSnapshot.logPowerEfficientSession();
}
- AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
- if (sessionSnapshot == null) {
- Slogf.w(TAG, "Session snapshot is null for uid " + mUid
- + " and tag " + mTag);
- return;
+ }
+ } else if (mode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ if (!mHasBeenGraphicsPipeline) {
+ mHasBeenGraphicsPipeline = true;
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid
+ + " and tag " + mTag);
+ return;
+ }
+ sessionSnapshot.logGraphicsPipelineSession();
}
- sessionSnapshot.logPowerEfficientSession();
}
}
}
@@ -1607,6 +2105,12 @@ public final class HintManagerService extends SystemService {
}
}
+ public boolean isGraphicsPipeline() {
+ synchronized (this) {
+ return mGraphicsPipeline;
+ }
+ }
+
public int getUid() {
return mUid;
}
@@ -1694,6 +2198,7 @@ public final class HintManagerService extends SystemService {
pw.println(prefix + "SessionAllowedByProcState: " + mUpdateAllowedByProcState);
pw.println(prefix + "SessionForcePaused: " + mShouldForcePause);
pw.println(prefix + "PowerEfficient: " + (mPowerEfficient ? "true" : "false"));
+ pw.println(prefix + "GraphicsPipeline: " + (mGraphicsPipeline ? "true" : "false"));
}
}
diff --git a/services/core/java/com/android/server/power/hint/adpf_flags.aconfig b/services/core/java/com/android/server/power/hint/adpf_flags.aconfig
new file mode 100644
index 000000000000..147d76bda477
--- /dev/null
+++ b/services/core/java/com/android/server/power/hint/adpf_flags.aconfig
@@ -0,0 +1,7 @@
+# New location for generic ADPF flags across the system
+# This will be moved to the top-level frameworks/base adpf library
+# once it lands
+
+package: "android.adpf"
+container: "system"
+
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
index 1260eeec098f..e8723b91a541 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
@@ -46,6 +46,7 @@ import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.security.advancedprotection.features.AdvancedProtectionHook;
import com.android.server.security.advancedprotection.features.AdvancedProtectionProvider;
+import com.android.server.security.advancedprotection.features.DisallowInstallUnknownSourcesAdvancedProtectionHook;
import java.io.FileDescriptor;
import java.util.ArrayList;
@@ -76,10 +77,9 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
}
private void initFeatures(boolean enabled) {
- // Empty until features are added.
- // Examples:
- // mHooks.add(new SideloadingAdvancedProtectionHook(mContext, enabled));
- // mProviders.add(new WifiAdvancedProtectionProvider());
+ if (android.security.Flags.aapmFeatureDisableInstallUnknownSources()) {
+ mHooks.add(new DisallowInstallUnknownSourcesAdvancedProtectionHook(mContext, enabled));
+ }
}
// Only for tests
@@ -141,7 +141,7 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
}
@Override
- @EnforcePermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+ @EnforcePermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
public void setAdvancedProtectionEnabled(boolean enabled) {
setAdvancedProtectionEnabled_enforcePermission();
final long identity = Binder.clearCallingIdentity();
@@ -159,7 +159,7 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
}
@Override
- @EnforcePermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+ @EnforcePermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
public List<AdvancedProtectionFeature> getAdvancedProtectionFeatures() {
getAdvancedProtectionFeatures_enforcePermission();
List<AdvancedProtectionFeature> features = new ArrayList<>();
diff --git a/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java b/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java
new file mode 100644
index 000000000000..21752e524619
--- /dev/null
+++ b/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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.security.advancedprotection.features;
+
+import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
+import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES;
+
+import android.annotation.NonNull;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.UserManager;
+import android.security.advancedprotection.AdvancedProtectionFeature;
+import android.util.Slog;
+
+/** @hide */
+public final class DisallowInstallUnknownSourcesAdvancedProtectionHook
+ extends AdvancedProtectionHook {
+ private static final String TAG = "AdvancedProtectionDisallowInstallUnknown";
+
+ private final AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(
+ FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES);
+ private final DevicePolicyManager mDevicePolicyManager;
+
+ public DisallowInstallUnknownSourcesAdvancedProtectionHook(@NonNull Context context,
+ boolean enabled) {
+ super(context, enabled);
+ mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
+ onAdvancedProtectionChanged(enabled);
+ }
+
+ @NonNull
+ @Override
+ public AdvancedProtectionFeature getFeature() {
+ return mFeature;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public void onAdvancedProtectionChanged(boolean enabled) {
+ if (enabled) {
+ Slog.d(TAG, "Setting DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
+ mDevicePolicyManager.addUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
+ return;
+ }
+ Slog.d(TAG, "Clearing DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
+ mDevicePolicyManager.clearUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
+
+ // TODO(b/369361373):
+ // 1. After clearing the restriction, set AppOpsManager.OP_REQUEST_INSTALL_PACKAGES to
+ // disabled.
+ // 2. Update dialog strings.
+ }
+}
diff --git a/services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
index b129fdc1b6e3..6798a6146ae0 100644
--- a/services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java
+++ b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
@@ -14,10 +14,13 @@
* limitations under the License.
*/
-package com.android.server.security.adaptiveauthentication;
+package com.android.server.security.authenticationpolicy;
+
+import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
+import android.annotation.EnforcePermission;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -32,9 +35,14 @@ import android.hardware.biometrics.events.AuthenticationStoppedInfo;
import android.hardware.biometrics.events.AuthenticationSucceededInfo;
import android.os.Build;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+import android.security.authenticationpolicy.IAuthenticationPolicyService;
import android.util.Log;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -55,8 +63,8 @@ import java.util.Objects;
/**
* @hide
*/
-public class AdaptiveAuthenticationService extends SystemService {
- private static final String TAG = "AdaptiveAuthenticationService";
+public class AuthenticationPolicyService extends SystemService {
+ private static final String TAG = "AuthenticationPolicyService";
private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
@VisibleForTesting
@@ -74,16 +82,17 @@ public class AdaptiveAuthenticationService extends SystemService {
private final KeyguardManager mKeyguardManager;
private final WindowManagerInternal mWindowManager;
private final UserManagerInternal mUserManager;
+ private SecureLockDeviceServiceInternal mSecureLockDeviceService;
@VisibleForTesting
final SparseIntArray mFailedAttemptsForUser = new SparseIntArray();
private final SparseLongArray mLastLockedTimestamp = new SparseLongArray();
- public AdaptiveAuthenticationService(Context context) {
+ public AuthenticationPolicyService(Context context) {
this(context, new LockPatternUtils(context));
}
@VisibleForTesting
- public AdaptiveAuthenticationService(Context context, LockPatternUtils lockPatternUtils) {
+ public AuthenticationPolicyService(Context context, LockPatternUtils lockPatternUtils) {
super(context);
mLockPatternUtils = lockPatternUtils;
mLockSettings = Objects.requireNonNull(
@@ -94,10 +103,16 @@ public class AdaptiveAuthenticationService extends SystemService {
mWindowManager = Objects.requireNonNull(
LocalServices.getService(WindowManagerInternal.class));
mUserManager = Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class));
+ if (android.security.Flags.secureLockdown()) {
+ mSecureLockDeviceService = Objects.requireNonNull(
+ LocalServices.getService(SecureLockDeviceServiceInternal.class));
+ }
}
@Override
- public void onStart() {}
+ public void onStart() {
+ publishBinderService(Context.AUTHENTICATION_POLICY_SERVICE, mService);
+ }
@Override
public void onBootPhase(int phase) {
@@ -294,4 +309,36 @@ public class AdaptiveAuthenticationService extends SystemService {
// next successful primary or biometric auth happens
mLastLockedTimestamp.put(userId, SystemClock.elapsedRealtime());
}
+
+ private final IBinder mService = new IAuthenticationPolicyService.Stub() {
+ /**
+ * @see AuthenticationPolicyManager#enableSecureLockDevice(EnableSecureLockDeviceParams)
+ * @param params EnableSecureLockDeviceParams for caller to supply params related
+ * to the secure lock device request
+ * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the Secure
+ * Lock Device request
+ */
+ @Override
+ @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
+ @AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus
+ public int enableSecureLockDevice(EnableSecureLockDeviceParams params) {
+ enableSecureLockDevice_enforcePermission();
+ return mSecureLockDeviceService.enableSecureLockDevice(params);
+ }
+
+ /**
+ * @see AuthenticationPolicyManager#disableSecureLockDevice(DisableSecureLockDeviceParams)
+ * @param params @DisableSecureLockDeviceParams for caller to supply params related
+ * to the secure lock device request
+ * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the Secure
+ * Lock Device request
+ */
+ @Override
+ @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
+ @AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus
+ public int disableSecureLockDevice(DisableSecureLockDeviceParams params) {
+ disableSecureLockDevice_enforcePermission();
+ return mSecureLockDeviceService.disableSecureLockDevice(params);
+ }
+ };
}
diff --git a/services/core/java/com/android/server/security/adaptiveauthentication/OWNERS b/services/core/java/com/android/server/security/authenticationpolicy/OWNERS
index 29affcdb81aa..29affcdb81aa 100644
--- a/services/core/java/com/android/server/security/adaptiveauthentication/OWNERS
+++ b/services/core/java/com/android/server/security/authenticationpolicy/OWNERS
diff --git a/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java
new file mode 100644
index 000000000000..7b89723deb6c
--- /dev/null
+++ b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 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.security.authenticationpolicy;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+/**
+ * System service for remotely calling secure lock on the device.
+ *
+ * Callers will access this class via
+ * {@link com.android.server.security.authenticationpolicy.AuthenticationPolicyService}.
+ *
+ * @see AuthenticationPolicyService
+ * @see AuthenticationPolicyManager#enableSecureLockDevice
+ * @see AuthenticationPolicyManager#disableSecureLockDevice
+ * @hide
+ */
+public class SecureLockDeviceService extends SecureLockDeviceServiceInternal {
+ private static final String TAG = "SecureLockDeviceService";
+ private final Context mContext;
+
+ public SecureLockDeviceService(@NonNull Context context) {
+ mContext = context;
+ }
+
+ private void start() {
+ // Expose private service for system components to use.
+ LocalServices.addService(SecureLockDeviceServiceInternal.class, this);
+ }
+
+ /**
+ * @see AuthenticationPolicyManager#enableSecureLockDevice
+ * @param params EnableSecureLockDeviceParams for caller to supply params related
+ * to the secure lock device request
+ * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the
+ * secure lock device request
+ *
+ * @hide
+ */
+ @Override
+ @EnableSecureLockDeviceRequestStatus
+ public int enableSecureLockDevice(EnableSecureLockDeviceParams params) {
+ // (1) Call into system_server to lock device, configure allowed auth types
+ // for secure lock
+ // TODO: lock device, configure allowed authentication types for device entry
+ // (2) Call into framework to configure secure lock 2FA lockscreen
+ // update, UI & string updates
+ // TODO: implement 2FA lockscreen when SceneContainerFlag.isEnabled()
+ // TODO: implement 2FA lockscreen when !SceneContainerFlag.isEnabled()
+ // (3) Call into framework to configure keyguard security updates
+ // TODO: implement security updates
+ return AuthenticationPolicyManager.ERROR_UNSUPPORTED;
+ }
+
+ /**
+ * @see AuthenticationPolicyManager#disableSecureLockDevice
+ * @param params @DisableSecureLockDeviceParams for caller to supply params related
+ * to the secure lock device request
+ * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the
+ * secure lock device request
+ *
+ * @hide
+ */
+ @Override
+ @DisableSecureLockDeviceRequestStatus
+ public int disableSecureLockDevice(DisableSecureLockDeviceParams params) {
+ // (1) Call into system_server to reset allowed auth types
+ // TODO: reset allowed authentication types for device entry;
+ // (2) Call into framework to disable secure lock 2FA lockscreen, reset UI
+ // & string updates
+ // TODO: implement reverting to normal lockscreen when SceneContainerFlag.isEnabled()
+ // TODO: implement reverting to normal lockscreen when !SceneContainerFlag.isEnabled()
+ // (3) Call into framework to revert keyguard security updates
+ // TODO: implement reverting security updates
+ return AuthenticationPolicyManager.ERROR_UNSUPPORTED;
+ }
+
+ /**
+ * System service lifecycle.
+ */
+ public static final class Lifecycle extends SystemService {
+ private final SecureLockDeviceService mService;
+
+ public Lifecycle(@NonNull Context context) {
+ super(context);
+ mService = new SecureLockDeviceService(context);
+ }
+
+ @Override
+ public void onStart() {
+ Slog.i(TAG, "Starting SecureLockDeviceService");
+ mService.start();
+ Slog.i(TAG, "Started SecureLockDeviceService");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java
new file mode 100644
index 000000000000..b90370956d8b
--- /dev/null
+++ b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 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.security.authenticationpolicy;
+
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+
+/**
+ * Local system service interface for {@link SecureLockDeviceService}.
+ *
+ * <p>No permission / argument checks will be performed inside.
+ * Callers must check the calling app permission and the calling package name.
+ *
+ * @hide
+ */
+public abstract class SecureLockDeviceServiceInternal {
+ private static final String TAG = "SecureLockDeviceServiceInternal";
+
+ /**
+ * @see AuthenticationPolicyManager#enableSecureLockDevice(EnableSecureLockDeviceParams)
+ * @param params EnableSecureLockDeviceParams for caller to supply params related
+ * to the secure lock request
+ * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the
+ * secure lock request
+ */
+ @EnableSecureLockDeviceRequestStatus
+ public abstract int enableSecureLockDevice(EnableSecureLockDeviceParams params);
+
+ /**
+ * @see AuthenticationPolicyManager#disableSecureLockDevice(DisableSecureLockDeviceParams)
+ * @param params @DisableSecureLockDeviceParams for caller to supply params related
+ * to the secure lock device request
+ * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the
+ * secure lock device request
+ */
+ @DisableSecureLockDeviceRequestStatus
+ public abstract int disableSecureLockDevice(DisableSecureLockDeviceParams params);
+}
diff --git a/services/core/java/com/android/server/security/forensic/ForensicService.java b/services/core/java/com/android/server/security/forensic/ForensicService.java
deleted file mode 100644
index 01f630b60ff5..000000000000
--- a/services/core/java/com/android/server/security/forensic/ForensicService.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (C) 2024 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.security.forensic;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.security.forensic.ForensicEvent;
-import android.security.forensic.IForensicService;
-import android.security.forensic.IForensicServiceCommandCallback;
-import android.security.forensic.IForensicServiceStateCallback;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.ServiceThread;
-import com.android.server.SystemService;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @hide
- */
-public class ForensicService extends SystemService {
- private static final String TAG = "ForensicService";
-
- private static final int MSG_MONITOR_STATE = 0;
- private static final int MSG_MAKE_VISIBLE = 1;
- private static final int MSG_MAKE_INVISIBLE = 2;
- private static final int MSG_ENABLE = 3;
- private static final int MSG_DISABLE = 4;
- private static final int MSG_BACKUP = 5;
-
- private static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN;
- private static final int STATE_INVISIBLE = IForensicServiceStateCallback.State.INVISIBLE;
- private static final int STATE_VISIBLE = IForensicServiceStateCallback.State.VISIBLE;
- private static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED;
-
- private static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN;
- private static final int ERROR_PERMISSION_DENIED =
- IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
- private static final int ERROR_INVALID_STATE_TRANSITION =
- IForensicServiceCommandCallback.ErrorCode.INVALID_STATE_TRANSITION;
- private static final int ERROR_BACKUP_TRANSPORT_UNAVAILABLE =
- IForensicServiceCommandCallback.ErrorCode.BACKUP_TRANSPORT_UNAVAILABLE;
- private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
- IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
-
- private final Context mContext;
- private final Handler mHandler;
- private final BackupTransportConnection mBackupTransportConnection;
- private final DataAggregator mDataAggregator;
- private final BinderService mBinderService;
-
- private final ArrayList<IForensicServiceStateCallback> mStateMonitors = new ArrayList<>();
- private volatile int mState = STATE_INVISIBLE;
-
- public ForensicService(@NonNull Context context) {
- this(new InjectorImpl(context));
- }
-
- @VisibleForTesting
- ForensicService(@NonNull Injector injector) {
- super(injector.getContext());
- mContext = injector.getContext();
- mHandler = new EventHandler(injector.getLooper(), this);
- mBackupTransportConnection = injector.getBackupTransportConnection();
- mDataAggregator = injector.getDataAggregator(this);
- mBinderService = new BinderService(this);
- }
-
- @VisibleForTesting
- protected void setState(int state) {
- mState = state;
- }
-
- private static final class BinderService extends IForensicService.Stub {
- final ForensicService mService;
-
- BinderService(ForensicService service) {
- mService = service;
- }
-
- @Override
- public void monitorState(IForensicServiceStateCallback callback) {
- mService.mHandler.obtainMessage(MSG_MONITOR_STATE, callback).sendToTarget();
- }
-
- @Override
- public void makeVisible(IForensicServiceCommandCallback callback) {
- mService.mHandler.obtainMessage(MSG_MAKE_VISIBLE, callback).sendToTarget();
- }
-
- @Override
- public void makeInvisible(IForensicServiceCommandCallback callback) {
- mService.mHandler.obtainMessage(MSG_MAKE_INVISIBLE, callback).sendToTarget();
- }
-
- @Override
- public void enable(IForensicServiceCommandCallback callback) {
- mService.mHandler.obtainMessage(MSG_ENABLE, callback).sendToTarget();
- }
-
- @Override
- public void disable(IForensicServiceCommandCallback callback) {
- mService.mHandler.obtainMessage(MSG_DISABLE, callback).sendToTarget();
- }
- }
-
- private static class EventHandler extends Handler {
- private final ForensicService mService;
-
- EventHandler(Looper looper, ForensicService service) {
- super(looper);
- mService = service;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_MONITOR_STATE:
- try {
- mService.monitorState(
- (IForensicServiceStateCallback) msg.obj);
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException", e);
- }
- break;
- case MSG_MAKE_VISIBLE:
- try {
- mService.makeVisible((IForensicServiceCommandCallback) msg.obj);
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException", e);
- }
- break;
- case MSG_MAKE_INVISIBLE:
- try {
- mService.makeInvisible((IForensicServiceCommandCallback) msg.obj);
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException", e);
- }
- break;
- case MSG_ENABLE:
- try {
- mService.enable((IForensicServiceCommandCallback) msg.obj);
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException", e);
- }
- break;
- case MSG_DISABLE:
- try {
- mService.disable((IForensicServiceCommandCallback) msg.obj);
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException", e);
- }
- break;
- case MSG_BACKUP:
- mService.backup((List<ForensicEvent>) msg.obj);
- break;
- default:
- Slog.w(TAG, "Unknown message: " + msg.what);
- }
- }
- }
-
- private void monitorState(IForensicServiceStateCallback callback) throws RemoteException {
- for (int i = 0; i < mStateMonitors.size(); i++) {
- if (mStateMonitors.get(i).asBinder() == callback.asBinder()) {
- return;
- }
- }
- mStateMonitors.add(callback);
- callback.onStateChange(mState);
- }
-
- private void notifyStateMonitors() throws RemoteException {
- for (int i = 0; i < mStateMonitors.size(); i++) {
- mStateMonitors.get(i).onStateChange(mState);
- }
- }
-
- private void makeVisible(IForensicServiceCommandCallback callback) throws RemoteException {
- switch (mState) {
- case STATE_INVISIBLE:
- if (!mDataAggregator.initialize()) {
- callback.onFailure(ERROR_DATA_SOURCE_UNAVAILABLE);
- break;
- }
- mState = STATE_VISIBLE;
- notifyStateMonitors();
- callback.onSuccess();
- break;
- case STATE_VISIBLE:
- callback.onSuccess();
- break;
- default:
- callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
- }
- }
-
- private void makeInvisible(IForensicServiceCommandCallback callback) throws RemoteException {
- switch (mState) {
- case STATE_VISIBLE:
- case STATE_ENABLED:
- mState = STATE_INVISIBLE;
- notifyStateMonitors();
- callback.onSuccess();
- break;
- case STATE_INVISIBLE:
- callback.onSuccess();
- break;
- default:
- callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
- }
- }
-
- private void enable(IForensicServiceCommandCallback callback) throws RemoteException {
- switch (mState) {
- case STATE_VISIBLE:
- if (!mBackupTransportConnection.initialize()) {
- callback.onFailure(ERROR_BACKUP_TRANSPORT_UNAVAILABLE);
- break;
- }
- mDataAggregator.enable();
- mState = STATE_ENABLED;
- notifyStateMonitors();
- callback.onSuccess();
- break;
- case STATE_ENABLED:
- callback.onSuccess();
- break;
- default:
- callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
- }
- }
-
- private void disable(IForensicServiceCommandCallback callback) throws RemoteException {
- switch (mState) {
- case STATE_ENABLED:
- mBackupTransportConnection.release();
- mDataAggregator.disable();
- mState = STATE_VISIBLE;
- notifyStateMonitors();
- callback.onSuccess();
- break;
- case STATE_VISIBLE:
- callback.onSuccess();
- break;
- default:
- callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
- }
- }
-
- /**
- * Add a list of ForensicEvent.
- */
- public void addNewData(List<ForensicEvent> events) {
- mHandler.obtainMessage(MSG_BACKUP, events).sendToTarget();
- }
-
- private void backup(List<ForensicEvent> events) {
- mBackupTransportConnection.addData(events);
- }
-
- @Override
- public void onStart() {
- try {
- publishBinderService(Context.FORENSIC_SERVICE, mBinderService);
- } catch (Throwable t) {
- Slog.e(TAG, "Could not start the ForensicService.", t);
- }
- }
-
- @VisibleForTesting
- IForensicService getBinderService() {
- return mBinderService;
- }
-
- interface Injector {
- Context getContext();
-
- Looper getLooper();
-
- BackupTransportConnection getBackupTransportConnection();
-
- DataAggregator getDataAggregator(ForensicService forensicService);
- }
-
- private static final class InjectorImpl implements Injector {
- private final Context mContext;
-
- InjectorImpl(Context context) {
- mContext = context;
- }
-
- @Override
- public Context getContext() {
- return mContext;
- }
-
-
- @Override
- public Looper getLooper() {
- ServiceThread serviceThread =
- new ServiceThread(
- TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
- serviceThread.start();
- return serviceThread.getLooper();
- }
-
- @Override
- public BackupTransportConnection getBackupTransportConnection() {
- return new BackupTransportConnection(mContext);
- }
-
- @Override
- public DataAggregator getDataAggregator(ForensicService forensicService) {
- return new DataAggregator(mContext, forensicService);
- }
- }
-}
-
diff --git a/services/core/java/com/android/server/security/forensic/OWNERS b/services/core/java/com/android/server/security/forensic/OWNERS
deleted file mode 100644
index 3bc3eb5d1412..000000000000
--- a/services/core/java/com/android/server/security/forensic/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file:platform/frameworks/base:main:/core/java/android/security/forensic/OWNERS
diff --git a/services/core/java/com/android/server/security/forensic/DataAggregator.java b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
index cc473caa0ee7..06e9dcdcbedd 100644
--- a/services/core/java/com/android/server/security/forensic/DataAggregator.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package com.android.server.security.forensic;
+package com.android.server.security.intrusiondetection;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.security.forensic.ForensicEvent;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -30,22 +30,22 @@ import java.util.ArrayList;
import java.util.List;
public class DataAggregator {
- private static final String TAG = "Forensic DataAggregator";
+ private static final String TAG = "IntrusionDetection DataAggregator";
private static final int MSG_SINGLE_DATA = 0;
private static final int MSG_BATCH_DATA = 1;
private static final int MSG_DISABLE = 2;
private static final int STORED_EVENTS_SIZE_LIMIT = 1024;
- private final ForensicService mForensicService;
+ private final IntrusionDetectionService mIntrusionDetectionService;
private final ArrayList<DataSource> mDataSources;
private Context mContext;
- private List<ForensicEvent> mStoredEvents = new ArrayList<>();
+ private List<IntrusionDetectionEvent> mStoredEvents = new ArrayList<>();
private ServiceThread mHandlerThread;
private Handler mHandler;
- public DataAggregator(Context context, ForensicService forensicService) {
- mForensicService = forensicService;
+ public DataAggregator(Context context, IntrusionDetectionService intrusionDetectionService) {
+ mIntrusionDetectionService = intrusionDetectionService;
mContext = context;
mDataSources = new ArrayList<DataSource>();
}
@@ -83,14 +83,14 @@ public class DataAggregator {
/**
* DataSource calls it to transmit a single event.
*/
- public void addSingleData(ForensicEvent event) {
+ public void addSingleData(IntrusionDetectionEvent event) {
mHandler.obtainMessage(MSG_SINGLE_DATA, event).sendToTarget();
}
/**
* DataSource calls it to transmit list of events.
*/
- public void addBatchData(List<ForensicEvent> events) {
+ public void addBatchData(List<IntrusionDetectionEvent> events) {
mHandler.obtainMessage(MSG_BATCH_DATA, events).sendToTarget();
}
@@ -104,17 +104,17 @@ public class DataAggregator {
}
}
- private void onNewSingleData(ForensicEvent event) {
+ private void onNewSingleData(IntrusionDetectionEvent event) {
if (mStoredEvents.size() < STORED_EVENTS_SIZE_LIMIT) {
mStoredEvents.add(event);
} else {
- mForensicService.addNewData(mStoredEvents);
+ mIntrusionDetectionService.addNewData(mStoredEvents);
mStoredEvents = new ArrayList<>();
}
}
- private void onNewBatchData(List<ForensicEvent> events) {
- mForensicService.addNewData(events);
+ private void onNewBatchData(List<IntrusionDetectionEvent> events) {
+ mIntrusionDetectionService.addNewData(events);
}
private void onDisable() {
@@ -135,10 +135,10 @@ public class DataAggregator {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SINGLE_DATA:
- mDataAggregator.onNewSingleData((ForensicEvent) msg.obj);
+ mDataAggregator.onNewSingleData((IntrusionDetectionEvent) msg.obj);
break;
case MSG_BATCH_DATA:
- mDataAggregator.onNewBatchData((List<ForensicEvent>) msg.obj);
+ mDataAggregator.onNewBatchData((List<IntrusionDetectionEvent>) msg.obj);
break;
case MSG_DISABLE:
mDataAggregator.onDisable();
diff --git a/services/core/java/com/android/server/security/forensic/DataSource.java b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java
index da7ee210281b..0bc448245b76 100644
--- a/services/core/java/com/android/server/security/forensic/DataSource.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.security.forensic;
+package com.android.server.security.intrusiondetection;
public interface DataSource {
/**
diff --git a/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
index caca011b6549..b25656ebf47f 100644
--- a/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
@@ -14,17 +14,21 @@
* limitations under the License.
*/
-package com.android.server.security.forensic;
+package com.android.server.security.intrusiondetection;
+
+import static android.Manifest.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.security.forensic.ForensicEvent;
-import android.security.forensic.IBackupTransport;
+import android.security.intrusiondetection.IIntrusionDetectionEventTransport;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
import android.text.TextUtils;
import android.util.Slog;
@@ -36,27 +40,27 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-public class BackupTransportConnection implements ServiceConnection {
- private static final String TAG = "BackupTransportConnection";
+public class IntrusionDetectionEventTransportConnection implements ServiceConnection {
+ private static final String TAG = "IntrusionDetectionEventTransportConnection";
private static final long FUTURE_TIMEOUT_MILLIS = 60 * 1000; // 1 mins
private final Context mContext;
- private String mForensicBackupTransportConfig;
- volatile IBackupTransport mService;
+ private String mIntrusionDetectionEventTransportConfig;
+ volatile IIntrusionDetectionEventTransport mService;
- public BackupTransportConnection(Context context) {
+ public IntrusionDetectionEventTransportConnection(Context context) {
mContext = context;
mService = null;
}
/**
- * Initialize the BackupTransport binder service.
+ * Initialize the IntrusionDetectionEventTransport binder service.
* @return Whether the initialization succeed.
*/
public boolean initialize() {
if (!bindService()) {
return false;
}
- AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+ AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
try {
mService.initialize(resultFuture);
} catch (RemoteException e) {
@@ -64,8 +68,8 @@ public class BackupTransportConnection implements ServiceConnection {
unbindService();
return false;
}
- Integer result = getFutureResult(resultFuture);
- if (result != null && result == 0) {
+ Boolean result = getFutureResult(resultFuture);
+ if (result != null && result == true) {
return true;
} else {
unbindService();
@@ -74,27 +78,27 @@ public class BackupTransportConnection implements ServiceConnection {
}
/**
- * Add data to the BackupTransport binder service.
- * @param data List of ForensicEvent.
+ * Add data to the IntrusionDetectionEventTransport binder service.
+ * @param data List of IntrusionDetectionEvent.
* @return Whether the data is added to the binder service.
*/
- public boolean addData(List<ForensicEvent> data) {
- AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+ public boolean addData(List<IntrusionDetectionEvent> data) {
+ AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
try {
mService.addData(data, resultFuture);
} catch (RemoteException e) {
Slog.e(TAG, "Remote Exception", e);
return false;
}
- Integer result = getFutureResult(resultFuture);
- return result != null && result == 0;
+ Boolean result = getFutureResult(resultFuture);
+ return result != null && result == true;
}
/**
* Release the BackupTransport binder service.
*/
public void release() {
- AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+ AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
try {
mService.release(resultFuture);
} catch (RemoteException e) {
@@ -109,21 +113,37 @@ public class BackupTransportConnection implements ServiceConnection {
return future.get(FUTURE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException
| CancellationException e) {
- Slog.w(TAG, "Failed to get result from transport:", e);
+ Slog.e(TAG, "Failed to get result from transport:", e);
return null;
}
}
private boolean bindService() {
- mForensicBackupTransportConfig = mContext.getString(
- com.android.internal.R.string.config_forensicBackupTransport);
- if (TextUtils.isEmpty(mForensicBackupTransportConfig)) {
+ mIntrusionDetectionEventTransportConfig = mContext.getString(
+ com.android.internal.R.string.config_intrusionDetectionEventTransport);
+ if (TextUtils.isEmpty(mIntrusionDetectionEventTransportConfig)) {
+ Slog.e(TAG, "config_intrusionDetectionEventTransport is empty");
return false;
}
ComponentName serviceComponent =
- ComponentName.unflattenFromString(mForensicBackupTransportConfig);
+ ComponentName.unflattenFromString(mIntrusionDetectionEventTransportConfig);
if (serviceComponent == null) {
+ Slog.e(TAG, "Can't get serviceComponent name");
+ return false;
+ }
+
+ try {
+ ServiceInfo serviceInfo = mContext.getPackageManager().getServiceInfo(serviceComponent,
+ 0 /* flags */);
+ if (!BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE.equals(serviceInfo.permission)) {
+ Slog.e(TAG, serviceComponent.flattenToShortString()
+ + " is not declared with the permission "
+ + "\"" + BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE + "\"");
+ return false;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Unable to find serviceComponent");
return false;
}
@@ -143,7 +163,7 @@ public class BackupTransportConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- mService = IBackupTransport.Stub.asInterface(service);
+ mService = IIntrusionDetectionEventTransport.Stub.asInterface(service);
}
@Override
diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java
new file mode 100644
index 000000000000..0287b415b9c2
--- /dev/null
+++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2024 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.security.intrusiondetection;
+
+import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE;
+import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE;
+
+import android.annotation.EnforcePermission;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PermissionEnforcer;
+import android.os.RemoteException;
+import android.security.intrusiondetection.IIntrusionDetectionService;
+import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback;
+import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class IntrusionDetectionService extends SystemService {
+ private static final String TAG = "IntrusionDetectionService";
+
+ private static final int MAX_STATE_CALLBACK_NUM = 16;
+ private static final int MSG_ADD_STATE_CALLBACK = 0;
+ private static final int MSG_REMOVE_STATE_CALLBACK = 1;
+ private static final int MSG_ENABLE = 2;
+ private static final int MSG_DISABLE = 3;
+ private static final int MSG_TRANSPORT = 4;
+
+ private static final int STATE_UNKNOWN =
+ IIntrusionDetectionServiceStateCallback.State.UNKNOWN;
+ private static final int STATE_DISABLED =
+ IIntrusionDetectionServiceStateCallback.State.DISABLED;
+ private static final int STATE_ENABLED =
+ IIntrusionDetectionServiceStateCallback.State.ENABLED;
+
+ private static final int ERROR_UNKNOWN =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.UNKNOWN;
+ private static final int ERROR_PERMISSION_DENIED =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
+ private static final int ERROR_INVALID_STATE_TRANSITION =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.INVALID_STATE_TRANSITION;
+ private static final int ERROR_TRANSPORT_UNAVAILABLE =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE;
+ private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final IntrusionDetectionEventTransportConnection
+ mIntrusionDetectionEventTransportConnection;
+ private final DataAggregator mDataAggregator;
+ private final BinderService mBinderService;
+
+ private final ArrayList<IIntrusionDetectionServiceStateCallback> mStateCallbacks =
+ new ArrayList<>();
+ private volatile int mState = STATE_DISABLED;
+
+ public IntrusionDetectionService(@NonNull Context context) {
+ this(new InjectorImpl(context));
+ }
+
+ @VisibleForTesting
+ IntrusionDetectionService(@NonNull Injector injector) {
+ super(injector.getContext());
+ mContext = injector.getContext();
+ mHandler = new EventHandler(injector.getLooper(), this);
+ mIntrusionDetectionEventTransportConnection =
+ injector.getIntrusionDetectionEventransportConnection();
+ mDataAggregator = injector.getDataAggregator(this);
+ mBinderService = new BinderService(this, injector.getPermissionEnforcer());
+ }
+
+ @VisibleForTesting
+ protected void setState(int state) {
+ mState = state;
+ }
+
+ private static final class BinderService extends IIntrusionDetectionService.Stub {
+ final IntrusionDetectionService mService;
+
+ BinderService(IntrusionDetectionService service,
+ @NonNull PermissionEnforcer permissionEnforcer) {
+ super(permissionEnforcer);
+ mService = service;
+ }
+
+ @Override
+ @EnforcePermission(READ_INTRUSION_DETECTION_STATE)
+ public void addStateCallback(IIntrusionDetectionServiceStateCallback callback) {
+ addStateCallback_enforcePermission();
+ mService.mHandler.obtainMessage(MSG_ADD_STATE_CALLBACK, callback).sendToTarget();
+ }
+
+ @Override
+ @EnforcePermission(READ_INTRUSION_DETECTION_STATE)
+ public void removeStateCallback(IIntrusionDetectionServiceStateCallback callback) {
+ removeStateCallback_enforcePermission();
+ mService.mHandler.obtainMessage(MSG_REMOVE_STATE_CALLBACK, callback).sendToTarget();
+ }
+
+ @Override
+ @EnforcePermission(MANAGE_INTRUSION_DETECTION_STATE)
+ public void enable(IIntrusionDetectionServiceCommandCallback callback) {
+ enable_enforcePermission();
+ mService.mHandler.obtainMessage(MSG_ENABLE, callback).sendToTarget();
+ }
+
+ @Override
+ @EnforcePermission(MANAGE_INTRUSION_DETECTION_STATE)
+ public void disable(IIntrusionDetectionServiceCommandCallback callback) {
+ disable_enforcePermission();
+ mService.mHandler.obtainMessage(MSG_DISABLE, callback).sendToTarget();
+ }
+ }
+
+ private static class EventHandler extends Handler {
+ private final IntrusionDetectionService mService;
+
+ EventHandler(Looper looper, IntrusionDetectionService service) {
+ super(looper);
+ mService = service;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ADD_STATE_CALLBACK:
+ try {
+ mService.addStateCallback(
+ (IIntrusionDetectionServiceStateCallback) msg.obj);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ break;
+ case MSG_REMOVE_STATE_CALLBACK:
+ try {
+ mService.removeStateCallback(
+ (IIntrusionDetectionServiceStateCallback) msg.obj);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ break;
+ case MSG_ENABLE:
+ try {
+ mService.enable((IIntrusionDetectionServiceCommandCallback) msg.obj);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ break;
+ case MSG_DISABLE:
+ try {
+ mService.disable((IIntrusionDetectionServiceCommandCallback) msg.obj);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ break;
+ case MSG_TRANSPORT:
+ mService.transport((List<IntrusionDetectionEvent>) msg.obj);
+ break;
+ default:
+ Slog.w(TAG, "Unknown message: " + msg.what);
+ }
+ }
+ }
+
+ private void addStateCallback(IIntrusionDetectionServiceStateCallback callback)
+ throws RemoteException {
+ for (int i = 0; i < mStateCallbacks.size(); i++) {
+ if (mStateCallbacks.get(i).asBinder() == callback.asBinder()) {
+ return;
+ }
+ }
+ mStateCallbacks.add(callback);
+ callback.onStateChange(mState);
+ }
+
+ private void removeStateCallback(IIntrusionDetectionServiceStateCallback callback)
+ throws RemoteException {
+ for (int i = 0; i < mStateCallbacks.size(); i++) {
+ if (mStateCallbacks.get(i).asBinder() == callback.asBinder()) {
+ mStateCallbacks.remove(i);
+ return;
+ }
+ }
+ }
+
+ private void notifyStateMonitors() {
+ if (mStateCallbacks.size() >= MAX_STATE_CALLBACK_NUM) {
+ mStateCallbacks.removeFirst();
+ }
+
+ for (int i = 0; i < mStateCallbacks.size(); i++) {
+ try {
+ mStateCallbacks.get(i).onStateChange(mState);
+ } catch (RemoteException e) {
+ mStateCallbacks.remove(i);
+ }
+ }
+ }
+
+ private void enable(IIntrusionDetectionServiceCommandCallback callback)
+ throws RemoteException {
+ if (mState == STATE_ENABLED) {
+ callback.onSuccess();
+ return;
+ }
+
+ // TODO: temporarily disable the following for the CTS IntrusionDetectionManagerTest.
+ // Enable it when the transport component is ready.
+ // if (!mIntrusionDetectionEventTransportConnection.initialize()) {
+ // callback.onFailure(ERROR_TRANSPORT_UNAVAILABLE);
+ // return;
+ // }
+
+ mDataAggregator.enable();
+ mState = STATE_ENABLED;
+ notifyStateMonitors();
+ callback.onSuccess();
+ }
+
+ private void disable(IIntrusionDetectionServiceCommandCallback callback)
+ throws RemoteException {
+ if (mState == STATE_DISABLED) {
+ callback.onSuccess();
+ return;
+ }
+
+ // TODO: temporarily disable the following for the CTS IntrusionDetectionManagerTest.
+ // Enable it when the transport component is ready.
+ // mIntrusionDetectionEventTransportConnection.release();
+ mDataAggregator.disable();
+ mState = STATE_DISABLED;
+ notifyStateMonitors();
+ callback.onSuccess();
+ }
+
+ /**
+ * Add a list of IntrusionDetectionEvent.
+ */
+ public void addNewData(List<IntrusionDetectionEvent> events) {
+ mHandler.obtainMessage(MSG_TRANSPORT, events).sendToTarget();
+ }
+
+ private void transport(List<IntrusionDetectionEvent> events) {
+ mIntrusionDetectionEventTransportConnection.addData(events);
+ }
+
+ @Override
+ public void onStart() {
+ try {
+ publishBinderService(Context.INTRUSION_DETECTION_SERVICE, mBinderService);
+ } catch (Throwable t) {
+ Slog.e(TAG, "Could not start the IntrusionDetectionService.", t);
+ }
+ }
+
+ @VisibleForTesting
+ IIntrusionDetectionService getBinderService() {
+ return mBinderService;
+ }
+
+ interface Injector {
+ Context getContext();
+
+ PermissionEnforcer getPermissionEnforcer();
+
+ Looper getLooper();
+
+ IntrusionDetectionEventTransportConnection getIntrusionDetectionEventransportConnection();
+
+ DataAggregator getDataAggregator(IntrusionDetectionService intrusionDetectionService);
+ }
+
+ private static final class InjectorImpl implements Injector {
+ private final Context mContext;
+
+ InjectorImpl(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ public PermissionEnforcer getPermissionEnforcer() {
+ return PermissionEnforcer.fromContext(mContext);
+ }
+
+ @Override
+ public Looper getLooper() {
+ ServiceThread serviceThread =
+ new ServiceThread(
+ TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+ serviceThread.start();
+ return serviceThread.getLooper();
+ }
+
+ @Override
+ public IntrusionDetectionEventTransportConnection
+ getIntrusionDetectionEventransportConnection() {
+ return new IntrusionDetectionEventTransportConnection(mContext);
+ }
+
+ @Override
+ public DataAggregator getDataAggregator(
+ IntrusionDetectionService intrusionDetectionService) {
+ return new DataAggregator(mContext, intrusionDetectionService);
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/security/intrusiondetection/OWNERS b/services/core/java/com/android/server/security/intrusiondetection/OWNERS
new file mode 100644
index 000000000000..05080670ca2c
--- /dev/null
+++ b/services/core/java/com/android/server/security/intrusiondetection/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/base:main:/core/java/android/security/intrusiondetection/OWNERS
diff --git a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
index 0f1aa42a2f46..226f9d879cab 100644
--- a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
@@ -14,17 +14,15 @@
* limitations under the License.
*/
-package com.android.server.security.forensic;
+package com.android.server.security.intrusiondetection;
import android.Manifest.permission;
import android.annotation.RequiresPermission;
import android.app.admin.DevicePolicyManager;
import android.app.admin.SecurityLog.SecurityEvent;
import android.content.Context;
-import android.security.forensic.ForensicEvent;
-import android.util.ArrayMap;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
-import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -33,11 +31,7 @@ import java.util.stream.Collectors;
public class SecurityLogSource implements DataSource {
- private static final String TAG = "Forensic SecurityLogSource";
- private static final String EVENT_TYPE = "SecurityEvent";
- private static final String EVENT_TAG = "TAG";
- private static final String EVENT_TIME = "TIME";
- private static final String EVENT_DATA = "DATA";
+ private static final String TAG = "IntrusionDetection SecurityLogSource";
private SecurityEventCallback mEventCallback = new SecurityEventCallback();
private DevicePolicyManager mDpm;
@@ -91,49 +85,12 @@ public class SecurityLogSource implements DataSource {
@Override
public void accept(List<SecurityEvent> events) {
- List<ForensicEvent> forensicEvents =
+ List<IntrusionDetectionEvent> intrusionDetectionEvents =
events.stream()
.filter(event -> event != null)
- .map(event -> toForensicEvent(event))
+ .map(event -> new IntrusionDetectionEvent(event))
.collect(Collectors.toList());
- mDataAggregator.addBatchData(forensicEvents);
- }
-
- private ForensicEvent toForensicEvent(SecurityEvent event) {
- ArrayMap<String, String> keyValuePairs = new ArrayMap<>();
- keyValuePairs.put(EVENT_TIME, String.valueOf(event.getTimeNanos()));
- // TODO: Map tag to corresponding string
- keyValuePairs.put(EVENT_TAG, String.valueOf(event.getTag()));
- keyValuePairs.put(EVENT_DATA, eventDataToString(event.getData()));
- return new ForensicEvent(EVENT_TYPE, keyValuePairs);
- }
-
- /**
- * Convert event data to a String.
- *
- * @param obj Object containing an Integer, Long, Float, String, null, or Object[] of the
- * same.
- * @return String representation of event data.
- */
- private String eventDataToString(Object obj) {
- if (obj == null) {
- return "";
- } else if (obj instanceof Integer
- || obj instanceof Long
- || obj instanceof Float
- || obj instanceof String) {
- return String.valueOf(obj);
- } else if (obj instanceof Object[]) {
- Object[] objArray = (Object[]) obj;
- String[] strArray = new String[objArray.length];
- for (int i = 0; i < objArray.length; ++i) {
- strArray[i] = eventDataToString(objArray[i]);
- }
- return Arrays.toString((String[]) strArray);
- } else {
- throw new IllegalArgumentException(
- "Unsupported data type: " + obj.getClass().getSimpleName());
- }
+ mDataAggregator.addBatchData(intrusionDetectionEvents);
}
}
}
diff --git a/services/core/java/com/android/server/stats/Android.bp b/services/core/java/com/android/server/stats/Android.bp
index f7955e86660a..40923b6009a5 100644
--- a/services/core/java/com/android/server/stats/Android.bp
+++ b/services/core/java/com/android/server/stats/Android.bp
@@ -11,3 +11,10 @@ java_aconfig_library {
name: "stats_flags_lib",
aconfig_declarations: "stats_flags",
}
+
+java_aconfig_library {
+ name: "stats_flags_lib_host",
+ aconfig_declarations: "stats_flags",
+ host_supported: true,
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
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 54e4f8e9a110..40ea9319c6be 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -61,6 +61,10 @@ import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS__SOFTWARE_SHORTCUT_TYPE__UNKNOWN_TYPE;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_CPU;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_IO;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_MEMORY;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__GEO;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__MANUAL;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
@@ -68,6 +72,7 @@ import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STA
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.Flags.accumulateNetworkStatsSinceBoot;
import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
+import static com.android.server.stats.Flags.addPressureStallInformationPuller;
import static com.android.server.stats.Flags.applyNetworkStatsPollRateLimit;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -234,6 +239,8 @@ import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
import com.android.server.stats.pull.netstats.NetworkStatsAccumulator;
import com.android.server.stats.pull.netstats.NetworkStatsExt;
import com.android.server.stats.pull.netstats.SubInfo;
+import com.android.server.stats.pull.psi.PsiData;
+import com.android.server.stats.pull.psi.PsiExtractor;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
import com.android.server.timezonedetector.MetricsTimeZoneDetectorState;
@@ -459,6 +466,10 @@ public class StatsPullAtomService extends SystemService {
public static final boolean ENABLE_MOBILE_DATA_STATS_AGGREGATED_PULLER =
addMobileBytesTransferByProcStatePuller();
+ // Whether or not to enable the new puller with pressure stall information.
+ public static final boolean ENABLE_PRESSURE_STALL_INFORMATION_PULLER =
+ addPressureStallInformationPuller();
+
// Puller locks
private final Object mDataBytesTransferLock = new Object();
private final Object mBluetoothBytesTransferLock = new Object();
@@ -835,6 +846,8 @@ public class StatsPullAtomService extends SystemService {
return pullHdrCapabilities(atomTag, data);
case FrameworkStatsLog.CACHED_APPS_HIGH_WATERMARK:
return pullCachedAppsHighWatermark(atomTag, data);
+ case FrameworkStatsLog.PRESSURE_STALL_INFORMATION:
+ return pullPressureStallInformation(atomTag, data);
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -1045,6 +1058,9 @@ public class StatsPullAtomService extends SystemService {
registerPinnerServiceStats();
registerHdrCapabilitiesPuller();
registerCachedAppsHighWatermarkPuller();
+ if (ENABLE_PRESSURE_STALL_INFORMATION_PULLER) {
+ registerPressureStallInformation();
+ }
}
private void initMobileDataStatsPuller() {
@@ -5156,6 +5172,55 @@ public class StatsPullAtomService extends SystemService {
);
}
+ private void registerPressureStallInformation() {
+ int tagId = FrameworkStatsLog.PRESSURE_STALL_INFORMATION;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null,
+ DIRECT_EXECUTOR,
+ mStatsCallbackImpl
+ );
+ }
+
+ int pullPressureStallInformation(int atomTag, List<StatsEvent> pulledData) {
+ PsiExtractor psiExtractor = new PsiExtractor();
+ for (PsiData.ResourceType resourceType: PsiData.ResourceType.values()) {
+ PsiData psiData = psiExtractor.getPsiData(resourceType);
+ if (psiData == null) {
+ Slog.e(
+ TAG,
+ "Failed to pull PressureStallInformation atom for resource: "
+ + resourceType.toString());
+ continue;
+ }
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ toProtoPsiResourceType(psiData.getResourceType()),
+ psiData.getSomeAvg10SecPercentage(),
+ psiData.getSomeAvg60SecPercentage(),
+ psiData.getSomeAvg300SecPercentage(),
+ psiData.getSomeTotalUsec(),
+ psiData.getFullAvg10SecPercentage(),
+ psiData.getFullAvg60SecPercentage(),
+ psiData.getFullAvg300SecPercentage(),
+ psiData.getFullTotalUsec()));
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ private int toProtoPsiResourceType(PsiData.ResourceType resourceType) {
+ if (resourceType == PsiData.ResourceType.CPU) {
+ return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_CPU;
+ } else if (resourceType == PsiData.ResourceType.MEMORY) {
+ return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_MEMORY;
+ } else if (resourceType == PsiData.ResourceType.IO) {
+ return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_IO;
+ } else {
+ return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_UNKNOWN;
+ }
+ }
+
+
int pullSystemServerPinnerStats(int atomTag, List<StatsEvent> pulledData) {
PinnerService pinnerService = LocalServices.getService(PinnerService.class);
List<PinnedFileStats> pinnedFileStats = pinnerService.dumpDataForStatsd();
diff --git a/services/core/java/com/android/server/stats/stats_flags.aconfig b/services/core/java/com/android/server/stats/stats_flags.aconfig
index 8686458ff8d4..f5f31746a09f 100644
--- a/services/core/java/com/android/server/stats/stats_flags.aconfig
+++ b/services/core/java/com/android/server/stats/stats_flags.aconfig
@@ -38,3 +38,11 @@ flag {
bug: "352537247"
is_fixed_read_only: true
}
+
+flag {
+ name: "add_pressure_stall_information_puller"
+ namespace: "statsd"
+ description: "Adds PressureStallInformation atom logging"
+ bug: "365731097"
+ is_fixed_read_only: true
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 465ac2f1731d..887e1861f789 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -61,6 +61,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -84,6 +85,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
+import com.android.internal.policy.IDeviceLockedStateListener;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockSettingsInternal;
@@ -105,6 +107,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
+import java.util.stream.IntStream;
/**
* Manages trust agents and trust listeners.
@@ -253,6 +256,10 @@ public class TrustManagerService extends SystemService {
new SparseArray<>();
private final SparseArray<TrustableTimeoutAlarmListener>
mIdleTrustableTimeoutAlarmListenerForUser = new SparseArray<>();
+
+ private final RemoteCallbackList<IDeviceLockedStateListener>
+ mDeviceLockedStateListeners = new RemoteCallbackList<>();
+
private AlarmManager mAlarmManager;
private final Object mAlarmLock = new Object();
@@ -1090,6 +1097,7 @@ public class TrustManagerService extends SystemService {
if (changed) {
notifyTrustAgentsOfDeviceLockState(userId, locked);
notifyKeystoreOfDeviceLockState(userId, locked);
+ notifyDeviceLockedListenersForUser(userId, locked);
// Also update the user's profiles who have unified challenge, since they
// share the same unlocked state (see {@link #isDeviceLocked(int)})
for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
@@ -1910,6 +1918,26 @@ public class TrustManagerService extends SystemService {
return mIsInSignificantPlace;
}
+ @EnforcePermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @Override
+ public void registerDeviceLockedStateListener(IDeviceLockedStateListener listener,
+ int deviceId) {
+ super.registerDeviceLockedStateListener_enforcePermission();
+ if (deviceId != Context.DEVICE_ID_DEFAULT) {
+ // Virtual devices are considered insecure.
+ return;
+ }
+ mDeviceLockedStateListeners.register(listener,
+ Integer.valueOf(UserHandle.getUserId(Binder.getCallingUid())));
+ }
+
+ @EnforcePermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @Override
+ public void unregisterDeviceLockedStateListener(IDeviceLockedStateListener listener) {
+ super.unregisterDeviceLockedStateListener_enforcePermission();
+ mDeviceLockedStateListeners.unregister(listener);
+ }
+
private void enforceReportPermission() {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
@@ -2031,6 +2059,7 @@ public class TrustManagerService extends SystemService {
}
notifyKeystoreOfDeviceLockState(userId, locked);
+ notifyDeviceLockedListenersForUser(userId, locked);
if (locked) {
try {
@@ -2497,4 +2526,24 @@ public class TrustManagerService extends SystemService {
updateTrust(mUserId, 0 /* flags */);
}
}
+
+ private void notifyDeviceLockedListenersForUser(int userId, boolean locked) {
+ int numListeners = mDeviceLockedStateListeners.beginBroadcast();
+ try {
+ IntStream.range(0, numListeners).forEach(i -> {
+ try {
+ Integer uid = (Integer) mDeviceLockedStateListeners.getBroadcastCookie(i);
+ if (userId == uid.intValue()) {
+ mDeviceLockedStateListeners.getBroadcastItem(i)
+ .onDeviceLockedStateChanged(locked);
+ }
+ } catch (RemoteException re) {
+ Log.i(TAG, "Service died", re);
+ }
+ });
+
+ } finally {
+ mDeviceLockedStateListeners.finishBroadcast();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 4589d26261dc..8bcf1a9be031 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -21,6 +21,7 @@ import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
import static android.media.tv.flags.Flags.tifUnbindInactiveTis;
import static android.media.tv.flags.Flags.kidsModeTvdbSharing;
+import static android.media.tv.flags.Flags.hdmiControlEnhancedBehavior;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -44,8 +45,10 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
+import android.hardware.hdmi.HdmiClient;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiTvClient;
import android.media.AudioPresentation;
import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
@@ -138,6 +141,8 @@ public final class TvInputManagerService extends SystemService {
private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS =
"com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS";
private static final long UPDATE_HARDWARE_TIS_BINDING_DELAY_IN_MILLIS = 10 * 1000; // 10 seconds
+ private static final long SET_TV_AS_ACTIVE_SOURCE_IF_NO_REQUEST_DELAY_IN_MILLIS
+ = 10 * 1000; // 10 seconds
// There are two different formats of DVB frontend devices. One is /dev/dvb%d.frontend%d,
// another one is /dev/dvb/adapter%d/frontend%d. Followings are the patterns for selecting the
@@ -185,6 +190,8 @@ public final class TvInputManagerService extends SystemService {
private final HashSet<String> mExternalInputLoggingDeviceOnScreenDisplayNames =
new HashSet<String>();
private final List<String> mExternalInputLoggingDeviceBrandNames = new ArrayList<String>();
+ private HdmiControlManager mHdmiControlManager = null;
+ private HdmiTvClient mHdmiTvClient = null;
public TvInputManagerService(Context context) {
super(context);
@@ -197,7 +204,12 @@ public final class TvInputManagerService extends SystemService {
mActivityManager =
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
-
+ mHdmiControlManager = mContext.getSystemService(HdmiControlManager.class);
+ if (mHdmiControlManager == null) {
+ Slog.w(TAG, "HdmiControlManager is null!");
+ } else {
+ mHdmiTvClient = mHdmiControlManager.getTvClient();
+ }
synchronized (mLock) {
getOrCreateUserStateLocked(mCurrentUserId);
}
@@ -208,6 +220,42 @@ public final class TvInputManagerService extends SystemService {
@Override
public void onStart() {
publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
+
+ if (!hdmiControlEnhancedBehavior()) {
+ return;
+ }
+
+ // To ensure the TV claims CEC active source status correctly, a receiver is registered to
+ // monitor wake-up and sleep intents. Upon wake-up, this receiver sends a delayed message
+ // triggering a TIF call into a CEC API to claim TV as the active source.
+ // However, the API call is cancelled if the TV switches inputs or goes to sleep.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ switch (action) {
+ case Intent.ACTION_SCREEN_ON:
+ Slog.w(TAG, "The TV woke up.");
+ mMessageHandler.removeMessages(
+ MessageHandler.MSG_CHECK_TV_AS_ACTIVE_SOURCE);
+ Message msg = mMessageHandler
+ .obtainMessage(MessageHandler.MSG_CHECK_TV_AS_ACTIVE_SOURCE);
+ mMessageHandler.sendMessageDelayed(msg,
+ SET_TV_AS_ACTIVE_SOURCE_IF_NO_REQUEST_DELAY_IN_MILLIS);
+ break;
+ case Intent.ACTION_SCREEN_OFF:
+ Slog.w(TAG, "The TV turned off.");
+ mMessageHandler.removeMessages(
+ MessageHandler.MSG_CHECK_TV_AS_ACTIVE_SOURCE);
+ break;
+ default:
+ return;
+ }
+ }
+ }, filter);
}
@Override
@@ -4503,6 +4551,7 @@ public final class TvInputManagerService extends SystemService {
static final int MSG_LOG_WATCH_END = 2;
static final int MSG_SWITCH_CONTENT_RESOLVER = 3;
static final int MSG_UPDATE_HARDWARE_TIS_BINDING = 4;
+ static final int MSG_CHECK_TV_AS_ACTIVE_SOURCE = 5;
private ContentResolver mContentResolver;
@@ -4575,8 +4624,27 @@ public final class TvInputManagerService extends SystemService {
args.recycle();
}
break;
+ case MSG_CHECK_TV_AS_ACTIVE_SOURCE:
+ synchronized (mLock) {
+ if (mOnScreenInputId == null) {
+ assertTvAsCecActiveSourceLocked();
+ break;
+ }
+ // TV that switched to a different input, but not an HDMI input
+ // (e.g. composite) can also assert active source.
+ UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
+ TvInputState inputState = userState.inputMap.get(mOnScreenInputId);
+ if (inputState == null) {
+ Slog.w(TAG, "Unexpected null TvInputState.");
+ break;
+ }
+ if (inputState.info.getType() != TvInputInfo.TYPE_HDMI) {
+ assertTvAsCecActiveSourceLocked();
+ }
+ }
+ break;
default: {
- Slog.w(TAG, "unhandled message code: " + msg.what);
+ Slog.w(TAG, "Unhandled message code: " + msg.what);
break;
}
}
@@ -4822,6 +4890,30 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
+ private void assertTvAsCecActiveSourceLocked() {
+ if (mHdmiTvClient == null) {
+ Slog.w(TAG, "HdmiTvClient is null!");
+ return;
+ }
+ mHdmiTvClient.selectDevice(HdmiDeviceInfo.DEVICE_TV,
+ mContext.getMainExecutor(),
+ new HdmiClient.OnDeviceSelectedListener() {
+ @Override
+ public void onDeviceSelected(int result,
+ int logicalAddress) {
+ if (result == HdmiControlManager.RESULT_SUCCESS) {
+ Slog.w(TAG,
+ "Setting TV as the active CEC device was successful.");
+ } else {
+ Slog.w(TAG,
+ "Setting TV as the active CEC device failed with result "
+ + result);
+ }
+ }
+ });
+ }
+
private static class SessionNotFoundException extends IllegalArgumentException {
public SessionNotFoundException(String name) {
super(name);
diff --git a/services/core/java/com/android/server/utils/LazyJniRegistrar.java b/services/core/java/com/android/server/utils/LazyJniRegistrar.java
index ac4a92e12909..6d29e9e58a98 100644
--- a/services/core/java/com/android/server/utils/LazyJniRegistrar.java
+++ b/services/core/java/com/android/server/utils/LazyJniRegistrar.java
@@ -42,6 +42,9 @@ public final class LazyJniRegistrar {
/** Registers native methods for ConsumerIrService. */
public static native void registerConsumerIrService();
+ /** Registers native methods for GameManagerService. */
+ public static native void registerGameManagerService();
+
/** Registers native methods for VrManagerService. */
public static native void registerVrManagerService();
}
diff --git a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
index 42203b113498..07d9ad16aca5 100644
--- a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
@@ -112,6 +112,14 @@ abstract class AbstractVibratorStep extends Step {
}
protected void stopVibrating() {
+ if (conductor.isInSession) {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "Vibration in session, skipping request to turn off vibrator "
+ + getVibratorId());
+ }
+ return;
+ }
if (VibrationThread.DEBUG) {
Slog.d(VibrationThread.TAG,
"Turning off vibrator " + getVibratorId());
diff --git a/services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java b/services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java
new file mode 100644
index 000000000000..54ae047a2858
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2024 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.vibrator;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.vibrator.IVibrator;
+import android.os.VibratorInfo;
+import android.os.vibrator.BasicPwleSegment;
+import android.os.vibrator.Flags;
+import android.os.vibrator.PwleSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.MathUtils;
+import android.util.Pair;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Adapts {@link BasicPwleSegment} instances to device-specific {@link PwleSegment}
+ * representations, considering device capabilities such as the supported frequency range
+ * (defined by the intersection points of the frequency-acceleration response curve with the
+ * minimum sensitivity threshold) and the maximum achievable sensitivity level.
+ *
+ * <p>The segments will not be changed if the device doesn't have
+ * {@link IVibrator#CAP_COMPOSE_PWLE_EFFECTS_V2}.
+ */
+final class BasicToPwleSegmentAdapter implements VibrationSegmentsAdapter {
+ private static final String TAG = "BasicToPwleSegmentAdapter";
+ private static final int MIN_REQUIRED_SENSITIVITY_DB_SL = 10;
+ /**
+ * An array of (frequency in Hz, minimum perceptible acceleration in dB) pairs.
+ * Each pair represents the minimum output level (in dB) required for a human to perceive the
+ * vibration at the corresponding frequency.
+ */
+ private static final Pair<Float, Float>[] MIN_PERCEPTIBLE_CURVE = new Pair[]{
+ Pair.create(0.4f, -97.81f), Pair.create(2.0f, -69.86f),
+ Pair.create(3.0f, -62.81f), Pair.create(4.0f, -58.81f),
+ Pair.create(5.0f, -56.69f), Pair.create(6.0f, -54.77f),
+ Pair.create(7.2f, -52.85f), Pair.create(8.0f, -51.77f),
+ Pair.create(8.64f, -50.84f), Pair.create(10.0f, -48.90f),
+ Pair.create(10.37f, -48.52f), Pair.create(12.44f, -46.50f),
+ Pair.create(14.93f, -44.43f), Pair.create(15.0f, -44.35f),
+ Pair.create(17.92f, -41.96f), Pair.create(20.0f, -40.36f),
+ Pair.create(21.5f, -39.60f), Pair.create(25.0f, -37.48f),
+ Pair.create(25.8f, -36.93f), Pair.create(30.0f, -34.31f),
+ Pair.create(35.0f, -33.13f), Pair.create(40.0f, -32.81f),
+ Pair.create(50.0f, -31.94f), Pair.create(60.0f, -31.77f),
+ Pair.create(70.0f, -31.59f), Pair.create(72.0f, -31.55f),
+ Pair.create(80.0f, -31.77f), Pair.create(86.4f, -31.94f),
+ Pair.create(90.0f, -31.73f), Pair.create(100.0f, -31.90f),
+ Pair.create(103.68f, -31.77f), Pair.create(124.42f, -31.70f),
+ Pair.create(149.3f, -31.38f), Pair.create(150.0f, -31.35f),
+ Pair.create(179.16f, -31.02f), Pair.create(200.0f, -30.86f),
+ Pair.create(215.0f, -30.35f), Pair.create(250.0f, -28.98f),
+ Pair.create(258.0f, -28.68f), Pair.create(300.0f, -26.81f),
+ Pair.create(400.0f, -19.81f)
+ };
+ private static final float[] sMinPerceptibleFrequenciesHz =
+ new float[MIN_PERCEPTIBLE_CURVE.length];
+ private static final float[] sMinPerceptibleAccelerationsDb =
+ new float[MIN_PERCEPTIBLE_CURVE.length];
+
+ BasicToPwleSegmentAdapter() {
+
+ // Sort the 'MIN_PERCEPTIBLE_LEVEL' data in ascending order based on the
+ // frequency values (first element of each pair).
+ Arrays.sort(MIN_PERCEPTIBLE_CURVE, Comparator.comparing(pair -> pair.first));
+
+ for (int i = 0; i < MIN_PERCEPTIBLE_CURVE.length; i++) {
+ sMinPerceptibleFrequenciesHz[i] = MIN_PERCEPTIBLE_CURVE[i].first;
+ sMinPerceptibleAccelerationsDb[i] = MIN_PERCEPTIBLE_CURVE[i].second;
+ }
+ }
+
+ @Override
+ public int adaptToVibrator(VibratorInfo info, List<VibrationEffectSegment> segments,
+ int repeatIndex) {
+ if (!Flags.normalizedPwleEffects()
+ || !info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+ // The vibrator does not have PWLE v2 capability, so keep the segments unchanged.
+ return repeatIndex;
+ }
+
+ VibratorInfo.FrequencyProfile frequencyProfile = info.getFrequencyProfile();
+ float[] frequenciesHz = frequencyProfile.getFrequenciesHz();
+ float[] accelerationsGs = frequencyProfile.getOutputAccelerationsGs();
+
+ Pair<Float, Float> frequencyRangeHz = calculateFrequencyRangeHz(
+ Objects.requireNonNull(frequenciesHz), Objects.requireNonNull(accelerationsGs));
+
+ if (frequencyRangeHz == null) {
+ // Failed to retrieve frequency range, so keep the segments unchanged.
+ return repeatIndex;
+ }
+ float minFrequencyHz = frequencyRangeHz.first;
+ float maxFrequencyHz = frequencyRangeHz.second;
+ float maxSensitivityLevel = getMaxSensitivityLevel(frequenciesHz, accelerationsGs,
+ minFrequencyHz, maxFrequencyHz);
+
+ for (int i = 0; i < segments.size(); i++) {
+ VibrationEffectSegment segment = segments.get(i);
+ if (segment instanceof BasicPwleSegment basicPwleSegment) {
+ PwleSegment pwleSegment = convertBasicToPwleSegment(frequencyProfile,
+ basicPwleSegment, minFrequencyHz, maxFrequencyHz,
+ maxSensitivityLevel);
+ segments.set(i, pwleSegment);
+ }
+ }
+
+ return repeatIndex;
+ }
+
+ /**
+ * Returns the supported frequency range within which {@link BasicPwleSegment}s are created.
+ * This range, also referred to as the "sharpness range", is defined by the
+ * minimum and maximum frequencies where the actuator's output acceleration exceeds the minimum
+ * required sensitivity level.
+ *
+ * <p>The minimum frequency is the first point where the actuator's frequency to output
+ * acceleration response curve intersects the minimum sensitivity threshold. The maximum
+ * frequency is determined by the second intersection point, or the maximum available
+ * frequency if no second intersection exists.
+ *
+ * @return The supported frequency range, or null if the minimum frequency cannot be determined.
+ */
+ @Nullable
+ private static Pair<Float, Float> calculateFrequencyRangeHz(@NonNull float[] frequenciesHz,
+ @NonNull float[] accelerationsGs) {
+ float minFrequencyHz = Float.NaN;
+ float maxFrequencyHz = Float.NaN;
+
+ for (int i = 0; i < frequenciesHz.length; i++) {
+ float minAcceptableOutputAcceleration = convertSensitivityLevelToAccelerationGs(
+ MIN_REQUIRED_SENSITIVITY_DB_SL, frequenciesHz[i]);
+
+ if (Float.isNaN(minFrequencyHz)
+ && minAcceptableOutputAcceleration <= accelerationsGs[i]) {
+ if (i == 0) {
+ minFrequencyHz = frequenciesHz[0];
+ } else {
+ minFrequencyHz = MathUtils.constrainedMap(
+ frequenciesHz[i - 1], frequenciesHz[i],
+ accelerationsGs[i - 1], accelerationsGs[i],
+ minAcceptableOutputAcceleration);
+ } // Found the lower bound
+ } else if (!Float.isNaN(minFrequencyHz)
+ && minAcceptableOutputAcceleration >= accelerationsGs[i]) {
+ maxFrequencyHz = MathUtils.constrainedMap(
+ frequenciesHz[i - 1], frequenciesHz[i],
+ accelerationsGs[i - 1], accelerationsGs[i],
+ minAcceptableOutputAcceleration); // Found the upper bound
+ return new Pair<>(minFrequencyHz, maxFrequencyHz);
+ }
+ }
+
+ if (Float.isNaN(minFrequencyHz)) {
+ // Lower bound was not found
+ Slog.e(TAG,
+ "Failed to retrieve frequency range. A valid frequency range must be "
+ + "available to create envelope vibration effects.");
+ return null;
+ }
+
+ // If only the lower bound was found, set the upper bound to the maximum frequency.
+ maxFrequencyHz = frequenciesHz[frequenciesHz.length - 1];
+
+ return new Pair<>(minFrequencyHz, maxFrequencyHz);
+ }
+
+ /**
+ * Converts the {@link BasicPwleSegment} to its equivalent {@link PwleSegment} based on the
+ * devices capabilities.
+ */
+ private static PwleSegment convertBasicToPwleSegment(
+ @NonNull VibratorInfo.FrequencyProfile frequencyProfile,
+ @NonNull BasicPwleSegment basicPwleSegment, float minFrequencyHz, float maxFrequencyHz,
+ float maxSensitivityLevel) {
+
+ float startFrequency = convertSharpnessToFrequencyHz(basicPwleSegment.getStartSharpness(),
+ minFrequencyHz, maxFrequencyHz);
+ float endFrequency = convertSharpnessToFrequencyHz(basicPwleSegment.getEndSharpness(),
+ minFrequencyHz, maxFrequencyHz);
+
+ float startAmplitude = convertIntensityToAmplitude(frequencyProfile,
+ basicPwleSegment.getStartIntensity(), startFrequency, maxSensitivityLevel);
+ float endAmplitude = convertIntensityToAmplitude(frequencyProfile,
+ basicPwleSegment.getEndIntensity(), endFrequency, maxSensitivityLevel);
+
+ return new PwleSegment(startAmplitude, endAmplitude, startFrequency, endFrequency,
+ basicPwleSegment.getDuration());
+ }
+
+ /**
+ * Calculates the amplitude for the vibrator, ranging [0.0, 1.0], based on the desired
+ * intensity and the vibrator's capabilities at the specified frequency.
+ *
+ * <p>This method first converts the desired intensity to an equivalent acceleration value
+ * based on the maximum sensitivity level within the sharpness range. It then compares this
+ * desired acceleration to the maximum acceleration the vibrator can produce at the given
+ * frequency.
+ *
+ * <p>If the desired acceleration exceeds the vibrator's capability, the method returns
+ * 1.0 (maximum amplitude). Otherwise, it returns a normalized amplitude value, calculated as
+ * the ratio of the desired acceleration to the maximum available acceleration at the given
+ * frequency.
+ */
+ private static float convertIntensityToAmplitude(VibratorInfo.FrequencyProfile frequencyProfile,
+ float intensity, float frequencyHz, float maxSensitivityLevel) {
+ if (intensity == 0) {
+ // Zero intensity should map to zero amplitude (i.e. vibrator off)
+ // instead of 0 db SL (i.e. the minimum perceivable output).
+ // This is for consistency with waveform envelopes, to ensure effects
+ // are able to ramp from/to the vibrator off state.
+ return 0;
+ }
+
+ float desiredAcceleration = convertIntensityToAccelerationGs(intensity, frequencyHz,
+ maxSensitivityLevel);
+ float availableAcceleration = frequencyProfile.getOutputAccelerationGs(
+ frequencyHz);
+ return desiredAcceleration >= availableAcceleration ? 1.0f
+ : desiredAcceleration / availableAcceleration;
+ }
+
+ private static float getMaxSensitivityLevel(float[] frequenciesHz, float[] accelerationsGs,
+ float minFrequencyHz, float maxFrequencyHz) {
+ float maxAccelerationGs = Float.MIN_VALUE;
+ int maxAccelerationIndex = -1;
+ for (int i = 0; i < frequenciesHz.length; i++) {
+ float frequency = frequenciesHz[i];
+ if (frequency < minFrequencyHz) {
+ continue;
+ }
+ if (frequency > maxFrequencyHz) {
+ break;
+ }
+ if (accelerationsGs[i] > maxAccelerationGs) {
+ maxAccelerationGs = accelerationsGs[i];
+ maxAccelerationIndex = i;
+ }
+ }
+
+ return convertDecibelToSensitivityLevel(convertAccelerationToDecibel(maxAccelerationGs),
+ frequenciesHz[maxAccelerationIndex]);
+ }
+
+ private static float convertSharpnessToFrequencyHz(float sharpness, float minFrequencyHz,
+ float maxFrequencyHz) {
+ return minFrequencyHz + sharpness * (maxFrequencyHz - minFrequencyHz);
+ }
+
+ private static float convertIntensityToAccelerationGs(float intensity, float frequencyHz,
+ float maxSensitivityLevel) {
+ return convertSensitivityLevelToAccelerationGs(intensity * maxSensitivityLevel,
+ frequencyHz);
+ }
+
+ private static float convertSensitivityLevelToAccelerationGs(float sensitivityLevel,
+ float frequencyHz) {
+ return convertDecibelToAccelerationGs(
+ convertSensitivityLevelToDecibel(sensitivityLevel, frequencyHz));
+ }
+
+ private static float convertDecibelToAccelerationGs(float db) {
+ return (float) Math.pow(10, db / 20);
+ }
+
+ private static float convertSensitivityLevelToDecibel(float sensitivityLevel,
+ float frequencyHz) {
+ float minPerceptibleDbAtFrequency = getMinPerceptibleAccelerationDb(frequencyHz);
+ return sensitivityLevel + minPerceptibleDbAtFrequency;
+ }
+
+ private static float convertAccelerationToDecibel(float accelerationGs) {
+ return (float) (20 * Math.log10(accelerationGs));
+ }
+
+ private static float convertDecibelToSensitivityLevel(float db, float frequencyHz) {
+ float minPerceptibleDbAtFrequency = getMinPerceptibleAccelerationDb(frequencyHz);
+ return db - minPerceptibleDbAtFrequency;
+ }
+
+ /**
+ * Retrieves the minimum perceptible acceleration, in dB, for the specified frequency (hz).
+ */
+ private static float getMinPerceptibleAccelerationDb(float frequencyHz) {
+
+ if (frequencyHz <= sMinPerceptibleFrequenciesHz[0]) {
+ return sMinPerceptibleAccelerationsDb[0];
+ }
+ if (frequencyHz >= sMinPerceptibleFrequenciesHz[sMinPerceptibleFrequenciesHz.length - 1]) {
+ return sMinPerceptibleAccelerationsDb[sMinPerceptibleAccelerationsDb.length - 1];
+ }
+
+ int idx = Arrays.binarySearch(sMinPerceptibleFrequenciesHz, frequencyHz);
+ if (idx >= 0) {
+ return sMinPerceptibleAccelerationsDb[idx];
+ }
+ // This indicates that the value was not found in the list. Adjust index of the
+ // insertion point to be at the lower bound.
+ idx = -idx - 2;
+
+ return MathUtils.constrainedMap(
+ sMinPerceptibleAccelerationsDb[idx],
+ sMinPerceptibleAccelerationsDb[idx + 1],
+ sMinPerceptibleFrequenciesHz[idx], sMinPerceptibleFrequenciesHz[idx + 1],
+ frequencyHz);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/DeviceAdapter.java b/services/core/java/com/android/server/vibrator/DeviceAdapter.java
index 751e83c7b9a9..e4542b359476 100644
--- a/services/core/java/com/android/server/vibrator/DeviceAdapter.java
+++ b/services/core/java/com/android/server/vibrator/DeviceAdapter.java
@@ -55,8 +55,9 @@ final class DeviceAdapter implements CombinedVibration.VibratorAdapter {
DeviceAdapter(VibrationSettings settings, SparseArray<VibratorController> vibrators) {
mSegmentAdapters = Arrays.asList(
- // TODO(b/167947076): add filter that removes unsupported primitives
// TODO(b/167947076): add filter that replaces unsupported prebaked with fallback
+ // Updates primitive delays to hardware supported pauses
+ new PrimitiveDelayAdapter(),
// Convert segments based on device capabilities
new RampToStepAdapter(settings.getRampStepDuration()),
new StepToRampAdapter(),
@@ -66,12 +67,16 @@ final class DeviceAdapter implements CombinedVibration.VibratorAdapter {
new SplitSegmentsAdapter(),
// Clip amplitudes and frequencies of final segments based on device bandwidth curve
new ClippingAmplitudeAndFrequencyAdapter(),
+ // Convert BasicPwleSegments to PwleSegments based on device capabilities
+ new BasicToPwleSegmentAdapter(),
// Split Pwle segments based on their duration and device supported limits
new SplitPwleSegmentsAdapter()
);
mSegmentsValidators = List.of(
// Validate Pwle segments base on the vibrators frequency range
- new PwleSegmentsValidator()
+ new PwleSegmentsValidator(),
+ // Validate primitive segments based on device support
+ new PrimitiveSegmentsValidator()
);
mAvailableVibrators = vibrators;
mAvailableVibratorIds = new int[vibrators.size()];
diff --git a/services/core/java/com/android/server/vibrator/PrimitiveDelayAdapter.java b/services/core/java/com/android/server/vibrator/PrimitiveDelayAdapter.java
new file mode 100644
index 000000000000..d63fffd4fed3
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/PrimitiveDelayAdapter.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2024 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.vibrator;
+
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
+
+import android.os.VibrationEffect.Composition.DelayType;
+import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.VibrationEffectSegment;
+
+import java.util.List;
+
+/**
+ * Adapter that converts between {@link DelayType} and the HAL supported pause delays.
+ *
+ * <p>Primitives that overlap due to the delays being shorter than the previous segments will be
+ * dropped from the effect here. Relative timings will still use the dropped primitives to preserve
+ * the design intention.
+ */
+final class PrimitiveDelayAdapter implements VibrationSegmentsAdapter {
+
+ PrimitiveDelayAdapter() {
+ }
+
+ @Override
+ public int adaptToVibrator(VibratorInfo info, List<VibrationEffectSegment> segments,
+ int repeatIndex) {
+ if (!Flags.primitiveCompositionAbsoluteDelay()) {
+ return repeatIndex;
+ }
+ int previousStartOffset = 0;
+ int segmentCount = segments.size();
+ for (int i = 0; i < segmentCount; i++) {
+ VibrationEffectSegment segment = segments.get(i);
+ if (i == repeatIndex) {
+ // Crossed the repeat line, reset start offset so repeating block is independent.
+ previousStartOffset = 0;
+ }
+
+ if (!(segment instanceof PrimitiveSegment primitive)
+ || (primitive.getDelayType() == DELAY_TYPE_PAUSE)) {
+ // Effect will play normally, keep track of its start offset.
+ previousStartOffset = -calculateEffectDuration(info, segment);
+ continue;
+ }
+
+ int pause = calculatePause(primitive, previousStartOffset);
+ if (pause >= 0) {
+ segments.set(i, toPrimitiveWithPause(primitive, pause));
+ // Delay will be ignored from this calculation.
+ previousStartOffset = -calculateEffectDuration(info, primitive);
+ } else {
+ // Primitive overlapping with previous segment, ignore it.
+ segments.remove(i);
+ if (repeatIndex > i) {
+ repeatIndex--;
+ }
+ segmentCount--;
+ i--;
+
+ // Keep the intended start time for future calculations. Here is an example:
+ // 10 20 30 40 50 60 70 | Timeline (D = relative delay, E = effect duration)
+ // D E E E E | D=10, E=40 | offset = 0 | pause = 10 | OK
+ // D E E | D=10, E=20 | offset = -40 | pause = -30 | IGNORED
+ // D E E | D=10, E=20 | offset = -30 | pause = -20 | IGNORED
+ // D E E | D=10, E=20 | offset = -20 | pause = -10 | IGNORED
+ // D E E | D=10, E=20 | offset = -10 | pause = 0 | OK
+ previousStartOffset = pause;
+ }
+ }
+ return repeatIndex;
+ }
+
+ private static int calculatePause(PrimitiveSegment primitive, int previousStartOffset) {
+ if (primitive.getDelayType() == DELAY_TYPE_RELATIVE_START_OFFSET) {
+ return previousStartOffset + primitive.getDelay();
+ }
+ return primitive.getDelay();
+ }
+
+ private static int calculateEffectDuration(VibratorInfo info, VibrationEffectSegment segment) {
+ long segmentDuration = segment.getDuration(info);
+ if (segmentDuration < 0) {
+ // Duration unknown, default to zero.
+ return 0;
+ }
+ int effectDuration = (int) segmentDuration;
+ if (segment instanceof PrimitiveSegment primitive) {
+ // Ignore primitive delays from effect duration.
+ effectDuration -= primitive.getDelay();
+ }
+ return effectDuration;
+ }
+
+ private static PrimitiveSegment toPrimitiveWithPause(PrimitiveSegment primitive, int pause) {
+ return new PrimitiveSegment(primitive.getPrimitiveId(), primitive.getScale(),
+ pause, DELAY_TYPE_PAUSE);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/PrimitiveSegmentsValidator.java b/services/core/java/com/android/server/vibrator/PrimitiveSegmentsValidator.java
new file mode 100644
index 000000000000..a1567fc470b5
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/PrimitiveSegmentsValidator.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 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.vibrator;
+
+import android.annotation.SuppressLint;
+import android.hardware.vibrator.IVibrator;
+import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.VibrationEffectSegment;
+
+import java.util.List;
+
+/**
+ * Validates primitive segments to ensure they are compatible with the device's capabilities.
+ *
+ * <p>The segments will be considered invalid if the device does not have
+ * {@link IVibrator#CAP_COMPOSE_EFFECTS} or if one of the primitives is not supported.
+ */
+final class PrimitiveSegmentsValidator implements VibrationSegmentsValidator {
+
+ @SuppressLint("WrongConstant") // using primitive id from validated segment
+ @Override
+ public boolean hasValidSegments(VibratorInfo info, List<VibrationEffectSegment> segments) {
+ int segmentCount = segments.size();
+ for (int i = 0; i < segmentCount; i++) {
+ if (!(segments.get(i) instanceof PrimitiveSegment primitive)) {
+ continue;
+ }
+ if (Flags.primitiveCompositionAbsoluteDelay()) {
+ // Primitive support checks introduced by this feature
+ if (!info.isPrimitiveSupported(primitive.getPrimitiveId())) {
+ return false;
+ }
+ } else {
+ // Delay type support not available without this feature
+ if ((primitive.getDelayType() != PrimitiveSegment.DEFAULT_DELAY_TYPE)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/PwleSegmentsValidator.java b/services/core/java/com/android/server/vibrator/PwleSegmentsValidator.java
index 87369aaabe98..85ba38d60dde 100644
--- a/services/core/java/com/android/server/vibrator/PwleSegmentsValidator.java
+++ b/services/core/java/com/android/server/vibrator/PwleSegmentsValidator.java
@@ -18,20 +18,30 @@ package com.android.server.vibrator;
import android.hardware.vibrator.IVibrator;
import android.os.VibratorInfo;
+import android.os.vibrator.BasicPwleSegment;
import android.os.vibrator.PwleSegment;
import android.os.vibrator.VibrationEffectSegment;
import java.util.List;
/**
- * Validates Pwle segments to ensure they are compatible with the device's capabilities
- * and adhere to frequency constraints.
+ * Validates {@link PwleSegment} and {@link BasicPwleSegment} instances to ensure they are
+ * compatible with the device's capabilities.
*
- * <p>The validator verifies that each segment's start and end frequencies fall within
- * the supported range.
- *
- * <p>The segments will be considered invalid of the device does not have
- * {@link IVibrator#CAP_COMPOSE_PWLE_EFFECTS_V2}.
+ * <p>This validator performs the following checks:
+ * <ul>
+ * <li>For {@link PwleSegment}:
+ * <ul>
+ * <li>Verifies that the device supports {@link IVibrator#CAP_COMPOSE_PWLE_EFFECTS_V2}.
+ * <li>Verifies that each segment's start and end frequencies fall within the supported range.
+ * </ul>
+ * </li>
+ * <li>For {@link BasicPwleSegment}:
+ * <ul>
+ * <li>Verifies that the device supports {@link IVibrator#CAP_COMPOSE_PWLE_EFFECTS_V2}.
+ * </ul>
+ * </li>
+ * </ul>
*/
final class PwleSegmentsValidator implements VibrationSegmentsValidator {
@@ -43,16 +53,17 @@ final class PwleSegmentsValidator implements VibrationSegmentsValidator {
float maxFrequency = info.getFrequencyProfile().getMaxFrequencyHz();
for (VibrationEffectSegment segment : segments) {
- if (!(segment instanceof PwleSegment pwleSegment)) {
- continue;
- }
-
- if (!hasPwleCapability || pwleSegment.getStartFrequencyHz() < minFrequency
- || pwleSegment.getStartFrequencyHz() > maxFrequency
- || pwleSegment.getEndFrequencyHz() < minFrequency
- || pwleSegment.getEndFrequencyHz() > maxFrequency) {
+ if (segment instanceof BasicPwleSegment && !hasPwleCapability) {
return false;
}
+ if (segment instanceof PwleSegment pwleSegment) {
+ if (!hasPwleCapability || pwleSegment.getStartFrequencyHz() < minFrequency
+ || pwleSegment.getStartFrequencyHz() > maxFrequency
+ || pwleSegment.getEndFrequencyHz() < minFrequency
+ || pwleSegment.getEndFrequencyHz() > maxFrequency) {
+ return false;
+ }
+ }
}
return true;
diff --git a/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java b/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java
index ad44227d935a..a8c4ac8cdeeb 100644
--- a/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java
+++ b/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java
@@ -44,7 +44,7 @@ final class SplitPwleSegmentsAdapter implements VibrationSegmentsAdapter {
// The vibrator does not have PWLE v2 capability, so keep the segments unchanged.
return repeatIndex;
}
- int maxPwleDuration = info.getMaxEnvelopeEffectDurationMillis();
+ int maxPwleDuration = (int) info.getMaxEnvelopeEffectDurationMillis();
if (maxPwleDuration <= 0) {
// No limit set to PWLE primitive duration.
return repeatIndex;
diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
index 07478e360d27..9e75cf2fc3f3 100644
--- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
+++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
@@ -37,8 +37,11 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
@@ -60,6 +63,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub
* used for another vibration.
*/
void onSessionReleased(long sessionId);
+
+ /** Request the manager to trigger a vibration within this session. */
+ void vibrate(long sessionId, CallerInfo callerInfo, CombinedVibration vibration);
}
private final Object mLock = new Object();
@@ -71,7 +77,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub
private final IVibrationSessionCallback mCallback;
private final CallerInfo mCallerInfo;
private final VibratorManagerHooks mManagerHooks;
+ private final DeviceAdapter mDeviceAdapter;
private final Handler mHandler;
+ private final List<DebugInfo> mVibrations = new ArrayList<>();
@GuardedBy("mLock")
private Status mStatus = Status.RUNNING;
@@ -83,24 +91,28 @@ final class VendorVibrationSession extends IVibrationSession.Stub
private long mEndUptime;
@GuardedBy("mLock")
private long mEndTime; // for debugging
+ @GuardedBy("mLock")
+ private VibrationStepConductor mConductor;
VendorVibrationSession(@NonNull CallerInfo callerInfo, @NonNull Handler handler,
- @NonNull VibratorManagerHooks managerHooks, @NonNull int[] vibratorIds,
+ @NonNull VibratorManagerHooks managerHooks, @NonNull DeviceAdapter deviceAdapter,
@NonNull IVibrationSessionCallback callback) {
mCreateUptime = SystemClock.uptimeMillis();
mCreateTime = System.currentTimeMillis();
- mVibratorIds = vibratorIds;
+ mVibratorIds = deviceAdapter.getAvailableVibratorIds();
mHandler = handler;
mCallback = callback;
mCallerInfo = callerInfo;
mManagerHooks = managerHooks;
+ mDeviceAdapter = deviceAdapter;
CancellationSignal.fromTransport(mCancellationSignal).setOnCancelListener(this);
}
@Override
public void vibrate(CombinedVibration vibration, String reason) {
- // TODO(b/345414356): implement vibration support
- throw new UnsupportedOperationException("Vendor session vibrations not yet implemented");
+ CallerInfo vibrationCallerInfo = new CallerInfo(mCallerInfo.attrs, mCallerInfo.uid,
+ mCallerInfo.deviceId, mCallerInfo.opPkg, reason);
+ mManagerHooks.vibrate(mSessionId, vibrationCallerInfo, vibration);
}
@Override
@@ -146,7 +158,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
public DebugInfo getDebugInfo() {
synchronized (mLock) {
return new DebugInfoImpl(mStatus, mCallerInfo, mCreateUptime, mCreateTime, mStartTime,
- mEndUptime, mEndTime);
+ mEndUptime, mEndTime, mVibrations);
}
}
@@ -200,12 +212,12 @@ final class VendorVibrationSession extends IVibrationSession.Stub
@Override
public void notifyVibratorCallback(int vibratorId, long vibrationId) {
- // TODO(b/345414356): implement vibration support
+ // Ignore it, the session vibration playback doesn't depend on HAL timings
}
@Override
public void notifySyncedVibratorsCallback(long vibrationId) {
- // TODO(b/345414356): implement vibration support
+ // Ignore it, the session vibration playback doesn't depend on HAL timings
}
@Override
@@ -214,8 +226,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub
// If end was not requested then the HAL has cancelled the session.
maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON);
maybeSetStatusToRequestedLocked();
+ clearVibrationConductor();
}
- mManagerHooks.onSessionReleased(mSessionId);
+ mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId));
}
@Override
@@ -228,7 +241,8 @@ final class VendorVibrationSession extends IVibrationSession.Stub
/* includeDate= */ true))
+ ", status: " + mStatus.name().toLowerCase(Locale.ROOT)
+ ", callerInfo: " + mCallerInfo
- + ", vibratorIds: " + Arrays.toString(mVibratorIds);
+ + ", vibratorIds: " + Arrays.toString(mVibratorIds)
+ + ", vibrations: " + mVibrations;
}
}
@@ -254,6 +268,13 @@ final class VendorVibrationSession extends IVibrationSession.Stub
return mVibratorIds;
}
+ @VisibleForTesting
+ public List<DebugInfo> getVibrations() {
+ synchronized (mLock) {
+ return new ArrayList<>(mVibrations);
+ }
+ }
+
public ICancellationSignal getCancellationSignal() {
return mCancellationSignal;
}
@@ -278,7 +299,39 @@ final class VendorVibrationSession extends IVibrationSession.Stub
}
if (isAlreadyEnded) {
// Session already ended, make sure we end it in the HAL.
- mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true);
+ mHandler.post(() -> mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true));
+ }
+ }
+
+ public void notifyVibrationAttempt(DebugInfo vibrationDebugInfo) {
+ mVibrations.add(vibrationDebugInfo);
+ }
+
+ @Nullable
+ public VibrationStepConductor clearVibrationConductor() {
+ synchronized (mLock) {
+ VibrationStepConductor conductor = mConductor;
+ if (conductor != null) {
+ mVibrations.add(conductor.getVibration().getDebugInfo());
+ }
+ mConductor = null;
+ return conductor;
+ }
+ }
+
+ public DeviceAdapter getDeviceAdapter() {
+ return mDeviceAdapter;
+ }
+
+ public boolean maybeSetVibrationConductor(VibrationStepConductor conductor) {
+ synchronized (mLock) {
+ if (mConductor != null) {
+ Slog.d(TAG, "Vibration session still dispatching previous vibration,"
+ + " new vibration ignored");
+ return false;
+ }
+ mConductor = conductor;
+ return true;
}
}
@@ -296,7 +349,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
}
}
if (shouldTriggerSessionHook) {
- mManagerHooks.endSession(mSessionId, shouldAbort);
+ mHandler.post(() -> mManagerHooks.endSession(mSessionId, shouldAbort));
}
}
@@ -309,6 +362,11 @@ final class VendorVibrationSession extends IVibrationSession.Stub
mEndStatusRequest = status;
mEndTime = System.currentTimeMillis();
mEndUptime = SystemClock.uptimeMillis();
+ if (mConductor != null) {
+ // Vibration is being dispatched when session end was requested, cancel it.
+ mConductor.notifyCancelled(new Vibration.EndInfo(status),
+ /* immediate= */ status != Status.FINISHED);
+ }
if (isStarted()) {
// Only trigger "finishing" callback if session started.
// Run client callback in separate thread.
@@ -377,6 +435,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
static final class DebugInfoImpl implements VibrationSession.DebugInfo {
private final Status mStatus;
private final CallerInfo mCallerInfo;
+ private final List<DebugInfo> mVibrations;
private final long mCreateUptime;
private final long mCreateTime;
@@ -385,7 +444,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
private final long mDurationMs;
DebugInfoImpl(Status status, CallerInfo callerInfo, long createUptime, long createTime,
- long startTime, long endUptime, long endTime) {
+ long startTime, long endUptime, long endTime, List<DebugInfo> vibrations) {
mStatus = status;
mCallerInfo = callerInfo;
mCreateUptime = createUptime;
@@ -393,6 +452,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
mStartTime = startTime;
mEndTime = endTime;
mDurationMs = endUptime > 0 ? endUptime - createUptime : -1;
+ mVibrations = vibrations == null ? new ArrayList<>() : new ArrayList<>(vibrations);
}
@Override
@@ -418,6 +478,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub
@Override
public void logMetrics(VibratorFrameworkStatsLogger statsLogger) {
+ for (DebugInfo vibration : mVibrations) {
+ vibration.logMetrics(statsLogger);
+ }
}
@Override
@@ -448,6 +511,14 @@ final class VendorVibrationSession extends IVibrationSession.Stub
pw.println("endTime = " + (mEndTime == 0 ? null
: formatTime(mEndTime, /*includeDate=*/ true)));
pw.println("callerInfo = " + mCallerInfo);
+
+ pw.println("vibrations:");
+ pw.increaseIndent();
+ for (DebugInfo vibration : mVibrations) {
+ vibration.dump(pw);
+ }
+ pw.decreaseIndent();
+
pw.decreaseIndent();
}
@@ -477,6 +548,12 @@ final class VendorVibrationSession extends IVibrationSession.Stub
" | %s (uid=%d, deviceId=%d) | reason: %s",
mCallerInfo.opPkg, mCallerInfo.uid, mCallerInfo.deviceId, mCallerInfo.reason);
pw.println(timingsStr + paramStr + audioUsageStr + callerStr);
+
+ pw.increaseIndent();
+ for (DebugInfo vibration : mVibrations) {
+ vibration.dumpCompact(pw);
+ }
+ pw.decreaseIndent();
}
@Override
@@ -487,7 +564,8 @@ final class VendorVibrationSession extends IVibrationSession.Stub
/* includeDate= */ true))
+ ", durationMs: " + mDurationMs
+ ", status: " + mStatus.name().toLowerCase(Locale.ROOT)
- + ", callerInfo: " + mCallerInfo;
+ + ", callerInfo: " + mCallerInfo
+ + ", vibrations: " + mVibrations;
}
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 9cb8c1ada246..797a350e4395 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -617,11 +617,11 @@ final class VibrationSettings {
private void updateRingerMode() {
synchronized (mLock) {
- // If audio manager was not loaded yet then assume most restrictive mode.
- // This will be loaded again as soon as the audio manager is loaded in onSystemReady.
- mRingerMode = (mAudioManager == null)
- ? AudioManager.RINGER_MODE_SILENT
- : mAudioManager.getRingerModeInternal();
+ if (mAudioManager == null) {
+ // Service not ready yet or audio service not available, skip this update request.
+ return;
+ }
+ mRingerMode = mAudioManager.getRingerModeInternal();
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 6a4790daf056..1e20debe156d 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -69,6 +69,7 @@ final class VibrationStepConductor {
// Used within steps.
public final VibrationSettings vibrationSettings;
public final VibrationThread.VibratorManagerHooks vibratorManagerHooks;
+ public final boolean isInSession;
private final DeviceAdapter mDeviceAdapter;
private final VibrationScaler mVibrationScaler;
@@ -105,12 +106,13 @@ final class VibrationStepConductor {
private int mRemainingStartSequentialEffectSteps;
private int mSuccessfulVibratorOnSteps;
- VibrationStepConductor(HalVibration vib, VibrationSettings vibrationSettings,
- DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler,
- VibratorFrameworkStatsLogger statsLogger,
+ VibrationStepConductor(HalVibration vib, boolean isInSession,
+ VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter,
+ VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger,
CompletableFuture<Void> requestVibrationParamsFuture,
VibrationThread.VibratorManagerHooks vibratorManagerHooks) {
this.mVibration = vib;
+ this.isInSession = isInSession;
this.vibrationSettings = vibrationSettings;
this.mDeviceAdapter = deviceAdapter;
mVibrationScaler = vibrationScaler;
@@ -286,6 +288,9 @@ final class VibrationStepConductor {
if (nextStep == null) {
return true; // Finished
}
+ if (isInSession) {
+ return true; // Don't wait to play session vibration steps
+ }
long waitMillis = nextStep.calculateWaitTime();
if (waitMillis <= 0) {
return true; // Regular step ready
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 476448148e28..cc163db4dc36 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -106,7 +106,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
private static final String VIBRATOR_CONTROL_SERVICE =
"android.frameworks.vibrator.IVibratorControlService/default";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
new VibrationAttributes.Builder().build();
private static final int ATTRIBUTES_ALL_BYPASS_FLAGS =
@@ -610,6 +610,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_ERROR_TOKEN);
return null;
}
+ enforceUpdateAppOpsStatsPermission(uid);
+ if (!isEffectValid(effect)) {
+ logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_UNSUPPORTED);
+ return null;
+ }
if (effect.hasVendorEffects()) {
if (!Flags.vendorVibrationEffects()) {
Slog.e(TAG, "vibrate; vendor effects feature disabled");
@@ -622,11 +627,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
return null;
}
}
- enforceUpdateAppOpsStatsPermission(uid);
- if (!isEffectValid(effect)) {
- logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_UNSUPPORTED);
- return null;
- }
// Create Vibration.Stats as close to the received request as possible, for tracking.
SingleVibrationSession session = new SingleVibrationSession(token, callerInfo, effect);
HalVibration vib = session.getVibration();
@@ -658,6 +658,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
// If not ignored so far then try to start this vibration.
if (ignoreStatus == null) {
+ // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls
final long ident = Binder.clearCallingIdentity();
try {
if (mCurrentSession != null) {
@@ -703,6 +704,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if (DEBUG) {
Slog.d(TAG, "Canceling vibration");
}
+ // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls
final long ident = Binder.clearCallingIdentity();
try {
// TODO(b/370948466): investigate why token not checked on external vibrations.
@@ -762,8 +764,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
vibratorIds = new int[0];
}
enforceUpdateAppOpsStatsPermission(uid);
+
+ // Create session with adapter that only uses the session vibrators.
+ SparseArray<VibratorController> sessionVibrators = new SparseArray<>(vibratorIds.length);
+ for (int vibratorId : vibratorIds) {
+ VibratorController controller = mVibrators.get(vibratorId);
+ if (controller != null) {
+ sessionVibrators.put(vibratorId, controller);
+ }
+ }
+ DeviceAdapter deviceAdapter = new DeviceAdapter(mVibrationSettings, sessionVibrators);
VendorVibrationSession session = new VendorVibrationSession(callerInfo, mHandler,
- mVendorVibrationSessionCallbacks, vibratorIds, callback);
+ mVendorVibrationSessionCallbacks, deviceAdapter, callback);
if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
// Force update of user settings before checking if this vibration effect should
@@ -787,12 +799,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
ignoreStatus = Status.IGNORED_UNSUPPORTED;
}
- // Check if any vibrator ID was requested.
- if (ignoreStatus == null && vibratorIds.length == 0) {
- if (DEBUG) {
- Slog.d(TAG, "Empty vibrator ids to start session, ignoring request");
+ // Check if vibrator IDs requested are available.
+ if (ignoreStatus == null) {
+ if (vibratorIds.length == 0
+ || vibratorIds.length != deviceAdapter.getAvailableVibratorIds().length) {
+ Slog.e(TAG, "Bad vibrator ids to start session, ignoring request."
+ + " requested=" + Arrays.toString(vibratorIds)
+ + " available=" + Arrays.toString(mVibratorIds));
+ ignoreStatus = Status.IGNORED_UNSUPPORTED;
}
- ignoreStatus = Status.IGNORED_UNSUPPORTED;
}
// Check if user settings or DnD is set to ignore this session.
@@ -810,6 +825,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
if (ignoreStatus == null) {
+ // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls
final long ident = Binder.clearCallingIdentity();
try {
// If not ignored so far then stop ongoing sessions before starting this one.
@@ -839,22 +855,40 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private Status startVendorSessionLocked(VendorVibrationSession session) {
Trace.traceBegin(TRACE_TAG_VIBRATOR, "startSessionLocked");
try {
+ long sessionId = session.getSessionId();
+ if (DEBUG) {
+ Slog.d(TAG, "Starting session " + sessionId + " in HAL");
+ }
if (session.isEnded()) {
// Session already ended, possibly cancelled by app cancellation signal.
return session.getStatus();
}
- if (!session.linkToDeath()) {
- return Status.IGNORED_ERROR_TOKEN;
- }
- if (!mNativeWrapper.startSession(session.getSessionId(), session.getVibratorIds())) {
- Slog.e(TAG, "Error starting session " + session.getSessionId()
- + " on vibrators " + Arrays.toString(session.getVibratorIds()));
- session.unlinkToDeath();
- return Status.IGNORED_UNSUPPORTED;
+ int mode = startAppOpModeLocked(session.getCallerInfo());
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ Trace.asyncTraceBegin(TRACE_TAG_VIBRATOR, "vibration", 0);
+ // Make sure mCurrentVibration is set while triggering the HAL.
+ mCurrentSession = session;
+ if (!session.linkToDeath()) {
+ mCurrentSession = null;
+ return Status.IGNORED_ERROR_TOKEN;
+ }
+ if (!mNativeWrapper.startSession(sessionId, session.getVibratorIds())) {
+ Slog.e(TAG, "Error starting session " + sessionId + " on vibrators "
+ + Arrays.toString(session.getVibratorIds()));
+ session.unlinkToDeath();
+ mCurrentSession = null;
+ return Status.IGNORED_UNSUPPORTED;
+ }
+ session.notifyStart();
+ return null;
+ case AppOpsManager.MODE_ERRORED:
+ Slog.w(TAG, "Start AppOpsManager operation errored for uid "
+ + session.getCallerInfo().uid);
+ return Status.IGNORED_ERROR_APP_OPS;
+ default:
+ return Status.IGNORED_APP_OPS;
}
- session.notifyStart();
- mCurrentSession = session;
- return null;
} finally {
Trace.traceEnd(TRACE_TAG_VIBRATOR);
}
@@ -1045,6 +1079,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
@GuardedBy("mLock")
@Nullable
private Status startVibrationOnThreadLocked(SingleVibrationSession session) {
+ if (DEBUG) {
+ Slog.d(TAG, "Starting vibration " + session.getVibration().id + " on thread");
+ }
VibrationStepConductor conductor = createVibrationStepConductor(session.getVibration());
session.setVibrationConductor(conductor);
int mode = startAppOpModeLocked(session.getCallerInfo());
@@ -1080,12 +1117,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
mNextSession = null;
Status errorStatus = startVibrationOnThreadLocked(session);
if (errorStatus != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Error starting next vibration " + session.getVibration().id);
+ }
endSessionLocked(session, errorStatus);
}
} else if (mNextSession instanceof VendorVibrationSession session) {
mNextSession = null;
Status errorStatus = startVendorSessionLocked(session);
if (errorStatus != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Error starting next session " + session.getSessionId());
+ }
endSessionLocked(session, errorStatus);
}
} // External vibrations cannot be started asynchronously.
@@ -1103,6 +1146,16 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
private VibrationStepConductor createVibrationStepConductor(HalVibration vib) {
+ return createVibrationStepConductor(vib, mDeviceAdapter, /* isInSession= */ false);
+ }
+
+ private VibrationStepConductor createSessionVibrationStepConductor(HalVibration vib,
+ DeviceAdapter deviceAdapter) {
+ return createVibrationStepConductor(vib, deviceAdapter, /* isInSession= */ true);
+ }
+
+ private VibrationStepConductor createVibrationStepConductor(HalVibration vib,
+ DeviceAdapter deviceAdapter, boolean isInSession) {
CompletableFuture<Void> requestVibrationParamsFuture = null;
if (Flags.adaptiveHapticsEnabled()
@@ -1114,8 +1167,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
mVibrationSettings.getRequestVibrationParamsTimeoutMs());
}
- return new VibrationStepConductor(vib, mVibrationSettings, mDeviceAdapter, mVibrationScaler,
- mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks);
+ return new VibrationStepConductor(vib, isInSession, mVibrationSettings,
+ deviceAdapter, mVibrationScaler, mFrameworkStatsLogger,
+ requestVibrationParamsFuture, mVibrationThreadCallbacks);
}
private Status startVibrationOnInputDevicesLocked(HalVibration vib) {
@@ -1135,18 +1189,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private void logAndRecordVibrationAttempt(@Nullable CombinedVibration effect,
CallerInfo callerInfo, Status status) {
- logAndRecordVibration(
- new Vibration.DebugInfoImpl(status, callerInfo,
- VibrationStats.StatsInfo.findVibrationType(effect), new VibrationStats(),
- effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE,
- VibrationScaler.ADAPTIVE_SCALE_NONE));
+ logAndRecordVibration(createVibrationAttemptDebugInfo(effect, callerInfo, status));
}
private void logAndRecordSessionAttempt(CallerInfo callerInfo, Status status) {
logAndRecordVibration(
new VendorVibrationSession.DebugInfoImpl(status, callerInfo,
SystemClock.uptimeMillis(), System.currentTimeMillis(),
- /* startTime= */ 0, /* endUptime= */ 0, /* endTime= */ 0));
+ /* startTime= */ 0, /* endUptime= */ 0, /* endTime= */ 0,
+ /* vibrations= */ null));
}
private void logAndRecordVibration(DebugInfo info) {
@@ -1155,6 +1206,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
mVibratorManagerRecords.record(info);
}
+ private DebugInfo createVibrationAttemptDebugInfo(@Nullable CombinedVibration effect,
+ CallerInfo callerInfo, Status status) {
+ return new Vibration.DebugInfoImpl(status, callerInfo,
+ VibrationStats.StatsInfo.findVibrationType(effect), new VibrationStats(),
+ effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE,
+ VibrationScaler.ADAPTIVE_SCALE_NONE);
+ }
+
private void logVibrationStatus(int uid, VibrationAttributes attrs, Status status) {
switch (status) {
case IGNORED_BACKGROUND:
@@ -1765,25 +1824,35 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
Trace.traceBegin(TRACE_TAG_VIBRATOR, "onVibrationThreadReleased");
try {
synchronized (mLock) {
- if (!(mCurrentSession instanceof SingleVibrationSession session)) {
+ if (mCurrentSession instanceof SingleVibrationSession session) {
+ if (Build.IS_DEBUGGABLE && (session.getVibration().id != vibrationId)) {
+ Slog.wtf(TAG, TextUtils.formatSimple(
+ "VibrationId mismatch on vibration thread release."
+ + " expected=%d, released=%d",
+ session.getVibration().id, vibrationId));
+ }
+ finishAppOpModeLocked(mCurrentSession.getCallerInfo());
+ clearCurrentSessionLocked();
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+ // Start next vibration if it's waiting for the thread.
+ maybeStartNextSessionLocked();
+ } else if (mCurrentSession instanceof VendorVibrationSession session) {
+ VibrationStepConductor conductor = session.clearVibrationConductor();
if (Build.IS_DEBUGGABLE) {
- Slog.wtf(TAG, "VibrationSession invalid on vibration thread release."
- + " currentSession=" + mCurrentSession);
+ if (conductor == null) {
+ Slog.wtf(TAG, "Vendor session without ongoing vibration on"
+ + " thread release. currentSession=" + mCurrentSession);
+ } else if (conductor.getVibration().id != vibrationId) {
+ Slog.wtf(TAG, TextUtils.formatSimple(
+ "VibrationId mismatch on vibration thread release."
+ + " expected=%d, released=%d",
+ conductor.getVibration().id, vibrationId));
+ }
}
- // Only single vibration sessions are ended by thread being released. Abort.
- return;
+ } else if (Build.IS_DEBUGGABLE) {
+ Slog.wtf(TAG, "VibrationSession invalid on vibration thread release."
+ + " currentSession=" + mCurrentSession);
}
- if (Build.IS_DEBUGGABLE && (session.getVibration().id != vibrationId)) {
- Slog.wtf(TAG, TextUtils.formatSimple(
- "VibrationId mismatch on vibration thread release."
- + " expected=%d, released=%d",
- session.getVibration().id, vibrationId));
- }
- finishAppOpModeLocked(mCurrentSession.getCallerInfo());
- clearCurrentSessionLocked();
- Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- // Start next vibration if it's waiting for the thread.
- maybeStartNextSessionLocked();
}
} finally {
Trace.traceEnd(TRACE_TAG_VIBRATOR);
@@ -1838,6 +1907,86 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
implements VendorVibrationSession.VibratorManagerHooks {
@Override
+ public void vibrate(long sessionId, CallerInfo callerInfo, CombinedVibration effect) {
+ if (DEBUG) {
+ Slog.d(TAG, "Vibration session " + sessionId + " vibration requested");
+ }
+ Trace.traceBegin(TRACE_TAG_VIBRATOR, "sessionVibrate");
+ try {
+ synchronized (mLock) {
+ if (!(mCurrentSession instanceof VendorVibrationSession session)) {
+ if (Build.IS_DEBUGGABLE) {
+ Slog.wtf(TAG, "VibrationSession invalid on session vibrate."
+ + " currentSession=" + mCurrentSession);
+ }
+ // Only vendor vibration sessions can handle this call. Abort.
+ return;
+ }
+ if (session.getSessionId() != sessionId) {
+ if (Build.IS_DEBUGGABLE) {
+ Slog.wtf(TAG, TextUtils.formatSimple(
+ "SessionId mismatch on vendor vibration session vibrate."
+ + " expected=%d, released=%d",
+ session.getSessionId(), sessionId));
+ }
+ // Only the ongoing vendor vibration sessions can handle this call. Abort.
+ return;
+ }
+ if (session.wasEndRequested()) {
+ if (DEBUG) {
+ Slog.d(TAG, "session vibrate; session is ending, vibration ignored");
+ }
+ session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+ callerInfo, Status.IGNORED_ERROR_SCHEDULING));
+ return;
+ }
+ if (!isEffectValid(effect)) {
+ session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+ callerInfo, Status.IGNORED_UNSUPPORTED));
+ return;
+ }
+ if (effect.getDuration() == Long.MAX_VALUE) {
+ // Repeating effects cannot be played by the service in a session.
+ session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+ callerInfo, Status.IGNORED_UNSUPPORTED));
+ return;
+ }
+ // Create Vibration.Stats as close to the request as possible, for tracking.
+ HalVibration vib = new HalVibration(callerInfo, effect);
+ vib.fillFallbacks(mVibrationSettings::getFallbackEffect);
+
+ if (callerInfo.attrs.isFlagSet(
+ VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+ // Force update of user settings before checking if this vibration effect
+ // should be ignored or scaled.
+ mVibrationSettings.update();
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Starting vibrate for vibration " + vib.id
+ + " in session " + sessionId);
+ }
+
+ VibrationStepConductor conductor =
+ createSessionVibrationStepConductor(vib, session.getDeviceAdapter());
+ if (session.maybeSetVibrationConductor(conductor)) {
+ if (!mVibrationThread.runVibrationOnVibrationThread(conductor)) {
+ // Shouldn't happen. The method call already logs.
+ vib.end(new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING));
+ session.clearVibrationConductor(); // Rejected by thread, clear it.
+ }
+ } else {
+ // Cannot set vibration in session, log failed attempt.
+ session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+ callerInfo, Status.IGNORED_ERROR_SCHEDULING));
+ }
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_VIBRATOR);
+ }
+ }
+
+ @Override
public void endSession(long sessionId, boolean shouldAbort) {
if (DEBUG) {
Slog.d(TAG, "Vibration session " + sessionId
@@ -1873,6 +2022,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
+ " expected=%d, released=%d",
session.getSessionId(), sessionId));
}
+ // Make sure all controllers in session are reset after session ended.
+ // This will update the vibrator state to isVibrating = false for listeners.
+ for (int vibratorId : session.getVibratorIds()) {
+ mVibrators.get(vibratorId).off();
+ }
+ finishAppOpModeLocked(mCurrentSession.getCallerInfo());
clearCurrentSessionLocked();
// Start next vibration if it's waiting for the HAL session to be over.
maybeStartNextSessionLocked();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
index 17a254ab85e9..ba0262a8bd19 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
@@ -194,12 +194,8 @@ public class WallpaperDataParser {
wallpaper.cropHint.set(0, 0, 0, 0);
wpdData.mPadding.set(0, 0, 0, 0);
wallpaper.name = "";
- if (liveWallpaperContentHandling()) {
- wallpaper.setDescription(new WallpaperDescription.Builder().setComponent(
- mImageWallpaper).build());
- } else {
- wallpaper.setComponent(mImageWallpaper);
- }
+ // TODO (b/379936272) Find a safe value for wallpaper component. mImageComponent
+ // does not work at least on some platforms.
} else {
if (wallpaper.wallpaperId <= 0) {
wallpaper.wallpaperId = makeWallpaperIdLocked();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d019516cd069..0337f5f4f9c8 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1513,11 +1513,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
if (wallpaper.getComponent() != null
&& isPackageModified(wallpaper.getComponent().getPackageName())) {
+ ServiceInfo serviceInfo = null;
try {
- mContext.getPackageManager().getServiceInfo(wallpaper.getComponent(),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- } catch (NameNotFoundException e) {
+ serviceInfo = mIPackageManager.getServiceInfo(
+ wallpaper.getComponent(), PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call IPackageManager.getServiceInfo", e);
+ }
+ if (serviceInfo == null) {
Slog.e(TAG, "Wallpaper component gone, removing: "
+ wallpaper.getComponent());
clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 7cbacd6b0b82..4b7e74af474c 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -22,7 +22,6 @@ import static android.os.Build.IS_USER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -1784,22 +1783,13 @@ final class AccessibilityController {
mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
mDisplayId, visibleWindows);
- if (!com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()) {
- windows = buildWindowInfoListLocked(visibleWindows, screenSize);
- }
-
// Gets the top focused display Id and window token for supporting multi-display.
topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
}
- if (com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()) {
- mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
- topFocusedWindowToken, screenSize, visibleWindows);
- } else {
- mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
- topFocusedWindowToken, windows);
- }
+ mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
+ topFocusedWindowToken, screenSize, visibleWindows);
// Recycle the windows as we do not need them.
for (final AccessibilityWindowsPopulator.AccessibilityWindow window : visibleWindows) {
@@ -1808,166 +1798,6 @@ final class AccessibilityController {
mInitialized = true;
}
- // Here are old code paths, called when computeWindowChangesOnA11yV2 flag is disabled.
- // LINT.IfChange
-
- /**
- * From a list of windows, decides windows to be exposed to accessibility based on touchable
- * region in the screen.
- */
- private List<WindowInfo> buildWindowInfoListLocked(List<AccessibilityWindow> visibleWindows,
- Point screenSize) {
- final List<WindowInfo> windows = new ArrayList<>();
- final Set<IBinder> addedWindows = mTempBinderSet;
- addedWindows.clear();
-
- boolean focusedWindowAdded = false;
-
- final int visibleWindowCount = visibleWindows.size();
-
- Region unaccountedSpace = mTempRegion;
- unaccountedSpace.set(0, 0, screenSize.x, screenSize.y);
-
- // Iterate until we figure out what is touchable for the entire screen.
- for (int i = 0; i < visibleWindowCount; i++) {
- final AccessibilityWindow a11yWindow = visibleWindows.get(i);
- final Region regionInWindow = new Region();
- a11yWindow.getTouchableRegionInWindow(regionInWindow);
- if (windowMattersToAccessibility(a11yWindow, regionInWindow, unaccountedSpace)) {
- addPopulatedWindowInfo(a11yWindow, regionInWindow, windows, addedWindows);
- if (windowMattersToUnaccountedSpaceComputation(a11yWindow)) {
- updateUnaccountedSpace(a11yWindow, unaccountedSpace);
- }
- focusedWindowAdded |= a11yWindow.isFocused();
- } else if (a11yWindow.isUntouchableNavigationBar()) {
- // If this widow is navigation bar without touchable region, accounting the
- // region of navigation bar inset because all touch events from this region
- // would be received by launcher, i.e. this region is a un-touchable one
- // for the application.
- unaccountedSpace.op(
- getSystemBarInsetsFrame(
- mService.mWindowMap.get(a11yWindow.getWindowInfo().token)),
- unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
- }
-
- if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
- break;
- }
- }
-
- // Remove child/parent references to windows that were not added.
- final int windowCount = windows.size();
- for (int i = 0; i < windowCount; i++) {
- WindowInfo window = windows.get(i);
- if (!addedWindows.contains(window.parentToken)) {
- window.parentToken = null;
- }
- if (window.childTokens != null) {
- final int childTokenCount = window.childTokens.size();
- for (int j = childTokenCount - 1; j >= 0; j--) {
- if (!addedWindows.contains(window.childTokens.get(j))) {
- window.childTokens.remove(j);
- }
- }
- // Leave the child token list if empty.
- }
- }
-
- addedWindows.clear();
-
- return windows;
- }
-
- // Some windows should be excluded from unaccounted space computation, though they still
- // should be reported
- private boolean windowMattersToUnaccountedSpaceComputation(AccessibilityWindow a11yWindow) {
- // Do not account space of trusted non-touchable windows, except the split-screen
- // divider.
- // If it's not trusted, touch events are not sent to the windows behind it.
- if (!a11yWindow.isTouchable()
- && (a11yWindow.getType() != TYPE_DOCK_DIVIDER)
- && a11yWindow.isTrustedOverlay()) {
- return false;
- }
-
- if (a11yWindow.getType() == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
- return false;
- }
- return true;
- }
-
- private boolean windowMattersToAccessibility(AccessibilityWindow a11yWindow,
- Region regionInScreen, Region unaccountedSpace) {
- if (a11yWindow.isFocused()) {
- return true;
- }
-
- // Ignore non-touchable windows, except the split-screen divider, which is
- // occasionally non-touchable but still useful for identifying split-screen
- // mode and the PIP menu.
- if (!a11yWindow.isTouchable()
- && (a11yWindow.getType() != TYPE_DOCK_DIVIDER
- && !a11yWindow.isPIPMenu())) {
- return false;
- }
-
- // If the window is completely covered by other windows - ignore.
- if (unaccountedSpace.quickReject(regionInScreen)) {
- return false;
- }
-
- // Add windows of certain types not covered by modal windows.
- if (isReportedWindowType(a11yWindow.getType())) {
- return true;
- }
-
- return false;
- }
-
- private void updateUnaccountedSpace(AccessibilityWindow a11yWindow,
- Region unaccountedSpace) {
- if (a11yWindow.getType()
- != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
- // Account for the space this window takes if the window
- // is not an accessibility overlay which does not change
- // the reported windows.
- final Region touchableRegion = mTempRegion2;
- a11yWindow.getTouchableRegionInScreen(touchableRegion);
- unaccountedSpace.op(touchableRegion, unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
- }
- }
-
- private static void addPopulatedWindowInfo(AccessibilityWindow a11yWindow,
- Region regionInScreen, List<WindowInfo> out, Set<IBinder> tokenOut) {
- final WindowInfo window = a11yWindow.getWindowInfo();
- if (window.token == null) {
- // The window was used in calculating visible windows but does not have an
- // associated IWindow token, so exclude it from the list returned to accessibility.
- return;
- }
- window.regionInScreen.set(regionInScreen);
- window.layer = tokenOut.size();
- out.add(window);
- tokenOut.add(window.token);
- }
-
- private static boolean isReportedWindowType(int windowType) {
- return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
- && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
- && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
- && windowType != WindowManager.LayoutParams.TYPE_DRAG
- && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
- && windowType != WindowManager.LayoutParams.TYPE_POINTER
- && windowType != TYPE_MAGNIFICATION_OVERLAY
- && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
- && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
- && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
- }
-
- // LINT.ThenChange(/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java)
-
private WindowState getTopFocusWindow() {
return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index fd2a909f8b05..7fc11e6c3ac9 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -724,8 +724,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
}
// Compute system bar insets frame if needed.
- if (com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()
- && windowState != null && instance.isUntouchableNavigationBar()) {
+ if (windowState != null && instance.isUntouchableNavigationBar()) {
final InsetsSourceProvider provider =
windowState.getControllableInsetProvider();
if (provider != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1c11c6701643..ae55a1a77873 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -630,8 +630,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// The locusId associated with this activity, if set.
private LocusId mLocusId;
- // Whether the activity is requesting to limit the system's educational dialogs
- public boolean mShouldLimitSystemEducationDialogs;
+ // The timestamp of the last request to show the "Open in browser" education
+ public long mRequestOpenInBrowserEducationTimestamp;
// Whether the activity was launched from a bubble.
private boolean mLaunchedFromBubble;
@@ -1623,6 +1623,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
newParent.setResumedActivity(this, "onParentChanged");
}
mAppCompatController.getTransparentPolicy().start();
+ if (mState == INITIALIZING && isRestrictedFixedOrientation(info.screenOrientation)) {
+ Slog.i(TAG, "Ignoring manifest-declared fixed orientation "
+ + ActivityInfo.screenOrientationToString(info.screenOrientation)
+ + " of " + this + " since target sdk 36");
+ }
}
if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -2538,6 +2543,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
if (!activityAllDrawn && !isActivityHome) {
+ // Only check the special case of a fragment host task because the starting window
+ // may not be visible if the client organizer delays the transition ready.
+ if (task.mTaskFragmentHostProcessName != null) {
+ // It may be launched from a task trampoline that already has a starting window.
+ // Return NONE because 2 consecutive splashes may not look smooth in visual.
+ final Task prevTask = task.getParent().getTaskBelow(task);
+ if (prevTask != null) {
+ final ActivityRecord prevTaskTop = prevTask.getTopMostActivity();
+ if (prevTaskTop != null && prevTaskTop.hasStartingWindow()) {
+ return STARTING_WINDOW_TYPE_NONE;
+ }
+ }
+ }
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
}
}
@@ -3179,6 +3197,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
+ * Returns {@code true} if the orientation will be ignored for {@link #isUniversalResizeable()}.
+ */
+ private boolean isRestrictedFixedOrientation(
+ @ActivityInfo.ScreenOrientation int orientation) {
+ // Exclude "locked" because it is not explicit portrait or landscape.
+ return orientation != ActivityInfo.SCREEN_ORIENTATION_LOCKED
+ && ActivityInfo.isFixedOrientation(orientation)
+ && isUniversalResizeable();
+ }
+
+ /**
* Returns {@code true} if the fixed orientation, aspect ratio, resizability of this activity
* will be ignored.
*/
@@ -4546,10 +4575,22 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// at #postWindowRemoveCleanupLocked
return false;
}
+
+ // Link the fixed rotation transform to this activity since we are transferring the
+ // starting window.
+ if (fromActivity.hasFixedRotationTransform()) {
+ mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
+ false /* checkOpening */);
+ }
// Do not transfer if the orientation doesn't match, redraw starting window while it is
// on top will cause flicker.
- if (fromActivity.getRequestedConfigurationOrientation()
- != getRequestedConfigurationOrientation()) {
+ final int fromOrientation = fromActivity.getConfiguration().orientation;
+ final int requestedOrientation = getRequestedConfigurationOrientation();
+ if (requestedOrientation == ORIENTATION_UNDEFINED) {
+ if (fromOrientation != getConfiguration().orientation) {
+ return false;
+ }
+ } else if (fromOrientation != requestedOrientation) {
return false;
}
// In this case, the starting icon has already been displayed, so start
@@ -4563,13 +4604,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final long origId = Binder.clearCallingIdentity();
try {
- // Link the fixed rotation transform to this activity since we are transferring the
- // starting window.
- if (fromActivity.hasFixedRotationTransform()) {
- mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
- false /* checkOpening */);
- }
-
// Transfer the starting window over to the new token.
mStartingData = fromActivity.mStartingData;
mStartingSurface = fromActivity.mStartingSurface;
@@ -7313,9 +7347,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return mLocusId;
}
- void setLimitSystemEducationDialogs(boolean limitSystemEducationDialogs) {
- if (mShouldLimitSystemEducationDialogs == limitSystemEducationDialogs) return;
- mShouldLimitSystemEducationDialogs = limitSystemEducationDialogs;
+ void requestOpenInBrowserEducation() {
+ mRequestOpenInBrowserEducationTimestamp = System.currentTimeMillis();
final Task task = getTask();
if (task != null) {
final boolean force = isVisibleRequested() && this == task.getTopNonFinishingActivity();
@@ -8110,7 +8143,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Setting requested orientation %s for %s",
ActivityInfo.screenOrientationToString(requestedOrientation), this);
- setOrientation(requestedOrientation, this);
+ final int resolvedOrientation = setOrientation(requestedOrientation, this);
+ if (resolvedOrientation != requestedOrientation
+ && isRestrictedFixedOrientation(requestedOrientation)) {
+ Slog.i(TAG, "Ignoring requested fixed orientation "
+ + ActivityInfo.screenOrientationToString(requestedOrientation)
+ + " of " + this + " since target sdk 36");
+ }
// Push the new configuration to the requested app in case where it's not pushed, e.g. when
// the request is handled at task level with letterbox.
@@ -8201,9 +8240,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@ActivityInfo.ScreenOrientation
protected int getOverrideOrientation() {
int candidateOrientation = super.getOverrideOrientation();
- if (candidateOrientation != ActivityInfo.SCREEN_ORIENTATION_LOCKED
- && ActivityInfo.isFixedOrientation(candidateOrientation)
- && isUniversalResizeable()) {
+ if (isRestrictedFixedOrientation(candidateOrientation)) {
candidateOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
return mAppCompatController.getOrientationPolicy()
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 198e14a16500..8ff08187c698 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3915,12 +3915,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void setLimitSystemEducationDialogs(
- IBinder appToken, boolean limitSystemEducationDialogs) {
+ public void requestOpenInBrowserEducation(IBinder appToken) {
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(appToken);
if (r != null) {
- r.setLimitSystemEducationDialogs(limitSystemEducationDialogs);
+ r.requestOpenInBrowserEducation();
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 4857b02eaf7c..70a8f563275f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -344,6 +344,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
private ActivityRecord mTopResumedActivity;
/**
+ * Cached value of the topmost resumed activity that reported to the client.
+ */
+ private ActivityRecord mLastReportedTopResumedActivity;
+
+ /**
* Flag indicating whether we're currently waiting for the previous top activity to handle the
* loss of the state and report back before making new activity top resumed.
*/
@@ -2287,15 +2292,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
* sent to the new top resumed activity.
*/
ActivityRecord updateTopResumedActivityIfNeeded(String reason) {
- if (!readyToResume()) {
- return mTopResumedActivity;
- }
final ActivityRecord prevTopActivity = mTopResumedActivity;
final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (topRootTask == null || topRootTask.getTopResumedActivity() == prevTopActivity) {
if (topRootTask == null) {
// There's no focused task and there won't have any resumed activity either.
scheduleTopResumedActivityStateLossIfNeeded();
+ mTopResumedActivity = null;
}
if (mService.isSleepingLocked()) {
// There won't be a next resumed activity. The top process should still be updated
@@ -2339,25 +2342,27 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
/** Schedule current top resumed activity state loss */
private void scheduleTopResumedActivityStateLossIfNeeded() {
- if (mTopResumedActivity == null) {
+ if (mLastReportedTopResumedActivity == null) {
return;
}
// mTopResumedActivityWaitingForPrev == true at this point would mean that an activity
// before the prevTopActivity one hasn't reported back yet. So server never sent the top
// resumed state change message to prevTopActivity.
- if (!mTopResumedActivityWaitingForPrev
- && mTopResumedActivity.scheduleTopResumedActivityChanged(false /* onTop */)) {
- scheduleTopResumedStateLossTimeout(mTopResumedActivity);
+ if (!mTopResumedActivityWaitingForPrev && readyToResume()
+ && mLastReportedTopResumedActivity.scheduleTopResumedActivityChanged(
+ false /* onTop */)) {
+ scheduleTopResumedStateLossTimeout(mLastReportedTopResumedActivity);
mTopResumedActivityWaitingForPrev = true;
+ mLastReportedTopResumedActivity = null;
}
- mTopResumedActivity = null;
}
/** Schedule top resumed state change if previous top activity already reported back. */
private void scheduleTopResumedActivityStateIfNeeded() {
- if (mTopResumedActivity != null && !mTopResumedActivityWaitingForPrev) {
+ if (mTopResumedActivity != null && !mTopResumedActivityWaitingForPrev && readyToResume()) {
mTopResumedActivity.scheduleTopResumedActivityChanged(true /* onTop */);
+ mLastReportedTopResumedActivity = mTopResumedActivity;
}
}
@@ -2611,6 +2616,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
*/
void endDeferResume() {
mDeferResumeCount--;
+ if (readyToResume() && mLastReportedTopResumedActivity != null
+ && mTopResumedActivity != mLastReportedTopResumedActivity) {
+ scheduleTopResumedActivityStateLossIfNeeded();
+ }
}
/** @return True if resume can be called. */
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
index fbf9478b4fd9..9754595581a0 100644
--- a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
@@ -16,10 +16,9 @@
package com.android.server.wm;
-import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -33,7 +32,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.AppCompatUtils.isChangeEnabled;
import android.annotation.NonNull;
-import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
import com.android.server.wm.utils.OptPropFactory;
import com.android.window.flags.Flags;
@@ -165,13 +163,13 @@ class AppCompatCameraOverrides {
*
* <p>The treatment is enabled when the following conditions are met:
* <ul>
- * <li>Property gating the camera compatibility free-form treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override.
+ * <li>Feature flag gating the camera compatibility free-form treatment is enabled.
+ * <li>Activity is opted in by the device manufacturer with override.
* </ul>
*/
boolean shouldApplyFreeformTreatmentForCameraCompat() {
- return Flags.enableCameraCompatForDesktopWindowing() && !isChangeEnabled(mActivityRecord,
- OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
+ return Flags.enableCameraCompatForDesktopWindowing() && isChangeEnabled(mActivityRecord,
+ OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT);
}
boolean isOverrideOrientationOnlyForCameraEnabled() {
@@ -202,22 +200,10 @@ class AppCompatCameraOverrides {
&& !mActivityRecord.shouldCreateAppCompatDisplayInsets();
}
- @FreeformCameraCompatMode
- int getFreeformCameraCompatMode() {
- return mAppCompatCameraOverridesState.mFreeformCameraCompatMode;
- }
-
- void setFreeformCameraCompatMode(@FreeformCameraCompatMode int freeformCameraCompatMode) {
- mAppCompatCameraOverridesState.mFreeformCameraCompatMode = freeformCameraCompatMode;
- }
-
static class AppCompatCameraOverridesState {
// Whether activity "refresh" was requested but not finished in
// ActivityRecord#activityResumedLocked following the camera compat force rotation in
// DisplayRotationCompatPolicy.
private boolean mIsRefreshRequested;
-
- @FreeformCameraCompatMode
- private int mFreeformCameraCompatMode = CAMERA_COMPAT_FREEFORM_NONE;
}
}
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index 145a3767c149..203932d4df58 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -76,6 +76,16 @@ class AppCompatController {
mAppCompatSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(mActivityRecord,
mAppCompatOverrides);
mAllowRestrictedResizability = AppCompatUtils.asLazy(() -> {
+ // Application level.
+ try {
+ if (packageManager.getProperty(PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
+ mActivityRecord.packageName).getBoolean()) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // Fall through.
+ }
+ // Activity level.
try {
return packageManager.getPropertyAsUser(
PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index bce8c2be271e..852a0ac054f4 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -1016,7 +1016,8 @@ public class BackgroundActivityStartController {
}
if (state.mCallingUidHasNonAppVisibleWindow) {
return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW,
- /*background*/ false, "callingUid has non-app visible window");
+ /*background*/ false, "callingUid has non-app visible window "
+ + mService.mActiveUids.getNonAppVisibleWindowDetails(state.mCallingUid));
}
// Don't abort if the callerApp or other processes of that uid are considered to be in the
// foreground.
@@ -1142,7 +1143,8 @@ public class BackgroundActivityStartController {
}
if (state.mRealCallingUidHasNonAppVisibleWindow) {
return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW,
- /*background*/ false, "realCallingUid has non-app visible window");
+ /*background*/ false, "realCallingUid has non-app visible window "
+ + mService.mActiveUids.getNonAppVisibleWindowDetails(state.mRealCallingUid));
}
// Don't abort if the realCallerApp or other processes of that uid are considered to be in
@@ -1894,20 +1896,8 @@ public class BackgroundActivityStartController {
(state.mOriginatingPendingIntent != null));
}
- if (finalVerdict.getRawCode() == BAL_ALLOW_GRACE_PERIOD) {
- if (state.realCallerExplicitOptInOrAutoOptIn()
- && state.mResultForRealCaller.allows()
- && state.mResultForRealCaller.getRawCode() != BAL_ALLOW_GRACE_PERIOD) {
- // real caller could allow with a different exemption
- } else if (state.callerExplicitOptInOrAutoOptIn() && state.mResultForCaller.allows()
- && state.mResultForCaller.getRawCode() != BAL_ALLOW_GRACE_PERIOD) {
- // caller could allow with a different exemption
- } else {
- // log to determine grace period length distribution
- Slog.wtf(TAG, "Activity start ONLY allowed by BAL_ALLOW_GRACE_PERIOD "
- + finalVerdict.mMessage + ": " + state);
- }
- }
+ logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_GRACE_PERIOD);
+ logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_NON_APP_VISIBLE_WINDOW);
if (balImprovedMetrics()) {
if (shouldLogStats(finalVerdict, state)) {
@@ -1946,6 +1936,30 @@ public class BackgroundActivityStartController {
return finalVerdict;
}
+ /**
+ * Logs details about the activity starts if the only reason it is allowed is the provided
+ * {@code balCode}.
+ */
+ private static void logIfOnlyAllowedBy(BalVerdict finalVerdict, BalState state, int balCode) {
+ if (finalVerdict.getRawCode() == balCode) {
+ if (state.realCallerExplicitOptInOrAutoOptIn()
+ && state.mResultForRealCaller != null
+ && state.mResultForRealCaller.allows()
+ && state.mResultForRealCaller.getRawCode() != balCode) {
+ // real caller could allow with a different exemption
+ } else if (state.callerExplicitOptInOrAutoOptIn()
+ && state.mResultForCaller != null
+ && state.mResultForCaller.allows()
+ && state.mResultForCaller.getRawCode() != balCode) {
+ // caller could allow with a different exemption
+ } else {
+ // log to determine grace period length distribution
+ Slog.wtf(TAG, "Activity start ONLY allowed by " + balCodeToString(balCode) + " "
+ + finalVerdict.mMessage + ": " + state);
+ }
+ }
+ }
+
@VisibleForTesting
boolean shouldLogStats(BalVerdict finalVerdict, BalState state) {
if (finalVerdict.getRawCode() == BAL_ALLOW_VISIBLE_WINDOW) {
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 2a0252ab06fd..506477f67bfc 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -38,7 +38,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.CameraCompatTaskInfo;
-import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -46,7 +45,6 @@ import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.WmProtoLogGroups;
-import com.android.window.flags.Flags;
/**
* Policy for camera compatibility freeform treatment.
@@ -124,26 +122,6 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa
return appBoundsChanged || displayRotationChanged;
}
- /**
- * Whether activity is eligible for camera compatibility free-form treatment.
- *
- * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
- * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
- * provides changes to the camera and display orientation signals to match those expected on a
- * portrait device in that orientation (for example, on a standard phone).
- *
- * <p>The treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Property gating the camera compatibility free-form treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override.
- * </ul>
- */
- @VisibleForTesting
- boolean isCameraCompatForFreeformEnabledForActivity(@NonNull ActivityRecord activity) {
- return Flags.enableCameraCompatForDesktopWindowing() && !activity.info.isChangeEnabled(
- ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
- }
-
@Override
public void onCameraOpened(@NonNull ActivityRecord cameraActivity,
@NonNull String cameraId) {
@@ -159,16 +137,10 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa
}
cameraActivity.recomputeConfiguration();
- updateCameraCompatMode(cameraActivity);
cameraActivity.getTask().dispatchTaskInfoChangedIfNeeded(/* force= */ true);
cameraActivity.ensureActivityConfiguration(/* ignoreVisibility= */ false);
}
- private void updateCameraCompatMode(@NonNull ActivityRecord cameraActivity) {
- cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
- .setFreeformCameraCompatMode(getCameraCompatMode(cameraActivity));
- }
-
@Override
public boolean onCameraClosed(@NonNull String cameraId) {
// Top activity in the same task as the camera activity, or `null` if the task is
@@ -277,7 +249,8 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa
boolean isTreatmentEnabledForActivity(@NonNull ActivityRecord activity,
boolean checkOrientation) {
int orientation = activity.getRequestedConfigurationOrientation();
- return isCameraCompatForFreeformEnabledForActivity(activity)
+ return activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldApplyFreeformTreatmentForCameraCompat()
&& mCameraStateMonitor.isCameraRunningForActivity(activity)
&& (!checkOrientation || orientation != ORIENTATION_UNDEFINED)
&& activity.inFreeformWindowingMode()
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 0b5872b3e601..93ccd74c6b23 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -32,6 +32,7 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.media.projection.IMediaProjectionManager;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -226,6 +227,7 @@ final class ContentRecorder implements WindowContainerListener {
+ "size %s",
mDisplayContent.getDisplayId(), recordedContentBounds,
recordedContentOrientation, surfaceSize);
+
updateMirroredSurface(mRecordedWindowContainer.getSyncTransaction(),
recordedContentBounds, surfaceSize);
} else {
@@ -295,12 +297,12 @@ final class ContentRecorder implements WindowContainerListener {
* Ensure recording does not fall back to the display stack; ensure the recording is stopped
* and the client notified by tearing down the virtual display.
*/
- private void stopMediaProjection() {
+ private void stopMediaProjection(@StopReason int stopReason) {
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Stop MediaProjection on virtual display %d",
mDisplayContent.getDisplayId());
if (mMediaProjectionManager != null) {
- mMediaProjectionManager.stopActiveProjection();
+ mMediaProjectionManager.stopActiveProjection(stopReason);
}
}
@@ -507,7 +509,7 @@ final class ContentRecorder implements WindowContainerListener {
if (shouldExitTaskRecording) {
// Clean up the cached session first to ensure recording doesn't re-start, since
// tearing down the display will generate display events which will trickle back here.
- stopMediaProjection();
+ stopMediaProjection(StopReason.STOP_ERROR);
}
}
@@ -599,9 +601,13 @@ final class ContentRecorder implements WindowContainerListener {
mLastRecordedBounds = new Rect(recordedContentBounds);
mLastConsumingSurfaceSize.x = surfaceSize.x;
mLastConsumingSurfaceSize.y = surfaceSize.y;
- // Request to notify the client about the resize.
- mMediaProjectionManager.notifyActiveProjectionCapturedContentResized(
- mLastRecordedBounds.width(), mLastRecordedBounds.height());
+
+ // Request to notify the client about the updated bounds.
+ mMediaProjectionManager.notifyCaptureBoundsChanged(
+ mContentRecordingSession.getContentToRecord(),
+ mContentRecordingSession.getTargetUid(),
+ mLastRecordedBounds
+ );
}
/**
@@ -641,7 +647,7 @@ final class ContentRecorder implements WindowContainerListener {
clearContentRecordingSession();
// Clean up the cached session first to ensure recording doesn't re-start, since
// tearing down the display will generate display events which will trickle back here.
- stopMediaProjection();
+ stopMediaProjection(StopReason.STOP_TARGET_REMOVED);
}
// WindowContainerListener
@@ -674,10 +680,10 @@ final class ContentRecorder implements WindowContainerListener {
}
@VisibleForTesting interface MediaProjectionManagerWrapper {
- void stopActiveProjection();
- void notifyActiveProjectionCapturedContentResized(int width, int height);
+ void stopActiveProjection(@StopReason int stopReason);
void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible);
void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode);
+ void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds);
}
private static final class RemoteMediaProjectionManagerWrapper implements
@@ -691,7 +697,7 @@ final class ContentRecorder implements WindowContainerListener {
}
@Override
- public void stopActiveProjection() {
+ public void stopActiveProjection(@StopReason int stopReason) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
@@ -700,7 +706,7 @@ final class ContentRecorder implements WindowContainerListener {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: stopping active projection for display %d",
mDisplayId);
- mIMediaProjectionManager.stopActiveProjection();
+ mIMediaProjectionManager.stopActiveProjection(stopReason);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Unable to tell MediaProjectionManagerService to stop "
@@ -710,52 +716,51 @@ final class ContentRecorder implements WindowContainerListener {
}
@Override
- public void notifyActiveProjectionCapturedContentResized(int width, int height) {
+ public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
}
try {
- mIMediaProjectionManager.notifyActiveProjectionCapturedContentResized(width,
- height);
+ mIMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(
+ isVisible);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Unable to tell MediaProjectionManagerService about "
- + "resizing the active projection: %s",
+ + "visibility change on the active projection: %s",
e);
}
}
@Override
- public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) {
+ public void notifyWindowingModeChanged(int contentToRecord, int targetUid,
+ int windowingMode) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
}
try {
- mIMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(
- isVisible);
+ mIMediaProjectionManager.notifyWindowingModeChanged(
+ contentToRecord, targetUid, windowingMode);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
- "Content Recording: Unable to tell MediaProjectionManagerService about "
- + "visibility change on the active projection: %s",
- e);
+ "Content Recording: Unable to tell log windowing mode change: %s", e);
}
}
@Override
- public void notifyWindowingModeChanged(int contentToRecord, int targetUid,
- int windowingMode) {
+ public void notifyCaptureBoundsChanged(int contentToRecord, int targetUid,
+ Rect captureBounds) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
}
try {
- mIMediaProjectionManager.notifyWindowingModeChanged(
- contentToRecord, targetUid, windowingMode);
+ mIMediaProjectionManager.notifyCaptureBoundsChanged(
+ contentToRecord, targetUid, captureBounds);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
- "Content Recording: Unable to tell log windowing mode change: %s", e);
+ "Content Recording: Unable to tell log bounds change: %s", e);
}
}
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index 6f8c17a9ac75..4e79e377a2a3 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -403,6 +403,7 @@ class DeferredDisplayUpdater {
|| first.renderFrameRate != second.renderFrameRate
|| first.hasArrSupport != second.hasArrSupport
|| !Objects.equals(first.frameRateCategoryRate, second.frameRateCategoryRate)
+ || !Arrays.equals(first.supportedRefreshRates, second.supportedRefreshRates)
|| first.defaultModeId != second.defaultModeId
|| first.userPreferredModeId != second.userPreferredModeId
|| !Arrays.equals(first.supportedModes, second.supportedModes)
diff --git a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
index c8cb62132b4c..43855aa3d247 100644
--- a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
+++ b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
@@ -196,10 +196,11 @@ public class DesktopAppCompatAspectRatioPolicy {
if (!aspectRatioOverrides.shouldOverrideMinAspectRatio()
&& !AppCompatCameraPolicy.shouldOverrideMinAspectRatioForCamera(mActivityRecord)) {
- if (mActivityRecord.isUniversalResizeable()) {
+ final float minAspectRatio = info.getMinAspectRatio();
+ if (minAspectRatio == 0 || mActivityRecord.isUniversalResizeable()) {
return 0;
}
- return info.getMinAspectRatio();
+ return minAspectRatio;
}
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
@@ -242,10 +243,11 @@ public class DesktopAppCompatAspectRatioPolicy {
if (mTransparentPolicy.isRunning()) {
return mTransparentPolicy.getInheritedMaxAspectRatio();
}
- if (mActivityRecord.isUniversalResizeable()) {
+ final float maxAspectRatio = mActivityRecord.info.getMaxAspectRatio();
+ if (maxAspectRatio == 0 || mActivityRecord.isUniversalResizeable()) {
return 0;
}
- return mActivityRecord.info.getMaxAspectRatio();
+ return maxAspectRatio;
}
/**
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 9f40bed3fcc8..25fdf89afad1 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -17,8 +17,6 @@
package com.android.server.wm;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_DIMMER;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -44,7 +42,8 @@ class Dimmer {
*/
private final WindowContainer<?> mHost;
- private static final String TAG = TAG_WITH_CLASS_NAME ? "Dimmer" : TAG_WM;
+ private static final String TAG = "WindowManagerDimmer";
+
DimState mDimState;
final DimmerAnimationHelper.AnimationAdapterFactory mAnimationAdapterFactory;
@@ -69,9 +68,10 @@ class Dimmer {
DimState() {
mHostContainer = mHost;
- mAnimationHelper = new DimmerAnimationHelper(mAnimationAdapterFactory);
+ mAnimationHelper = new DimmerAnimationHelper(mHost, mAnimationAdapterFactory);
try {
mDimSurface = makeDimLayer();
+ EventLogTags.writeWmDimCreated(mHost.getName(), mDimSurface.getLayerId());
} catch (Surface.OutOfResourcesException e) {
Log.w(TAG, "OutOfResourcesException creating dim surface");
}
@@ -102,6 +102,11 @@ class Dimmer {
* Prepare the dim for the exit animation
*/
void exit(@NonNull SurfaceControl.Transaction t) {
+ EventLogTags.writeWmDimExit(mDimState.mDimSurface.getLayerId(),
+ mDimState.mLastDimmingWindow != null
+ ? mDimState.mLastDimmingWindow.getName() : "-",
+ mDimState.mHostContainer.isVisible() ? 1 : 0,
+ mAnimateExit ? 0 : 1);
if (!mAnimateExit) {
remove(t);
} else {
@@ -111,8 +116,10 @@ class Dimmer {
}
void remove(@NonNull SurfaceControl.Transaction t) {
+ EventLogTags.writeWmDimCancelAnim(mDimSurface.getLayerId(), "ready to remove");
mAnimationHelper.stopCurrentAnimation(mDimSurface);
if (mDimSurface.isValid()) {
+ EventLogTags.writeWmDimRemoved(mDimSurface.getLayerId());
t.remove(mDimSurface);
ProtoLog.d(WM_DEBUG_DIMMER,
"Removing dim surface %s on transaction %s", this, t);
@@ -126,6 +133,13 @@ class Dimmer {
return "Dimmer#DimState with host=" + mHostContainer + ", surface=" + mDimSurface;
}
+
+ String reasonForRemoving() {
+ return mLastDimmingWindow != null ? mLastDimmingWindow
+ + " is dimming but host " + mHostContainer + " is not visibleRequested"
+ : " no one is dimming";
+ }
+
/**
* Set the parameters to prepare the dim to be relative parented to the dimming container
*/
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index 0d0e5483fc0e..1d447dd692df 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -76,9 +76,11 @@ public class DimmerAnimationHelper {
return mDimmingContainer != null && mDimmingContainer == other.mDimmingContainer;
}
- void inheritPropertiesFromAnimation(@NonNull AnimationSpec anim) {
- mAlpha = anim.mCurrentAlpha;
- mBlurRadius = anim.mCurrentBlur;
+ void inheritPropertiesFromAnimation(@Nullable AnimationSpec anim) {
+ if (anim != null) {
+ mAlpha = anim.mCurrentAlpha;
+ mBlurRadius = anim.mCurrentBlur;
+ }
}
@Override
@@ -92,11 +94,13 @@ public class DimmerAnimationHelper {
private final Change mRequestedProperties = new Change();
private AnimationSpec mAlphaAnimationSpec;
+ private final SurfaceAnimationRunner mSurfaceAnimationRunner;
private final AnimationAdapterFactory mAnimationAdapterFactory;
private AnimationAdapter mLocalAnimationAdapter;
- DimmerAnimationHelper(AnimationAdapterFactory animationFactory) {
+ DimmerAnimationHelper(WindowContainer<?> host, AnimationAdapterFactory animationFactory) {
mAnimationAdapterFactory = animationFactory;
+ mSurfaceAnimationRunner = host.mWmService.mSurfaceAnimationRunner;
}
void setExitParameters() {
@@ -160,6 +164,7 @@ public class DimmerAnimationHelper {
}
if (!startProperties.hasSameVisualProperties(mRequestedProperties)) {
+ EventLogTags.writeWmDimCancelAnim(dim.mDimSurface.getLayerId(), "new target values");
stopCurrentAnimation(dim.mDimSurface);
if (dim.mSkipAnimation
@@ -189,13 +194,15 @@ public class DimmerAnimationHelper {
ProtoLog.v(WM_DEBUG_DIMMER, "Starting animation on %s", dim);
mAlphaAnimationSpec = getRequestedAnimationSpec(from, to);
mLocalAnimationAdapter = mAnimationAdapterFactory.get(mAlphaAnimationSpec,
- dim.mHostContainer.mWmService.mSurfaceAnimationRunner);
+ mSurfaceAnimationRunner);
float targetAlpha = to.mAlpha;
+ EventLogTags.writeWmDimAnimate(dim.mDimSurface.getLayerId(), targetAlpha, to.mBlurRadius);
mLocalAnimationAdapter.startAnimation(dim.mDimSurface, t,
ANIMATION_TYPE_DIMMER, /* finishCallback */ (type, animator) -> {
synchronized (dim.mHostContainer.mWmService.mGlobalLock) {
+ EventLogTags.writeWmDimFinishAnim(dim.mDimSurface.getLayerId());
SurfaceControl.Transaction finishTransaction =
dim.mHostContainer.getSyncTransaction();
setCurrentAlphaBlur(dim, finishTransaction);
@@ -208,18 +215,12 @@ public class DimmerAnimationHelper {
});
}
- private boolean isAnimating() {
- return mAlphaAnimationSpec != null;
- }
-
void stopCurrentAnimation(@NonNull SurfaceControl surface) {
- if (mLocalAnimationAdapter != null && isAnimating()) {
- // Save the current animation progress and cancel the animation
- mCurrentProperties.inheritPropertiesFromAnimation(mAlphaAnimationSpec);
- mLocalAnimationAdapter.onAnimationCancelled(surface);
- mLocalAnimationAdapter = null;
- mAlphaAnimationSpec = null;
- }
+ // (If animating) save the current animation progress and cancel the animation
+ mCurrentProperties.inheritPropertiesFromAnimation(mAlphaAnimationSpec);
+ mSurfaceAnimationRunner.onAnimationCancelled(surface);
+ mLocalAnimationAdapter = null;
+ mAlphaAnimationSpec = null;
}
@NonNull
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 3b2479885f57..f40d636b522a 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -101,8 +101,6 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
DisplayArea(WindowManagerService wms, Type type, String name, int featureId) {
super(wms);
- // TODO(display-area): move this up to ConfigurationContainer
- setOverrideOrientation(SCREEN_ORIENTATION_UNSET);
mType = type;
mName = name;
mFeatureId = featureId;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e9e550e72a00..9a33df13bb6a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5502,14 +5502,18 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Attach the SystemUiContext to this DisplayContent the get latest configuration.
// Note that the SystemUiContext will be removed automatically if this DisplayContent
// is detached.
- final WindowProcessController wpc = mAtmService.getProcessController(
- getDisplayUiContext().getIApplicationThread());
- mWmService.mWindowContextListenerController.registerWindowContainerListener(
- wpc, getDisplayUiContext().getWindowContextToken(), this,
- INVALID_WINDOW_TYPE, null /* options */);
+ registerSystemUiContext();
}
}
+ private void registerSystemUiContext() {
+ final WindowProcessController wpc = mAtmService.getProcessController(
+ getDisplayUiContext().getIApplicationThread());
+ mWmService.mWindowContextListenerController.registerWindowContainerListener(
+ wpc, getDisplayUiContext().getWindowContextToken(), this,
+ INVALID_WINDOW_TYPE, null /* options */);
+ }
+
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
assignRelativeLayerForIme(t, false /* forceUpdate */);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 4cf1fb400fe7..df209ff4cf50 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -485,6 +485,9 @@ public class DisplayRotation {
if (isDefaultDisplay) {
updateOrientationListenerLw();
}
+ } else if (mCompatPolicyForImmersiveApps != null
+ && mCompatPolicyForImmersiveApps.deferOrientationUpdate()) {
+ return false;
}
return updateRotationUnchecked(forceUpdate);
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
index 094434d07cfe..046ed614dc19 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
@@ -17,10 +17,13 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Configuration.Orientation;
@@ -66,6 +69,37 @@ final class DisplayRotationImmersiveAppCompatPolicy {
}
/**
+ * Returns {@code true} if the orientation update should be skipped and it will update when
+ * transition is done. This is to keep the orientation which was preserved by
+ * {@link #isRotationLockEnforced} from being changed by a transient launch (i.e. recents).
+ */
+ boolean deferOrientationUpdate() {
+ if (mDisplayRotation.getUserRotation() != USER_ROTATION_FREE
+ || mDisplayRotation.getLastOrientation() != SCREEN_ORIENTATION_UNSPECIFIED) {
+ return false;
+ }
+ final WindowOrientationListener orientationListener =
+ mDisplayRotation.getOrientationListener();
+ if (orientationListener == null
+ || orientationListener.getProposedRotation() == mDisplayRotation.getRotation()) {
+ return false;
+ }
+ // The above conditions mean that isRotationLockEnforced might have taken effect:
+ // Auto-rotation is enabled and the proposed rotation is not applied.
+ // Then the update should defer until the transition idle to avoid disturbing animation.
+ if (!mDisplayContent.mTransitionController.hasTransientLaunch(mDisplayContent)) {
+ return false;
+ }
+ mDisplayContent.mTransitionController.mStateValidators.add(() -> {
+ if (!isRotationLockEnforcedLocked(orientationListener.getProposedRotation())) {
+ mDisplayContent.mWmService.updateRotation(false /* alwaysSendConfiguration */,
+ false /* forceRelayout */);
+ }
+ });
+ return true;
+ }
+
+ /**
* Decides whether it is necessary to lock screen rotation, preventing auto rotation, based on
* the top activity configuration and proposed screen rotation.
*
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
index cc2249de010c..9d6688648021 100644
--- a/services/core/java/com/android/server/wm/EventLogTags.logtags
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -87,3 +87,16 @@ option java_package com.android.server.wm
# Entering pip called
38000 wm_enter_pip (User|1|5),(Token|1|5),(Component Name|3),(is Auto Enter|3)
+
+# Dim layer is created
+38200 wm_dim_created (Host|3),(Surface|1)
+# Dimmer is ready for removal
+38201 wm_dim_exit (Surface|1),(dimmingWindow|3),(hostIsVisible|1),(removeImmediately|1)
+# Dimmer is starting an animation
+38202 wm_dim_animate (Surface|1, (toAlpha|5), (toBlur|5))
+# Dimmer animation is cancelled
+38203 wm_dim_cancel_anim (Surface|1),(reason|3)
+# Dimmer animation is finished
+38204 wm_dim_finish_anim (Surface|1)
+# Dimmer removing surface
+38205 wm_dim_removed (Surface|1) \ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 4b2d45430bb4..cf145f94f787 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -228,13 +228,11 @@ class InsetsStateController {
changed |= provider.updateClientVisibility(caller,
isImeProvider ? statsToken : null);
}
- if (!android.view.inputmethod.Flags.refactorInsetsController()) {
- if (changed) {
- notifyInsetsChanged();
- mDisplayContent.updateSystemGestureExclusion();
+ if (changed) {
+ notifyInsetsChanged();
+ mDisplayContent.updateSystemGestureExclusion();
- mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
- }
+ mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
}
}
diff --git a/services/core/java/com/android/server/wm/MirrorActiveUids.java b/services/core/java/com/android/server/wm/MirrorActiveUids.java
index b9aa9599babe..b7bf16257f24 100644
--- a/services/core/java/com/android/server/wm/MirrorActiveUids.java
+++ b/services/core/java/com/android/server/wm/MirrorActiveUids.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import android.app.ActivityManager.ProcessState;
+import android.util.SparseArray;
import android.util.SparseIntArray;
import java.io.PrintWriter;
@@ -34,6 +35,8 @@ class MirrorActiveUids {
/** Uid -> number of non-app visible windows belong to the uid. */
private final SparseIntArray mNumNonAppVisibleWindowMap = new SparseIntArray();
+ /** Type -> Uid -> number of non-app visible windows for type/uid. */
+ private final SparseArray<SparseIntArray> mNumNonAppVisibleWindowMapByType = new SparseArray();
synchronized void onUidActive(int uid, int procState) {
mUidStates.put(uid, procState);
@@ -55,17 +58,31 @@ class MirrorActiveUids {
}
/** Called when the surface of non-application (exclude toast) window is shown or hidden. */
- synchronized void onNonAppSurfaceVisibilityChanged(int uid, boolean visible) {
- final int index = mNumNonAppVisibleWindowMap.indexOfKey(uid);
+ synchronized void onNonAppSurfaceVisibilityChanged(int uid, int type, boolean visible) {
+ updateCount(uid, visible, mNumNonAppVisibleWindowMap);
+ updateCount(uid, visible, getNumNonAppVisibleWindowMapByType(type));
+ }
+
+ private SparseIntArray getNumNonAppVisibleWindowMapByType(int type) {
+ SparseIntArray result = mNumNonAppVisibleWindowMapByType.get(type);
+ if (result == null) {
+ result = new SparseIntArray();
+ mNumNonAppVisibleWindowMapByType.append(type, result);
+ }
+ return result;
+ }
+
+ private void updateCount(int uid, boolean visible, SparseIntArray numNonAppVisibleWindowMap) {
+ final int index = numNonAppVisibleWindowMap.indexOfKey(uid);
if (index >= 0) {
- final int num = mNumNonAppVisibleWindowMap.valueAt(index) + (visible ? 1 : -1);
+ final int num = numNonAppVisibleWindowMap.valueAt(index) + (visible ? 1 : -1);
if (num > 0) {
- mNumNonAppVisibleWindowMap.setValueAt(index, num);
+ numNonAppVisibleWindowMap.setValueAt(index, num);
} else {
- mNumNonAppVisibleWindowMap.removeAt(index);
+ numNonAppVisibleWindowMap.removeAt(index);
}
} else if (visible) {
- mNumNonAppVisibleWindowMap.append(uid, 1);
+ numNonAppVisibleWindowMap.append(uid, 1);
}
}
@@ -78,6 +95,24 @@ class MirrorActiveUids {
return mNumNonAppVisibleWindowMap.get(uid) > 0;
}
+ /**
+ * Returns details about the windows that contribute to the result of
+ * {@link #hasNonAppVisibleWindow(int)}.
+ *
+ * @return a map of window type to count
+ */
+ synchronized SparseIntArray getNonAppVisibleWindowDetails(int uid) {
+ SparseIntArray result = new SparseIntArray();
+ for (int i = 0; i < mNumNonAppVisibleWindowMapByType.size(); i++) {
+ SparseIntArray numNonAppVisibleWindowMap = mNumNonAppVisibleWindowMapByType.valueAt(i);
+ int count = numNonAppVisibleWindowMap.get(uid);
+ if (count > 0) {
+ result.append(mNumNonAppVisibleWindowMapByType.keyAt(i), count);
+ }
+ }
+ return result;
+ }
+
synchronized void dump(PrintWriter pw, String prefix) {
pw.print(prefix + "NumNonAppVisibleWindowUidMap:[");
for (int i = mNumNonAppVisibleWindowMap.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 9de96f1440a2..27f82d90fdac 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -326,9 +326,12 @@ class RecentTasks {
ProtoLog.i(WM_DEBUG_TASKS, "Setting frozen recents task list");
// Always update the reordering time when this is called to ensure that the timeout
- // is reset
+ // is reset. Extend this duration when running in tests.
+ final long timeout = ActivityManager.isRunningInUserTestHarness()
+ ? mFreezeTaskListTimeoutMs * 10
+ : mFreezeTaskListTimeoutMs;
mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable);
- mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, mFreezeTaskListTimeoutMs);
+ mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, timeout);
}
/**
@@ -492,11 +495,18 @@ class RecentTasks {
mTaskNotificationController.notifyTaskListUpdated();
}
- private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
+ private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess,
+ boolean removedForAddTask) {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
}
mTaskNotificationController.notifyTaskListUpdated();
+ if (removedForAddTask) {
+ mTaskNotificationController.notifyRecentTaskRemovedForAddTask(task.mTaskId);
+ }
+ }
+ private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
+ notifyTaskRemoved(task, wasTrimmed, killProcess, false /* removedForAddTask */);
}
/**
@@ -1632,7 +1642,8 @@ class RecentTasks {
// from becoming dangling.
mHiddenTasks.add(0, removedTask);
}
- notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
+ notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */,
+ true /* removedForAddTask */);
if (DEBUG_RECENTS_TRIM_TASKS) {
Slog.d(TAG, "Trimming task=" + removedTask
+ " for addition of task=" + task);
@@ -2022,22 +2033,9 @@ class RecentTasks {
// Fill in some deprecated values.
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
- rti.lastSnapshotData.set(tr.mLastTaskSnapshotData);
if (!getTasksAllowed) {
Task.trimIneffectiveInfo(tr, rti);
}
-
- // Fill in organized child task info for the task created by organizer.
- if (tr.mCreatedByOrganizer) {
- for (int i = tr.getChildCount() - 1; i >= 0; i--) {
- final Task childTask = tr.getChildAt(i).asTask();
- if (childTask != null && childTask.isOrganized()) {
- final ActivityManager.RecentTaskInfo cti = new ActivityManager.RecentTaskInfo();
- childTask.fillTaskInfo(cti, true /* stripExtras */, tda);
- rti.childrenTaskInfos.add(cti);
- }
- }
- }
return rti;
}
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index e4c34ed52359..5ce8a32aa141 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -234,6 +234,12 @@ class RefreshRatePolicy {
return w.mFrameRateVote.reset();
}
+ // If insets animation is running, do not convey the preferred app refresh rate to let VRI
+ // to control the refresh rate.
+ if (w.isInsetsAnimationRunning()) {
+ return w.mFrameRateVote.reset();
+ }
+
// If the app set a preferredDisplayModeId, the preferred refresh rate is the refresh rate
// of that mode id.
if (refreshRateSwitchingType != SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY) {
@@ -272,7 +278,7 @@ class RefreshRatePolicy {
float getPreferredMinRefreshRate(WindowState w) {
// If app is animating, it's not able to control refresh rate because we want the animation
// to run in default refresh rate.
- if (w.isAnimationRunningSelfOrParent()) {
+ if (w.isAnimationRunningSelfOrParent() || w.isInsetsAnimationRunning()) {
return 0;
}
@@ -295,7 +301,7 @@ class RefreshRatePolicy {
float getPreferredMaxRefreshRate(WindowState w) {
// If app is animating, it's not able to control refresh rate because we want the animation
// to run in default refresh rate.
- if (w.isAnimationRunningSelfOrParent()) {
+ if (w.isAnimationRunningSelfOrParent() || w.isInsetsAnimationRunning()) {
return 0;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6707a27d83c8..c89feb41e723 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -108,6 +108,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayBrightnessOverrideRequest;
import android.hardware.power.Mode;
import android.net.Uri;
import android.os.Binder;
@@ -185,8 +186,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private static final long SLEEP_TRANSITION_WAIT_MILLIS = 1000L;
private Object mLastWindowFreezeSource = null;
- private float mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- private CharSequence mScreenBrightnessOverrideTag;
+ // Per-display WindowManager overrides that are passed on.
+ private final SparseArray<DisplayBrightnessOverrideRequest> mDisplayBrightnessOverrides =
+ new SparseArray<>();
private long mUserActivityTimeout = -1;
private boolean mUpdateRotation = false;
// Only set while traversing the default display based on its content.
@@ -775,8 +777,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
}
- mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- mScreenBrightnessOverrideTag = null;
+ mDisplayBrightnessOverrides.clear();
mUserActivityTimeout = -1;
mObscureApplicationContentOnSecondaryDisplays = false;
mSustainedPerformanceModeCurrent = false;
@@ -879,18 +880,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
if (!mWmService.mDisplayFrozen) {
- final float brightnessOverride = mScreenBrightnessOverride < PowerManager.BRIGHTNESS_MIN
- || mScreenBrightnessOverride > PowerManager.BRIGHTNESS_MAX
- ? PowerManager.BRIGHTNESS_INVALID_FLOAT : mScreenBrightnessOverride;
- CharSequence overrideTag = null;
- if (brightnessOverride != PowerManager.BRIGHTNESS_INVALID_FLOAT) {
- overrideTag = mScreenBrightnessOverrideTag;
- }
- int brightnessFloatAsIntBits = Float.floatToIntBits(brightnessOverride);
// Post these on a handler such that we don't call into power manager service while
// holding the window manager lock to avoid lock contention with power manager lock.
- mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightnessFloatAsIntBits,
- 0, overrideTag).sendToTarget();
+ mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, mDisplayBrightnessOverrides)
+ .sendToTarget();
mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
}
@@ -1043,10 +1036,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
if (w.isDrawn() || (w.mActivityRecord != null && w.mActivityRecord.firstWindowDrawn
&& w.mActivityRecord.isVisibleRequested())) {
- if (!syswin && w.mAttrs.screenBrightness >= 0
- && Float.isNaN(mScreenBrightnessOverride)) {
- mScreenBrightnessOverride = w.mAttrs.screenBrightness;
- mScreenBrightnessOverrideTag = w.getWindowTag();
+ if (!syswin && w.mAttrs.screenBrightness >= PowerManager.BRIGHTNESS_MIN
+ && w.mAttrs.screenBrightness <= PowerManager.BRIGHTNESS_MAX
+ && !mDisplayBrightnessOverrides.contains(w.getDisplayId())) {
+ var brightnessOverride = new DisplayBrightnessOverrideRequest();
+ brightnessOverride.brightness = w.mAttrs.screenBrightness;
+ brightnessOverride.tag = w.getWindowTag();
+ mDisplayBrightnessOverrides.put(w.getDisplayId(), brightnessOverride);
}
// This function assumes that the contents of the default display are processed first
@@ -1118,8 +1114,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
public void handleMessage(Message msg) {
switch (msg.what) {
case SET_SCREEN_BRIGHTNESS_OVERRIDE:
- mWmService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
- Float.intBitsToFloat(msg.arg1), (CharSequence) msg.obj);
+ var brightnessOverrides =
+ (SparseArray<DisplayBrightnessOverrideRequest>) msg.obj;
+ mWmService.mDisplayManagerInternal.setScreenBrightnessOverrideFromWindowManager(
+ brightnessOverrides);
break;
case SET_USER_ACTIVITY_TIMEOUT:
mWmService.mPowerManagerInternal.
@@ -2856,7 +2854,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void prepareForShutdown() {
for (int i = 0; i < getChildCount(); i++) {
- createSleepToken("shutdown", getChildAt(i).mDisplayId);
+ final int displayId = getChildAt(i).mDisplayId;
+ mWindowManager.mSnapshotController.mTaskSnapshotController
+ .snapshotForShutdown(displayId);
+ createSleepToken("shutdown", displayId);
}
}
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 70b214cc71b5..88e534351e2e 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -361,10 +361,13 @@ public class SafeActivityOptions {
}
// If launched from bubble is specified, then ensure that the caller is system or sysui.
- if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) {
+ if ((options.getLaunchedFromBubble() || options.getTaskAlwaysOnTop())
+ && !isSystemOrSystemUI(callingPid, callingUid)) {
final String msg = "Permission Denial: starting " + getIntentString(intent)
+ " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ") with launchedFromBubble=true";
+ + ", uid=" + callingUid + ") with"
+ + (options.getLaunchedFromBubble() ? " launchedFromBubble=true" : "")
+ + (options.getTaskAlwaysOnTop() ? " taskAlwaysOnTop=true" : "");
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1bb4c41e79e0..07de489d9ff4 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -706,6 +706,10 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
win.setRequestedVisibleTypes(requestedVisibleTypes);
win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win,
imeStatsToken);
+ final Task task = win.getTask();
+ if (task != null) {
+ task.dispatchTaskInfoChangedIfNeeded(/* forced= */ true);
+ }
} else {
EmbeddedWindowController.EmbeddedWindow embeddedWindow = null;
if (android.view.inputmethod.Flags.refactorInsetsController()) {
@@ -1008,4 +1012,15 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
}
}
+
+ @Override
+ public void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running) {
+ synchronized (mService.mGlobalLock) {
+ final WindowState win = mService.windowForClientLocked(this, window,
+ false /* throwOnError */);
+ if (win != null) {
+ win.notifyInsetsAnimationRunningStateChanged(running);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index 1c8c245f7640..bd8e8f4008de 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -64,6 +64,7 @@ class SnapshotPersistQueue {
private boolean mStarted;
private final Object mLock = new Object();
private final UserManagerInternal mUserManagerInternal;
+ private boolean mShutdown;
SnapshotPersistQueue() {
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -101,6 +102,16 @@ class SnapshotPersistQueue {
}
}
+ /**
+ * Write out everything in the queue because of shutdown.
+ */
+ void shutdown() {
+ synchronized (mLock) {
+ mShutdown = true;
+ mLock.notifyAll();
+ }
+ }
+
@VisibleForTesting
void waitForQueueEmpty() {
while (true) {
@@ -193,7 +204,9 @@ class SnapshotPersistQueue {
if (isReadyToWrite) {
next.write();
}
- SystemClock.sleep(DELAY_MS);
+ if (!mShutdown) {
+ SystemClock.sleep(DELAY_MS);
+ }
}
synchronized (mLock) {
final boolean writeQueueEmpty = mWriteQueue.isEmpty();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 352dc528f815..87e472ab7aa6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -128,7 +128,6 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -256,9 +255,6 @@ class Task extends TaskFragment {
private static final String ATTR_MIN_HEIGHT = "min_height";
private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
- private static final String ATTR_LAST_SNAPSHOT_TASK_SIZE = "last_snapshot_task_size";
- private static final String ATTR_LAST_SNAPSHOT_CONTENT_INSETS = "last_snapshot_content_insets";
- private static final String ATTR_LAST_SNAPSHOT_BUFFER_SIZE = "last_snapshot_buffer_size";
// How long to wait for all background Activities to redraw following a call to
// convertToTranslucent().
@@ -472,10 +468,6 @@ class Task extends TaskFragment {
// NOTE: This value needs to be persisted with each task
private TaskDescription mTaskDescription;
- // Information about the last snapshot that should be persisted with the task to allow SystemUI
- // to layout without loading all the task snapshots
- final PersistedTaskSnapshotData mLastTaskSnapshotData;
-
/** @see #setCanAffectSystemUiFlags */
private boolean mCanAffectSystemUiFlags = true;
@@ -635,14 +627,13 @@ class Task extends TaskFragment {
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
boolean _autoRemoveRecents, int _userId, int _effectiveUid,
String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity,
- TaskDescription _lastTaskDescription, PersistedTaskSnapshotData _lastSnapshotData,
- int taskAffiliation, int prevTaskId, int nextTaskId, int callingUid,
- String callingPackage, @Nullable String callingFeatureId, int resizeMode,
- boolean supportsPictureInPicture, boolean _realActivitySuspended,
- boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
- IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
- boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
- boolean _removeWithTaskOrganizer) {
+ TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
+ int nextTaskId, int callingUid, String callingPackage,
+ @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture,
+ boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
+ ActivityInfo info, IVoiceInteractionSession _voiceSession,
+ IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer, IBinder _launchCookie,
+ boolean _deferTaskAppear, boolean _removeWithTaskOrganizer) {
super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */);
mTaskId = _taskId;
@@ -652,9 +643,6 @@ class Task extends TaskFragment {
mTaskDescription = _lastTaskDescription != null
? _lastTaskDescription
: new TaskDescription();
- mLastTaskSnapshotData = _lastSnapshotData != null
- ? _lastSnapshotData
- : new PersistedTaskSnapshotData();
affinityIntent = _affinityIntent;
affinity = _affinity;
rootAffinity = _rootAffinity;
@@ -1212,20 +1200,23 @@ class Task extends TaskFragment {
@Override
void onResize() {
super.onResize();
- updateTaskLayerForFreeform();
+ onTaskBoundsChangedForFreeform();
}
@Override
void onMovedByResize() {
super.onMovedByResize();
- updateTaskLayerForFreeform();
+ onTaskBoundsChangedForFreeform();
}
- private void updateTaskLayerForFreeform() {
- if (!com.android.window.flags.Flags.processPriorityPolicyForMultiWindowMode()) {
+ private void onTaskBoundsChangedForFreeform() {
+ if (!isVisibleRequested() || !inFreeformWindowingMode()) {
return;
}
- if (!isVisibleRequested() || !inFreeformWindowingMode()) {
+
+ mAtmService.notifyTaskPersisterLocked(this, false /* flush */);
+
+ if (!com.android.window.flags.Flags.processPriorityPolicyForMultiWindowMode()) {
return;
}
mRootWindowContainer.invalidateTaskLayersAndUpdateOomAdjIfNeeded();
@@ -3111,7 +3102,6 @@ class Task extends TaskFragment {
}
void onSnapshotChanged(TaskSnapshot snapshot) {
- mLastTaskSnapshotData.set(snapshot);
mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
mTaskId, snapshot);
}
@@ -3423,8 +3413,8 @@ class Task extends TaskFragment {
? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID;
info.shouldDockBigOverlays = top != null && top.shouldDockBigOverlays;
info.mTopActivityLocusId = top != null ? top.getLocusId() : null;
- info.isTopActivityLimitSystemEducationDialogs = top != null
- ? top.mShouldLimitSystemEducationDialogs : false;
+ info.topActivityRequestOpenInBrowserEducationTimestamp = top != null
+ ? top.mRequestOpenInBrowserEducationTimestamp : 0;
final Task parentTask = getParent() != null ? getParent().asTask() : null;
info.parentTaskId = parentTask != null && parentTask.mCreatedByOrganizer
? parentTask.mTaskId
@@ -3436,7 +3426,8 @@ class Task extends TaskFragment {
info.isSleeping = shouldSleepActivities();
info.isTopActivityTransparent = top != null && !top.fillsParent();
info.lastNonFullscreenBounds = topTask.mLastNonFullscreenBounds;
- final WindowState windowState = top != null ? top.findMainWindow() : null;
+ final WindowState windowState = top != null
+ ? top.findMainWindow(/* includeStartingApp= */ false) : null;
info.requestedVisibleTypes = (windowState != null && Flags.enableFullyImmersiveInDesktop())
? windowState.getRequestedVisibleTypes() : WindowInsets.Type.defaultVisible();
AppCompatUtils.fillAppCompatTaskInfo(this, info, top);
@@ -3522,6 +3513,7 @@ class Task extends TaskFragment {
info.capturedLink = null;
info.capturedLinkTimestamp = 0;
+ info.topActivityRequestOpenInBrowserEducationTimestamp = 0;
}
@Nullable PictureInPictureParams getPictureInPictureParams() {
@@ -3988,19 +3980,6 @@ class Task extends TaskFragment {
out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight);
out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION);
- if (mLastTaskSnapshotData.taskSize != null) {
- out.attribute(null, ATTR_LAST_SNAPSHOT_TASK_SIZE,
- mLastTaskSnapshotData.taskSize.flattenToString());
- }
- if (mLastTaskSnapshotData.contentInsets != null) {
- out.attribute(null, ATTR_LAST_SNAPSHOT_CONTENT_INSETS,
- mLastTaskSnapshotData.contentInsets.flattenToString());
- }
- if (mLastTaskSnapshotData.bufferSize != null) {
- out.attribute(null, ATTR_LAST_SNAPSHOT_BUFFER_SIZE,
- mLastTaskSnapshotData.bufferSize.flattenToString());
- }
-
if (affinityIntent != null) {
out.startTag(null, TAG_AFFINITYINTENT);
affinityIntent.saveToXml(out);
@@ -4067,7 +4046,6 @@ class Task extends TaskFragment {
int taskId = INVALID_TASK_ID;
final int outerDepth = in.getDepth();
TaskDescription taskDescription = new TaskDescription();
- PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
int taskAffiliation = INVALID_TASK_ID;
int prevTaskId = INVALID_TASK_ID;
int nextTaskId = INVALID_TASK_ID;
@@ -4174,15 +4152,6 @@ class Task extends TaskFragment {
case ATTR_PERSIST_TASK_VERSION:
persistTaskVersion = Integer.parseInt(attrValue);
break;
- case ATTR_LAST_SNAPSHOT_TASK_SIZE:
- lastSnapshotData.taskSize = Point.unflattenFromString(attrValue);
- break;
- case ATTR_LAST_SNAPSHOT_CONTENT_INSETS:
- lastSnapshotData.contentInsets = Rect.unflattenFromString(attrValue);
- break;
- case ATTR_LAST_SNAPSHOT_BUFFER_SIZE:
- lastSnapshotData.bufferSize = Point.unflattenFromString(attrValue);
- break;
default:
if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
Slog.w(TAG, "Task: Unknown attribute=" + attrName);
@@ -4276,7 +4245,6 @@ class Task extends TaskFragment {
.setLastTimeMoved(lastTimeOnTop)
.setNeverRelinquishIdentity(neverRelinquishIdentity)
.setLastTaskDescription(taskDescription)
- .setLastSnapshotData(lastSnapshotData)
.setTaskAffiliation(taskAffiliation)
.setPrevAffiliateTaskId(prevTaskId)
.setNextAffiliateTaskId(nextTaskId)
@@ -6442,7 +6410,6 @@ class Task extends TaskFragment {
private long mLastTimeMoved;
private boolean mNeverRelinquishIdentity;
private TaskDescription mLastTaskDescription;
- private PersistedTaskSnapshotData mLastSnapshotData;
private int mTaskAffiliation;
private int mPrevAffiliateTaskId = INVALID_TASK_ID;
private int mNextAffiliateTaskId = INVALID_TASK_ID;
@@ -6670,11 +6637,6 @@ class Task extends TaskFragment {
return this;
}
- private Builder setLastSnapshotData(PersistedTaskSnapshotData lastSnapshotData) {
- mLastSnapshotData = lastSnapshotData;
- return this;
- }
-
private Builder setOrigActivity(ComponentName origActivity) {
mOrigActivity = origActivity;
return this;
@@ -6823,7 +6785,7 @@ class Task extends TaskFragment {
return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
- mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,
+ mNeverRelinquishIdentity, mLastTaskDescription,
mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,
mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 586f3c35c0c4..c3649fe98056 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -62,6 +62,8 @@ class TaskChangeNotificationController {
private static final int NOTIFY_TASK_MOVED_TO_BACK_LISTENERS_MSG = 27;
private static final int NOTIFY_LOCK_TASK_MODE_CHANGED_MSG = 28;
private static final int NOTIFY_TASK_SNAPSHOT_INVALIDATED_LISTENERS_MSG = 29;
+ private static final int NOTIFY_RECENT_TASK_REMOVED_FOR_ADD_TASK_LISTENERS_MSG = 30;
+
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -167,6 +169,10 @@ class TaskChangeNotificationController {
l.onRecentTaskListFrozenChanged(m.arg1 != 0);
};
+ private final TaskStackConsumer mNotifyRecentTaskRemovedForAddTask = (l, m) -> {
+ l.onRecentTaskRemovedForAddTask(m.arg1);
+ };
+
private final TaskStackConsumer mNotifyTaskFocusChanged = (l, m) -> {
l.onTaskFocusChanged(m.arg1, m.arg2 != 0);
};
@@ -261,6 +267,9 @@ class TaskChangeNotificationController {
case NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG:
forAllRemoteListeners(mNotifyTaskListFrozen, msg);
break;
+ case NOTIFY_RECENT_TASK_REMOVED_FOR_ADD_TASK_LISTENERS_MSG:
+ forAllRemoteListeners(mNotifyRecentTaskRemovedForAddTask, msg);
+ break;
case NOTIFY_TASK_FOCUS_CHANGED_MSG:
forAllRemoteListeners(mNotifyTaskFocusChanged, msg);
break;
@@ -541,6 +550,15 @@ class TaskChangeNotificationController {
msg.sendToTarget();
}
+ /** Called when a task is removed from the recent tasks list. */
+ void notifyRecentTaskRemovedForAddTask(int taskId) {
+ final Message msg = mHandler.obtainMessage(
+ NOTIFY_RECENT_TASK_REMOVED_FOR_ADD_TASK_LISTENERS_MSG, taskId,
+ 0 /* unused */);
+ forAllLocalListeners(mNotifyRecentTaskRemovedForAddTask, msg);
+ msg.sendToTarget();
+ }
+
/** @see ITaskStackListener#onTaskFocusChanged(int, boolean) */
void notifyTaskFocusChanged(int taskId, boolean focused) {
final Message msg = mHandler.obtainMessage(NOTIFY_TASK_FOCUS_CHANGED_MSG,
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 1f82cdb70b91..9fe3f7563902 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -307,6 +307,28 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot
}
/**
+ * Record task snapshots before shutdown.
+ */
+ void snapshotForShutdown(int displayId) {
+ if (!com.android.window.flags.Flags.recordTaskSnapshotsBeforeShutdown()) {
+ return;
+ }
+ final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
+ if (displayContent == null) {
+ return;
+ }
+ displayContent.forAllLeafTasks(task -> {
+ if (task.isVisible() && !task.isActivityTypeHome()) {
+ final TaskSnapshot snapshot = captureSnapshot(task);
+ if (snapshot != null) {
+ mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+ }
+ }
+ }, true /* traverseTopToBottom */);
+ mPersister.mSnapshotPersistQueue.shutdown();
+ }
+
+ /**
* Called when screen is being turned off.
*/
void screenTurningOff(int displayId, ScreenOffListener listener) {
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 143d1b72fff9..8562bb23b30f 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -658,8 +658,8 @@ class TransitionController {
}
// Always allow WindowState to assign layers since it won't affect transition.
return wc.asWindowState() != null || (!isPlaying()
- // Don't assign task while collecting.
- && !(wc.asTask() != null && isCollecting()));
+ // Don't assign task or display area layers while collecting.
+ && !((wc.asTask() != null || wc.asDisplayArea() != null) && isCollecting()));
}
@WindowConfiguration.WindowingMode
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5f92bb626154..2397e032fcc8 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1676,30 +1676,36 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @param orientation the specified orientation. Needs to be one of {@link ScreenOrientation}.
* @param requestingContainer the container which orientation request has changed. Mostly used
* to ensure it gets correct configuration.
+ * @return the resolved override orientation of this window container.
*/
- void setOrientation(@ScreenOrientation int orientation,
+ @ScreenOrientation
+ int setOrientation(@ScreenOrientation int orientation,
@Nullable WindowContainer requestingContainer) {
if (getOverrideOrientation() == orientation) {
- return;
+ return orientation;
}
-
setOverrideOrientation(orientation);
final WindowContainer parent = getParent();
- if (parent != null) {
- if (getConfiguration().orientation != getRequestedConfigurationOrientation()
- // Update configuration directly only if the change won't be dispatched from
- // ancestor. This prevents from computing intermediate configuration when the
- // parent also needs to be updated from the ancestor. E.g. the app requests
- // portrait but the task is still in landscape. While updating from display,
- // the task can be updated to portrait first so the configuration can be
- // computed in a consistent environment.
- && (inMultiWindowMode()
+ if (parent == null) {
+ return orientation;
+ }
+ // The derived class can return a result that is different from the given orientation.
+ final int resolvedOrientation = getOverrideOrientation();
+ if (getConfiguration().orientation != getRequestedConfigurationOrientation(
+ false /* forDisplay */, resolvedOrientation)
+ // Update configuration directly only if the change won't be dispatched from
+ // ancestor. This prevents from computing intermediate configuration when the
+ // parent also needs to be updated from the ancestor. E.g. the app requests
+ // portrait but the task is still in landscape. While updating from display,
+ // the task can be updated to portrait first so the configuration can be
+ // computed in a consistent environment.
+ && (inMultiWindowMode()
|| !handlesOrientationChangeFromDescendant(orientation))) {
- // Resolve the requested orientation.
- onConfigurationChanged(parent.getConfiguration());
- }
- onDescendantOrientationChanged(requestingContainer);
+ // Resolve the requested orientation.
+ onConfigurationChanged(parent.getConfiguration());
}
+ onDescendantOrientationChanged(requestingContainer);
+ return resolvedOrientation;
}
@ScreenOrientation
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ce032b4f7f9a..c77b1d9a7bcf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -46,7 +46,6 @@ import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
-import android.view.WindowInfo;
import android.view.WindowManager.DisplayImePolicy;
import android.view.inputmethod.ImeTracker;
import android.window.ScreenCapture;
@@ -158,26 +157,8 @@ public abstract class WindowManagerInternal {
* accessibility changed.
*/
public interface WindowsForAccessibilityCallback {
-
- /**
- * Called when the windows for accessibility changed. This is called if
- * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
- * false.
- *
- * @param forceSend Send the windows for accessibility even if they haven't changed.
- * @param topFocusedDisplayId The display Id which has the top focused window.
- * @param topFocusedWindowToken The window token of top focused window.
- * @param windows The windows for accessibility.
- */
- void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
- IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows);
-
/**
- * Called when the windows for accessibility changed. This is called if
- * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
- * true.
- * TODO(b/322444245): Remove screenSize parameter by getting it from
- * DisplayManager#getDisplay(int).getRealSize() on the a11y side.
+ * Called when the windows for accessibility changed.
*
* @param forceSend Send the windows for accessibility even if they haven't changed.
* @param topFocusedDisplayId The display Id which has the top focused window.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 88b2d229e083..a0c0b9836507 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1022,12 +1022,12 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- final boolean disableSecureWindows;
+ boolean disableSecureWindows;
try {
disableSecureWindows = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.DISABLE_SECURE_WINDOWS, 0) != 0;
} catch (Settings.SettingNotFoundException e) {
- return;
+ disableSecureWindows = false;
}
if (mDisableSecureWindows == disableSecureWindows) {
return;
@@ -3030,8 +3030,8 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowContextListenerController.unregisterWindowContainerListener(clientToken);
- final WindowToken token = wc.asWindowToken();
- if (token != null && token.isFromClient()) {
+ final WindowToken token = wc != null ? wc.asWindowToken() : null;
+ if (token != null && token.isFromClient() && token.getDisplayContent() != null) {
removeWindowToken(token.token, token.getDisplayContent().getDisplayId());
}
}
@@ -10233,6 +10233,17 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ /**
+ * Resets the spatial ordering of recents for testing purposes.
+ */
+ void resetFreezeRecentTaskListReordering() {
+ if (!checkCallingPermission(permission.MANAGE_ACTIVITY_TASKS,
+ "resetFreezeRecentTaskListReordering()")) {
+ throw new SecurityException("Requires MANAGE_ACTIVITY_TASKS permission");
+ }
+ mAtmService.getRecentTasks().resetFreezeTaskListReorderingOnTimeout();
+ }
+
@Override
public void registerTrustedPresentationListener(IBinder window,
ITrustedPresentationListener listener,
@@ -10303,7 +10314,7 @@ public class WindowManagerService extends IWindowManager.Stub
mH.post(() -> {
Toast.makeText(mContext, Looper.getMainLooper(),
mContext.getString(R.string.screen_not_shared_sensitive_content),
- Toast.LENGTH_SHORT)
+ Toast.LENGTH_LONG)
.show();
});
// If blocked due to notification protection (null window token) log protection applied
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 21ed8d793b24..fe2bcc7a74f3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -161,6 +161,8 @@ public class WindowManagerShellCommand extends ShellCommand {
return runReset(pw);
case "disable-blur":
return runSetBlurDisabled(pw);
+ case "reset-freeze-recent-tasks":
+ return runResetFreezeRecentTaskListReordering(pw);
case "set-display-windowing-mode":
return runSetDisplayWindowingMode(pw);
case "get-display-windowing-mode":
@@ -275,6 +277,11 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runResetFreezeRecentTaskListReordering(PrintWriter pw) throws RemoteException {
+ mInternal.resetFreezeRecentTaskListReordering();
+ return 0;
+ }
+
private void printInitialDisplayDensity(PrintWriter pw , int displayId) {
try {
final int initialDensity = mInterface.getInitialDisplayDensity(displayId);
@@ -1592,6 +1599,8 @@ public class WindowManagerShellCommand extends ShellCommand {
printLetterboxHelp(pw);
printMultiWindowConfigHelp(pw);
+ pw.println(" reset-freeze-recent-tasks");
+ pw.println(" Resets the spatial ordering of the recent tasks list");
pw.println(" set-display-windowing-mode [-d DISPLAY_ID] [mode_id]");
pw.println(" As mode_id, use " + WINDOWING_MODE_UNDEFINED + " for undefined, "
+ WINDOWING_MODE_FREEFORM + " for freeform, " + WINDOWING_MODE_FULLSCREEN + " for"
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index ead12826c263..c42aa37d847b 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -814,10 +814,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
if (deferResume) {
mService.mTaskSupervisor.endDeferResume();
- // Transient launching the Recents via HIERARCHY_OP_TYPE_PENDING_INTENT directly
- // resume the Recents activity with no TRANSACT_EFFECTS_LIFECYCLE. Explicitly
- // checks if the top resumed activity should be updated after defer-resume ended.
- mService.mTaskSupervisor.updateTopResumedActivityIfNeeded("endWCT");
}
mService.continueWindowLayout();
}
@@ -886,7 +882,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (windowingMode > -1) {
if (mService.isInLockTaskMode()
- && WindowConfiguration.inMultiWindowMode(windowingMode)) {
+ && WindowConfiguration.inMultiWindowMode(windowingMode)
+ && !container.isEmbedded()) {
Slog.w(TAG, "Dropping unsupported request to set multi-window windowing mode"
+ " during locked task mode.");
return effects;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 079170a70433..82947377d01e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -182,7 +182,6 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE
import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
-import static com.android.window.flags.Flags.secureWindowState;
import static com.android.window.flags.Flags.surfaceTrustedOverlay;
import android.annotation.CallSuper;
@@ -213,6 +212,7 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.WorkSource;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.MergedConfiguration;
@@ -793,6 +793,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
private final List<DrawHandler> mDrawHandlers = new ArrayList<>();
+ /**
+ * Indicates whether inset animations are currently running within the Window.
+ * This value is used by (@link com.android.server.wm.RefreshRatePolicy.java)
+ * to omit setting a frame rate on the WindowState. Insets Animation is unique in that
+ * sense that an app might drive an insets animation for a Window owned by a different
+ * app (such as IME). In that case, we need the app that drives the insets animation
+ * to be able to vote for high refresh rate from VRI.
+ */
+ private boolean mInsetsAnimationRunning;
+
private final Consumer<SurfaceControl.Transaction> mSeamlessRotationFinishedConsumer = t -> {
finishSeamlessRotation(t);
updateSurfacePosition(t);
@@ -1187,9 +1197,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (surfaceTrustedOverlay() && isWindowTrustedOverlay()) {
getPendingTransaction().setTrustedOverlay(mSurfaceControl, true);
}
- if (secureWindowState()) {
- getPendingTransaction().setSecure(mSurfaceControl, isSecureLocked());
- }
+ getPendingTransaction().setSecure(mSurfaceControl, isSecureLocked());
// All apps should be considered as occluding when computing TrustedPresentation Thresholds.
final boolean canOccludePresentation = !mSession.mCanAddInternalSystemWindow;
getPendingTransaction().setCanOccludePresentation(mSurfaceControl, canOccludePresentation);
@@ -2989,15 +2997,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return (mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
}
- @Override
- void resolveOverrideConfiguration(Configuration newParentConfig) {
- super.resolveOverrideConfiguration(newParentConfig);
- if (mActivityRecord != null) {
- // Let the activity decide whether to apply the size override.
- return;
- }
- final Configuration resolvedConfig = getResolvedOverrideConfiguration();
- resolvedConfig.seq = newParentConfig.seq;
+ void applySizeOverride(Configuration newParentConfig, Configuration resolvedConfig) {
applySizeOverrideIfNeeded(
getDisplayContent(),
mSession.mProcess.mInfo,
@@ -3380,8 +3380,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (cleanupOnResume) {
requestUpdateWallpaperIfNeeded();
}
- mDestroying = false;
- destroyedSomething = true;
+ if (!mHasSurface) {
+ mDestroying = false;
+ destroyedSomething = true;
+ }
// Since mDestroying will affect ActivityRecord#allDrawn, we need to perform another
// traversal in case we are waiting on this window to start the transition.
@@ -3434,7 +3436,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& mAttrs.type != TYPE_PRIVATE_PRESENTATION
&& !(mAttrs.type == TYPE_PRESENTATION && isOnVirtualDisplay())
) {
- mWmService.mAtmService.mActiveUids.onNonAppSurfaceVisibilityChanged(mOwnerUid, shown);
+ mWmService.mAtmService.mActiveUids.onNonAppSurfaceVisibilityChanged(mOwnerUid,
+ mAttrs.type, shown);
}
}
@@ -6180,21 +6183,28 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void setSecureLocked(boolean isSecure) {
ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, getName());
- if (secureWindowState()) {
- if (mSurfaceControl == null) {
- return;
- }
- getPendingTransaction().setSecure(mSurfaceControl, isSecure);
- } else {
- if (mWinAnimator.mSurfaceControl == null) {
- return;
- }
- getPendingTransaction().setSecure(mWinAnimator.mSurfaceControl,
- isSecure);
+ if (mSurfaceControl == null) {
+ return;
}
+ getPendingTransaction().setSecure(mSurfaceControl, isSecure);
if (mDisplayContent != null) {
mDisplayContent.refreshImeSecureFlag(getSyncTransaction());
}
mWmService.scheduleAnimationLocked();
}
+
+ void notifyInsetsAnimationRunningStateChanged(boolean running) {
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.instant(TRACE_TAG_WINDOW_MANAGER,
+ TextUtils.formatSimple("%s: notifyInsetsAnimationRunningStateChanged(%s)",
+ getName(),
+ Boolean.toString(running)));
+ }
+ mInsetsAnimationRunning = running;
+ mWmService.scheduleAnimationLocked();
+ }
+
+ boolean isInsetsAnimationRunning() {
+ return mInsetsAnimationRunning;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a934eea690f7..0154d95d888d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -49,7 +49,6 @@ import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
import static com.android.server.wm.WindowSurfaceControllerProto.SHOWN;
-import static com.android.window.flags.Flags.secureWindowState;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import android.content.Context;
@@ -310,12 +309,6 @@ class WindowStateAnimator {
int flags = SurfaceControl.HIDDEN;
final WindowManager.LayoutParams attrs = w.mAttrs;
- if (!secureWindowState()) {
- if (w.isSecureLocked()) {
- flags |= SurfaceControl.SECURE;
- }
- }
-
if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
flags |= SurfaceControl.SKIP_SCREENSHOT;
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 44e237aa27de..004f406035c0 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -672,6 +672,15 @@ class WindowToken extends WindowContainer<WindowState> {
getResolvedOverrideConfiguration().updateFrom(
mFixedRotationTransformState.mRotatedOverrideConfiguration);
}
+ if (asActivityRecord() == null) {
+ // Let ActivityRecord override the config if there is one. Otherwise, override here.
+ // Resolve WindowToken's configuration by the latest window.
+ final WindowState win = getTopChild();
+ if (win != null) {
+ final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+ win.applySizeOverride(newParentConfig, resolvedConfig);
+ }
+ }
}
@Override
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index eaa3a37d5bf3..4c0cee404b68 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -38,7 +38,6 @@ cc_library_static {
"com_android_server_adb_AdbDebuggingManager.cpp",
"com_android_server_am_BatteryStatsService.cpp",
"com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
- "com_android_server_ConsumerIrService.cpp",
"com_android_server_companion_virtual_InputController.cpp",
"com_android_server_companion_virtual_VirtualDeviceImpl.cpp",
"com_android_server_devicepolicy_CryptoTestHelper.cpp",
@@ -63,7 +62,6 @@ cc_library_static {
"com_android_server_SystemServer.cpp",
"com_android_server_tv_TvUinputBridge.cpp",
"com_android_server_tv_TvInputHal.cpp",
- "com_android_server_vr_VrManagerService.cpp",
"com_android_server_UsbAlsaJackDetector.cpp",
"com_android_server_UsbAlsaMidiDevice.cpp",
"com_android_server_UsbDeviceManager.cpp",
@@ -75,14 +73,13 @@ cc_library_static {
"com_android_server_am_LowMemDetector.cpp",
"com_android_server_pm_PackageManagerShellCommandDataLoader.cpp",
"com_android_server_sensor_SensorService.cpp",
- "com_android_server_utils_LazyJniRegistrar.cpp",
"com_android_server_wm_TaskFpsCallbackController.cpp",
"onload.cpp",
":lib_cachedAppOptimizer_native",
":lib_freezer_native",
- ":lib_gameManagerService_native",
":lib_oomConnection_native",
":lib_anrTimer_native",
+ ":lib_lazilyRegisteredServices_native",
],
include_dirs: [
@@ -248,13 +245,6 @@ filegroup {
}
filegroup {
- name: "lib_gameManagerService_native",
- srcs: [
- "com_android_server_app_GameManagerService.cpp",
- ],
-}
-
-filegroup {
name: "lib_oomConnection_native",
srcs: ["com_android_server_am_OomConnection.cpp"],
}
@@ -265,3 +255,13 @@ filegroup {
"com_android_server_utils_AnrTimer.cpp",
],
}
+
+filegroup {
+ name: "lib_lazilyRegisteredServices_native",
+ srcs: [
+ "com_android_server_ConsumerIrService.cpp",
+ "com_android_server_app_GameManagerService.cpp",
+ "com_android_server_utils_LazyJniRegistrar.cpp",
+ "com_android_server_vr_VrManagerService.cpp",
+ ],
+}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e38337540ad9..dece612c9424 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -2330,6 +2330,12 @@ static void nativeToggleCapsLock(JNIEnv* env, jobject nativeImplObj, jint device
im->getInputManager()->getReader().toggleCapsLockState(deviceId);
}
+static void resetLockedModifierState(JNIEnv* env, jobject nativeImplObj) {
+ NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+
+ im->getInputManager()->getReader().resetLockedModifierState();
+}
+
static void nativeDisplayRemoved(JNIEnv* env, jobject nativeImplObj, jint displayId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
@@ -3134,6 +3140,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"verifyInputEvent", "(Landroid/view/InputEvent;)Landroid/view/VerifiedInputEvent;",
(void*)nativeVerifyInputEvent},
{"toggleCapsLock", "(I)V", (void*)nativeToggleCapsLock},
+ {"resetLockedModifierState", "()V", (void*)resetLockedModifierState},
{"displayRemoved", "(I)V", (void*)nativeDisplayRemoved},
{"setFocusedApplication", "(ILandroid/view/InputApplicationHandle;)V",
(void*)nativeSetFocusedApplication},
diff --git a/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp b/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
index ad7781e3b8b5..0c0f8b02279b 100644
--- a/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
+++ b/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
@@ -22,6 +22,7 @@ namespace android {
// Forward declared per-class registration methods.
int register_android_server_ConsumerIrService(JNIEnv* env);
+int register_android_server_app_GameManagerService(JNIEnv* env);
int register_android_server_vr_VrManagerService(JNIEnv* env);
namespace {
@@ -33,12 +34,17 @@ void registerConsumerIrService(JNIEnv* env, jclass) {
register_android_server_ConsumerIrService(env);
}
+void registerGameManagerService(JNIEnv* env, jclass) {
+ register_android_server_app_GameManagerService(env);
+}
+
void registerVrManagerService(JNIEnv* env, jclass) {
register_android_server_vr_VrManagerService(env);
}
static const JNINativeMethod sJniRegistrarMethods[] = {
{"registerConsumerIrService", "()V", (void*)registerConsumerIrService},
+ {"registerGameManagerService", "()V", (void*)registerGameManagerService},
{"registerVrManagerService", "()V", (void*)registerVrManagerService},
};
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index c170ae99da04..df37ec3ef037 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -65,7 +65,6 @@ int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env);
int register_android_server_companion_virtual_InputController(JNIEnv* env);
int register_android_server_companion_virtual_VirtualDeviceImpl(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
int register_com_android_server_display_DisplayControl(JNIEnv* env);
int register_com_android_server_SystemClockTime(JNIEnv* env);
@@ -131,7 +130,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_sensor_SensorService(vm, env);
register_android_server_companion_virtual_InputController(env);
register_android_server_companion_virtual_VirtualDeviceImpl(env);
- register_android_server_app_GameManagerService(env);
register_com_android_server_wm_TaskFpsCallbackController(env);
register_com_android_server_display_DisplayControl(env);
register_com_android_server_SystemClockTime(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index b982098fefa4..76d16e19e774 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -371,6 +371,9 @@ class ActiveAdmin {
}
ActiveAdmin(int userId, boolean permissionBased) {
+ if (Flags.activeAdminCleanup()) {
+ throw new UnsupportedOperationException("permission based admin no longer supported");
+ }
if (permissionBased == false) {
throw new IllegalArgumentException("Can only pass true for permissionBased admin");
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 395ea9176877..c937e10a28ce 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.flags.Flags;
import android.content.ComponentName;
import android.os.FileUtils;
import android.os.PersistableBundle;
@@ -124,17 +125,18 @@ class DevicePolicyData {
final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
- // Some DevicePolicyManager APIs can be called by (1) a DPC or (2) an app with permissions that
- // isn't a DPC. For the latter, the caller won't have to provide a ComponentName and won't be
- // mapped to an ActiveAdmin. This permission-based admin should be used to persist policies
- // set by the permission-based caller. This admin should not be added to mAdminMap or mAdminList
- // since a lot of methods in DPMS assume the ActiveAdmins here have a valid ComponentName.
- // Instead, use variants of DPMS active admin getters to include the permission-based admin.
+ /**
+ * @deprecated Do not use. Policies set by permission holders must go into DevicePolicyEngine.
+ */
+ @Deprecated
ActiveAdmin mPermissionBasedAdmin;
// Create or get the permission-based admin. The permission-based admin will not have a
// DeviceAdminInfo or ComponentName.
ActiveAdmin createOrGetPermissionBasedAdmin(int userId) {
+ if (Flags.activeAdminCleanup()) {
+ throw new UnsupportedOperationException("permission based admin no longer supported");
+ }
if (mPermissionBasedAdmin == null) {
mPermissionBasedAdmin = new ActiveAdmin(userId, /* permissionBased= */ true);
}
@@ -147,7 +149,7 @@ class DevicePolicyData {
// This is the list of component allowed to start lock task mode.
List<String> mLockTaskPackages = new ArrayList<>();
- /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */
+ /** @deprecated moved to DevicePolicyEngine. */
@Deprecated
@Nullable
List<String> mUserControlDisabledPackages;
@@ -280,7 +282,7 @@ class DevicePolicyData {
}
}
- if (policyData.mPermissionBasedAdmin != null) {
+ if (!Flags.activeAdminCleanup() && policyData.mPermissionBasedAdmin != null) {
out.startTag(null, "permission-based-admin");
policyData.mPermissionBasedAdmin.writeToXml(out);
out.endTag(null, "permission-based-admin");
@@ -521,7 +523,8 @@ class DevicePolicyData {
} catch (RuntimeException e) {
Slogf.w(TAG, e, "Failed loading admin %s", name);
}
- } else if ("permission-based-admin".equals(tag)) {
+ } else if (!Flags.activeAdminCleanup() && "permission-based-admin".equals(tag)) {
+
ActiveAdmin ap = new ActiveAdmin(policy.mUserId, /* permissionBased= */ true);
ap.readFromXml(parser, /* overwritePolicies= */ false);
policy.mPermissionBasedAdmin = ap;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 984105865f7d..cb333f02757e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -99,10 +99,11 @@ import java.util.concurrent.CompletableFuture;
final class DevicePolicyEngine {
static final String TAG = "DevicePolicyEngine";
- // TODO(b/281701062): reference role name from role manager once its exposed.
static final String DEVICE_LOCK_CONTROLLER_ROLE =
"android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER";
+ static final String SYSTEM_SUPERVISION_ROLE = "android.app.role.SYSTEM_SUPERVISION";
+
private static final String CELLULAR_2G_USER_RESTRICTION_ID =
DevicePolicyIdentifiers.getIdentifierForUserRestriction(
UserManager.DISALLOW_CELLULAR_2G);
@@ -1235,6 +1236,8 @@ final class DevicePolicyEngine {
}
}
for (EnforcingAdmin admin : admins) {
+ // No need to make changes to system enforcing admins.
+ if (admin.isSystemAuthority()) break;
if (updatedPackage == null || updatedPackage.equals(admin.getPackageName())) {
if (!isPackageInstalled(admin.getPackageName(), userId)) {
Slogf.i(TAG, String.format(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 50f3f39e7e66..dde213de1d40 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -376,6 +376,7 @@ import android.app.backup.IBackupManager;
import android.app.compat.CompatChanges;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
+import android.app.supervision.SupervisionManagerInternal;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
@@ -504,6 +505,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.LocalePicker;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.NetworkUtilsInternal;
import com.android.internal.notification.SystemNotificationChannels;
@@ -715,24 +717,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.add(Settings.Secure.LOCATION_MODE);
GLOBAL_SETTINGS_ALLOWLIST = new ArraySet<>();
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_ENABLED);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_WIFI_ENABLED);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME_ZONE);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.DATA_ROAMING);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_SLEEP_POLICY);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_MODE);
- GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.ADB_ENABLED);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.ADB_WIFI_ENABLED);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.AUTO_TIME);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.AUTO_TIME_ZONE);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.DATA_ROAMING);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.USB_MASS_STORAGE_ENABLED);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.WIFI_SLEEP_POLICY);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.STAY_ON_WHILE_PLUGGED_IN);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
+ GLOBAL_SETTINGS_ALLOWLIST.add(Global.PRIVATE_DNS_MODE);
+ GLOBAL_SETTINGS_ALLOWLIST.add(PRIVATE_DNS_SPECIFIER);
GLOBAL_SETTINGS_DEPRECATED = new ArraySet<>();
- GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.BLUETOOTH_ON);
- GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
- GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.MODE_RINGER);
- GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.NETWORK_PREFERENCE);
- GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON);
+ GLOBAL_SETTINGS_DEPRECATED.add(Global.BLUETOOTH_ON);
+ GLOBAL_SETTINGS_DEPRECATED.add(Global.DEVELOPMENT_SETTINGS_ENABLED);
+ GLOBAL_SETTINGS_DEPRECATED.add(Global.MODE_RINGER);
+ GLOBAL_SETTINGS_DEPRECATED.add(Global.NETWORK_PREFERENCE);
+ GLOBAL_SETTINGS_DEPRECATED.add(Global.WIFI_ON);
SYSTEM_SETTINGS_ALLOWLIST = new ArraySet<>();
SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS);
@@ -775,7 +777,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* Strings logged with {@link
- * com.android.internal.logging.nano.MetricsProto.MetricsEvent#PROVISIONING_ENTRY_POINT_ADB},
+ * MetricsProto.MetricsEvent#PROVISIONING_ENTRY_POINT_ADB},
* {@link DevicePolicyEnums#PROVISIONING_ENTRY_POINT_ADB},
* {@link DevicePolicyEnums#SET_NETWORK_LOGGING_ENABLED} and
* {@link DevicePolicyEnums#RETRIEVE_NETWORK_LOGS}.
@@ -786,11 +788,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* For admin apps targeting R+, throw when the app sets password requirement
* that is not taken into account at given quality. For example when quality is set
- * to {@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, it doesn't
+ * to {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, it doesn't
* make sense to require certain password length. If the intent is to require a password of
* certain length having at least NUMERIC quality, the admin should first call
- * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} and only then call
- * {@link android.app.admin.DevicePolicyManager#setPasswordMinimumLength}.
+ * {@link DevicePolicyManager#setPasswordQuality} and only then call
+ * {@link DevicePolicyManager#setPasswordMinimumLength}.
*
* <p>Conversely when an admin app targeting R+ lowers password quality, those
* requirements that stop making sense are reset to default values.
@@ -801,9 +803,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* Admin apps targeting Android R+ may not use
- * {@link android.app.admin.DevicePolicyManager#setSecureSetting} to change the deprecated
- * {@link android.provider.Settings.Secure#LOCATION_MODE} setting. Instead they should use
- * {@link android.app.admin.DevicePolicyManager#setLocationEnabled}.
+ * {@link DevicePolicyManager#setSecureSetting} to change the deprecated
+ * {@link Settings.Secure#LOCATION_MODE} setting. Instead they should use
+ * {@link DevicePolicyManager#setLocationEnabled}.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
@@ -849,7 +851,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private @interface CopyAccountStatus {}
/**
- * Mapping of {@link android.app.admin.DevicePolicyManager.ApplicationExemptionConstants} to
+ * Mapping of {@link DevicePolicyManager.ApplicationExemptionConstants} to
* corresponding app-ops.
*/
private static final Map<Integer, String> APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS =
@@ -881,11 +883,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* Admin apps targeting Android S+ may not use
- * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} to set password quality
+ * {@link DevicePolicyManager#setPasswordQuality} to set password quality
* on the {@code DevicePolicyManager} instance obtained by calling
- * {@link android.app.admin.DevicePolicyManager#getParentProfileInstance}.
+ * {@link DevicePolicyManager#getParentProfileInstance}.
* Instead, they should use
- * {@link android.app.admin.DevicePolicyManager#setRequiredPasswordComplexity} to set
+ * {@link DevicePolicyManager#setRequiredPasswordComplexity} to set
* coarse-grained password requirements device-wide.
*/
@ChangeId
@@ -894,7 +896,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* For Admin Apps targeting U+
- * If {@link android.security.IKeyChainService#setGrant} is called with an alias with no
+ * If {@link IKeyChainService#setGrant} is called with an alias with no
* existing key, throw IllegalArgumentException.
*/
@ChangeId
@@ -926,6 +928,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final UsageStatsManagerInternal mUsageStatsManagerInternal;
final TelephonyManager mTelephonyManager;
final RoleManager mRoleManager;
+ final SupervisionManagerInternal mSupervisionManagerInternal;
+
private final LockPatternUtils mLockPatternUtils;
private final LockSettingsInternal mLockSettingsInternal;
private final DeviceAdminServiceController mDeviceAdminServiceController;
@@ -1474,8 +1478,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (packageName == null || packageName.equals(adminPackage)) {
if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
|| mIPackageManager.getReceiverInfo(aa.info.getComponent(),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE,
userHandle) == null) {
Slogf.e(LOG_TAG, String.format(
"Admin package %s not found for user %d, removing active admin",
@@ -1693,7 +1697,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
}
- Context createContextAsUser(UserHandle user) throws PackageManager.NameNotFoundException {
+ Context createContextAsUser(UserHandle user) throws NameNotFoundException {
final String packageName = mContext.getPackageName();
return mContext.createPackageContextAsUser(packageName, 0, user);
}
@@ -2005,25 +2009,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
- Settings.Global.putStringForUser(mContext.getContentResolver(),
+ Global.putStringForUser(mContext.getContentResolver(),
name, value, userHandle);
}
int settingsGlobalGetInt(String name, int def) {
- return Settings.Global.getInt(mContext.getContentResolver(), name, def);
+ return Global.getInt(mContext.getContentResolver(), name, def);
}
@Nullable
String settingsGlobalGetString(String name) {
- return Settings.Global.getString(mContext.getContentResolver(), name);
+ return Global.getString(mContext.getContentResolver(), name);
}
void settingsGlobalPutInt(String name, int value) {
- Settings.Global.putInt(mContext.getContentResolver(), name, value);
+ Global.putInt(mContext.getContentResolver(), name, value);
}
void settingsGlobalPutString(String name, String value) {
- Settings.Global.putString(mContext.getContentResolver(), name, value);
+ Global.putString(mContext.getContentResolver(), name, value);
}
void settingsSystemPutStringForUser(String name, String value, int userId) {
@@ -2082,6 +2086,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean isAdminInstalledCaCertAutoApproved() {
return false;
}
+
+ @Nullable
+ SupervisionManagerInternal getSupervisionManager() {
+ return LocalServices.getService(SupervisionManagerInternal.class);
+ }
}
/**
@@ -2113,6 +2122,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
mRoleManager = Objects.requireNonNull(injector.getRoleManager());
+ if (Flags.secondaryLockscreenApiEnabled()) {
+ mSupervisionManagerInternal = injector.getSupervisionManager();
+ } else {
+ mSupervisionManagerInternal = null;
+ }
mLocalService = new LocalService();
mLockPatternUtils = injector.newLockPatternUtils();
@@ -2234,7 +2248,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return Collections.unmodifiableSet(packageNames);
}
-
private @Nullable String getDefaultRoleHolderPackageName(int resId) {
String packageNameAndSignature = mContext.getString(resId);
@@ -3194,8 +3207,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return mIPackageManager.getReceiverInfo(adminName,
GET_META_DATA
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
+ | MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE, userHandle);
} catch (RemoteException e) {
// shouldn't happen.
Slogf.wtf(LOG_TAG, "Error getting receiver info", e);
@@ -3206,9 +3219,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalArgumentException("Unknown admin: " + adminName);
}
- if (!permission.BIND_DEVICE_ADMIN.equals(ai.permission)) {
+ if (!BIND_DEVICE_ADMIN.equals(ai.permission)) {
final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
- + permission.BIND_DEVICE_ADMIN;
+ + BIND_DEVICE_ADMIN;
Slogf.w(LOG_TAG, message);
if (throwForMissingPermission &&
ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
@@ -3966,7 +3979,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int N = admins.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
- if ((admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD))
+ if (((!Flags.activeAdminCleanup() && admin.isPermissionBased)
+ || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD))
&& admin.passwordExpirationTimeout > 0L
&& now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
&& admin.passwordExpirationDate > 0L) {
@@ -4399,8 +4413,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final ApplicationInfo ai;
try {
ai = mInjector.getIPackageManager().getApplicationInfo(packageName,
- (PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle);
+ (MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE), userHandle);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -5563,13 +5577,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
caller.getUserId());
Preconditions.checkArgument(!calledOnParent || isProfileOwner(caller));
- ActiveAdmin activeAdmin = admin.getActiveAdmin();
+ final ActiveAdmin activeAdmin;
+ if (Flags.activeAdminCleanup()) {
+ if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
+ synchronized (getLockObject()) {
+ activeAdmin = getActiveAdminUncheckedLocked(
+ admin.getComponentName(), admin.getUserId());
+ }
+ } else {
+ activeAdmin = null;
+ }
+ } else {
+ activeAdmin = admin.getActiveAdmin();
+ }
// We require the caller to explicitly clear any password quality requirements set
// on the parent DPM instance, to avoid the case where password requirements are
// specified in the form of quality on the parent but complexity on the profile
// itself.
- if (!calledOnParent) {
+ if (activeAdmin != null && !calledOnParent) {
final boolean hasQualityRequirementsOnParent = activeAdmin.hasParentActiveAdmin()
&& activeAdmin.getParentActiveAdmin().mPasswordPolicy.quality
!= PASSWORD_QUALITY_UNSPECIFIED;
@@ -5593,20 +5619,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
mInjector.binderWithCleanCallingIdentity(() -> {
- // Reset the password policy.
- if (calledOnParent) {
- activeAdmin.getParentActiveAdmin().mPasswordPolicy = new PasswordPolicy();
- } else {
- activeAdmin.mPasswordPolicy = new PasswordPolicy();
+ if (activeAdmin != null) {
+ // Reset the password policy.
+ if (calledOnParent) {
+ activeAdmin.getParentActiveAdmin().mPasswordPolicy = new PasswordPolicy();
+ } else {
+ activeAdmin.mPasswordPolicy = new PasswordPolicy();
+ }
+ updatePasswordQualityCacheForUserGroup(caller.getUserId());
}
+
synchronized (getLockObject()) {
updatePasswordValidityCheckpointLocked(caller.getUserId(), calledOnParent);
}
- updatePasswordQualityCacheForUserGroup(caller.getUserId());
saveSettingsLocked(caller.getUserId());
});
-
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PASSWORD_COMPLEXITY)
.setAdmin(caller.getPackageName())
@@ -5965,7 +5993,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkCallAuthorization(admin != null,
"Unauthorized caller cannot call resetPassword.");
if (getTargetSdk(admin.info.getPackageName(),
- userHandle) <= android.os.Build.VERSION_CODES.M) {
+ userHandle) <= Build.VERSION_CODES.M) {
Slogf.e(LOG_TAG, "Device admin can no longer call resetPassword()");
return false;
}
@@ -6115,7 +6143,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (policy.mLastMaximumTimeToLock != Long.MAX_VALUE) {
// Make sure KEEP_SCREEN_ON is disabled, since that
// would allow bypassing of the maximum time to lock.
- mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+ mInjector.settingsGlobalPutInt(Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(parentId, timeMs);
});
@@ -6287,28 +6315,33 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int callingUserId = caller.getUserId();
ComponentName adminComponent = null;
synchronized (getLockObject()) {
- ActiveAdmin admin;
// Make sure the caller has any active admin with the right policy or
// the required permission.
if (Flags.lockNowCoexistence()) {
- admin = enforcePermissionsAndGetEnforcingAdmin(
+ EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin(
/* admin= */ null,
/* permissions= */ new String[]{MANAGE_DEVICE_POLICY_LOCK, LOCK_DEVICE},
/* deviceAdminPolicy= */ USES_POLICY_FORCE_LOCK,
caller.getPackageName(),
getAffectedUser(parent)
- ).getActiveAdmin();
+ );
+ if (Flags.activeAdminCleanup()) {
+ adminComponent = enforcingAdmin.getComponentName();
+ } else {
+ ActiveAdmin admin = enforcingAdmin.getActiveAdmin();
+ adminComponent = admin == null ? null : admin.info.getComponent();
+ }
} else {
- admin = getActiveAdminOrCheckPermissionForCallerLocked(
+ ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked(
null,
- DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
+ USES_POLICY_FORCE_LOCK,
parent,
LOCK_DEVICE);
+ adminComponent = admin == null ? null : admin.info.getComponent();
}
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOCK_NOW);
final long ident = mInjector.binderClearCallingIdentity();
try {
- adminComponent = admin == null ? null : admin.info.getComponent();
if (adminComponent != null) {
// For Profile Owners only, callers with only permission not allowed.
if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
@@ -7443,7 +7476,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* privileged APIs.
* <p>
* This is done by checking that the calling package is authorized to perform the app operation
- * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}.
+ * {@link AppOpsManager#OP_MANAGE_CREDENTIALS}.
*
* @param caller the calling identity
* @return {@code true} if the calling process is the credential management app.
@@ -7453,7 +7486,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
AppOpsManager appOpsManager = mInjector.getAppOpsManager();
if (appOpsManager == null) return false;
return appOpsManager.noteOpNoThrow(AppOpsManager.OP_MANAGE_CREDENTIALS, caller.getUid(),
- caller.getPackageName(), null, null) == AppOpsManager.MODE_ALLOWED;
+ caller.getPackageName(), null, null) == MODE_ALLOWED;
});
}
@@ -7764,7 +7797,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public void wipeDataWithReason(String callerPackageName, int flags,
@NonNull String wipeReasonForUser, boolean calledOnParentInstance,
boolean factoryReset) {
- if (!mHasFeature && !hasCallingOrSelfPermission(permission.MASTER_CLEAR)) {
+ if (!mHasFeature && !hasCallingOrSelfPermission(MASTER_CLEAR)) {
return;
}
CallerIdentity caller = getCallerIdentity(callerPackageName);
@@ -7777,7 +7810,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
USES_POLICY_WIPE_DATA,
caller.getPackageName(),
factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance));
- ActiveAdmin admin = enforcingAdmin.getActiveAdmin();
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_WIPE_DATA);
@@ -7786,10 +7818,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
calledByProfileOwnerOnOrgOwnedDevice, calledOnParentInstance);
}
- int userId = admin != null ? admin.getUserHandle().getIdentifier()
- : caller.getUserId();
- Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin,
- userId);
+ int userId;
+ ActiveAdmin admin = null;
+ if (Flags.activeAdminCleanup()) {
+ userId = enforcingAdmin.getUserId();
+ Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser,
+ enforcingAdmin, userId);
+ } else {
+ admin = enforcingAdmin.getActiveAdmin();
+ userId = admin != null ? admin.getUserHandle().getIdentifier()
+ : caller.getUserId();
+ Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin,
+ userId);
+ }
+
if (calledByProfileOwnerOnOrgOwnedDevice) {
// When wipeData is called on the parent instance, it implies wiping the entire device.
if (calledOnParentInstance) {
@@ -7810,25 +7852,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final String adminName;
final ComponentName adminComp;
- if (admin != null) {
- if (admin.isPermissionBased) {
+ if (Flags.activeAdminCleanup()) {
+ adminComp = enforcingAdmin.getComponentName();
+ adminName = adminComp != null
+ ? adminComp.flattenToShortString()
+ : enforcingAdmin.getPackageName();
+ event.setAdmin(enforcingAdmin.getPackageName());
+ // Not including any HSUM handling here because the "else" branch in the "flag off"
+ // case below is unreachable under normal circumstances and for permission-based
+ // callers admin won't be null.
+ } else {
+ if (admin != null) {
+ if (admin.isPermissionBased) {
+ adminComp = null;
+ adminName = caller.getPackageName();
+ event.setAdmin(adminName);
+ } else {
+ adminComp = admin.info.getComponent();
+ adminName = adminComp.flattenToShortString();
+ event.setAdmin(adminComp);
+ }
+ } else {
adminComp = null;
- adminName = caller.getPackageName();
+ adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0];
+ Slogf.i(LOG_TAG, "Logging wipeData() event admin as " + adminName);
event.setAdmin(adminName);
- } else {
- adminComp = admin.info.getComponent();
- adminName = adminComp.flattenToShortString();
- event.setAdmin(adminComp);
- }
- } else {
- adminComp = null;
- adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0];
- Slogf.i(LOG_TAG, "Logging wipeData() event admin as " + adminName);
- event.setAdmin(adminName);
- if (mInjector.userManagerIsHeadlessSystemUserMode()) {
- // On headless system user mode, the call is meant to factory reset the whole
- // device, otherwise the caller could simply remove the current user.
- userId = UserHandle.USER_SYSTEM;
+ if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+ // On headless system user mode, the call is meant to factory reset the whole
+ // device, otherwise the caller could simply remove the current user.
+ userId = UserHandle.USER_SYSTEM;
+ }
}
}
event.write();
@@ -8142,7 +8195,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (getLockObject()) {
if (who == null) {
Preconditions.checkCallAuthorization(frpManagementAgentUid == caller.getUid()
- || hasCallingPermission(permission.MASTER_CLEAR)
+ || hasCallingPermission(MASTER_CLEAR)
|| hasCallingPermission(MANAGE_DEVICE_POLICY_FACTORY_RESET),
"Must be called by the FRP management agent on device");
admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
@@ -8316,7 +8369,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle);
for (int i = 0; i < admins.size(); i++) {
ActiveAdmin admin = admins.get(i);
- if (admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
+ if ((!Flags.activeAdminCleanup() && admin.isPermissionBased)
+ || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
affectedUserIds.add(admin.getUserHandle().getIdentifier());
long timeout = admin.passwordExpirationTimeout;
admin.passwordExpirationDate =
@@ -8410,7 +8464,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
*/
private int getUserIdToWipeForFailedPasswords(ActiveAdmin admin) {
final int userId = admin.getUserHandle().getIdentifier();
- if (admin.isPermissionBased) {
+ if (!Flags.activeAdminCleanup() && admin.isPermissionBased) {
return userId;
}
final ComponentName component = admin.info.getComponent();
@@ -8628,9 +8682,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slogf.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
- mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
- mInjector.settingsGlobalPutInt(Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
- mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+ mInjector.settingsGlobalPutString(Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
+ mInjector.settingsGlobalPutInt(Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
+ mInjector.settingsGlobalPutString(Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
exclusionList);
}
@@ -8751,7 +8805,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
final int rawStatus = getEncryptionStatus();
- if ((rawStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) {
+ if ((rawStatus == ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) {
return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
}
return rawStatus;
@@ -8775,7 +8829,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
*/
private int getEncryptionStatus() {
if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
- return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+ return ENCRYPTION_STATUS_ACTIVE_PER_USER;
} else {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
}
@@ -8970,7 +9024,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Turn AUTO_TIME on in settings if it is required
if (required) {
mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME,
+ () -> mInjector.settingsGlobalPutInt(Global.AUTO_TIME,
1 /* AUTO_TIME on */));
}
DevicePolicyEventLogger
@@ -9004,26 +9058,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return;
}
-
- CallerIdentity caller;
- if (Flags.setAutoTimeEnabledCoexistence()) {
- caller = getCallerIdentity(who, callerPackageName);
- } else {
- caller = getCallerIdentity(who);
- }
-
- if (Flags.setAutoTimeEnabledCoexistence()) {
- // The effect of this policy is device-wide.
- enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
- } else {
- Objects.requireNonNull(who, "ComponentName is null");
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
- || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
- caller));
- }
+ CallerIdentity caller = getCallerIdentity(who);
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
+ caller));
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, enabled ? 1 : 0));
-
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_AUTO_TIME)
.setAdmin(caller.getPackageName())
@@ -9039,23 +9080,74 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return false;
}
- CallerIdentity caller;
- if (Flags.setAutoTimeEnabledCoexistence()) {
- caller = getCallerIdentity(who, callerPackageName);
- } else {
- caller = getCallerIdentity(who);
+ CallerIdentity caller = getCallerIdentity(who);
+
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(caller));
+
+ return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
+ }
+
+ /**
+ * Set whether auto time is enabled on the device.
+ */
+ @Override
+ public void setAutoTimePolicy(String callerPackageName, int policy) {
+ if (!mHasFeature) {
+ return;
}
- if (Flags.setAutoTimeEnabledCoexistence()) {
- enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
+ final Set<Integer> allowedValues =
+ Set.of(
+ DevicePolicyManager.AUTO_TIME_ENABLED,
+ DevicePolicyManager.AUTO_TIME_DISABLED,
+ DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY);
+ Preconditions.checkArgument(
+ allowedValues.contains(policy), "Provided mode is not one of the allowed values.");
+
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ // The effect of this policy is device-wide.
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ /* who */ null,
+ SET_TIME,
+ caller.getPackageName(),
+ UserHandle.USER_ALL
+ );
+ if (policy == DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY) {
+ mDevicePolicyEngine.removeGlobalPolicy(PolicyDefinition.AUTO_TIME, enforcingAdmin);
} else {
- Objects.requireNonNull(who, "ComponentName is null");
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
- || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
- caller));
+ mDevicePolicyEngine.setGlobalPolicy(
+ PolicyDefinition.AUTO_TIME,
+ enforcingAdmin,
+ new IntegerPolicyValue(policy));
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_AUTO_TIME)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(policy == DevicePolicyManager.AUTO_TIME_ENABLED)
+ .write();
}
+ }
- return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
+ /**
+ * Returns whether auto time is used on the device or not.
+ */
+ @Override
+ public int getAutoTimePolicy(String callerPackageName) {
+ if (!mHasFeature) {
+ return DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY;
+ }
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ // The effect of this policy is device-wide.
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ /* who */ null,
+ SET_TIME,
+ caller.getPackageName(),
+ UserHandle.USER_ALL
+ );
+ Integer state = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+ PolicyDefinition.AUTO_TIME, enforcingAdmin);
+ return state != null ? state : DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY;
}
/**
@@ -9068,35 +9160,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
- CallerIdentity caller;
- if (Flags.setAutoTimeZoneEnabledCoexistence()) {
- caller = getCallerIdentity(who, callerPackageName);
- } else {
- caller = getCallerIdentity(who);
- }
+ CallerIdentity caller = getCallerIdentity(who);
- if (Flags.setAutoTimeZoneEnabledCoexistence()) {
- // The effect of this policy is device-wide.
- EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
- who,
- SET_TIME_ZONE,
- caller.getPackageName(),
- UserHandle.USER_ALL
- );
- mDevicePolicyEngine.setGlobalPolicy(
- PolicyDefinition.AUTO_TIMEZONE,
- // TODO(b/260573124): add correct enforcing admin when permission changes are
- // merged.
- enforcingAdmin,
- new BooleanPolicyValue(enabled));
- } else {
- Objects.requireNonNull(who, "ComponentName is null");
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
- || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
- caller));
- mInjector.binderWithCleanCallingIdentity(() ->
- mInjector.settingsGlobalPutInt(Global.AUTO_TIME_ZONE, enabled ? 1 : 0));
- }
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
+ caller));
+ mInjector.binderWithCleanCallingIdentity(() ->
+ mInjector.settingsGlobalPutInt(Global.AUTO_TIME_ZONE, enabled ? 1 : 0));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_AUTO_TIME_ZONE)
@@ -9114,24 +9185,68 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
- CallerIdentity caller;
- if (Flags.setAutoTimeZoneEnabledCoexistence()) {
- caller = getCallerIdentity(who, callerPackageName);
- } else {
- caller = getCallerIdentity(who);
+ CallerIdentity caller = getCallerIdentity(who);
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
+ caller));
+ return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
+ }
+
+ /**
+ * Set auto time zone state.
+ */
+ public void setAutoTimeZonePolicy(String callerPackageName, int policy) {
+ if (!mHasFeature) {
+ return;
}
- if (Flags.setAutoTimeZoneEnabledCoexistence()) {
- // The effect of this policy is device-wide.
- enforceCanQuery(SET_TIME_ZONE, caller.getPackageName(), UserHandle.USER_ALL);
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ // The effect of this policy is device-wide.
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ /* who */ null,
+ SET_TIME_ZONE,
+ caller.getPackageName(),
+ UserHandle.USER_ALL
+ );
+
+ if (policy != DevicePolicyManager.AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY) {
+ mDevicePolicyEngine.setGlobalPolicy(
+ PolicyDefinition.AUTO_TIME_ZONE,
+ enforcingAdmin,
+ new IntegerPolicyValue(policy));
+
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_AUTO_TIME_ZONE)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(policy == DevicePolicyManager.AUTO_TIME_ZONE_ENABLED)
+ .write();
} else {
- Objects.requireNonNull(who, "ComponentName is null");
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
- || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
- caller));
+ mDevicePolicyEngine.removeGlobalPolicy(
+ PolicyDefinition.AUTO_TIME_ZONE,
+ enforcingAdmin);
}
+ }
- return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
+ /**
+ * Returns whether auto time zone is used on the device or not.
+ */
+ @Override
+ public int getAutoTimeZonePolicy(String callerPackageName) {
+ if (!mHasFeature) {
+ return DevicePolicyManager.AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY;
+ }
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ // The effect of this policy is device-wide.
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ /* who */ null,
+ SET_TIME_ZONE,
+ caller.getPackageName(),
+ UserHandle.USER_ALL
+ );
+ Integer state = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+ PolicyDefinition.AUTO_TIME_ZONE, enforcingAdmin);
+ return state != null ? state : DevicePolicyManager.AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY;
}
// TODO (b/137101239): remove this method in follow-up CL
@@ -10341,7 +10456,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mDelegationMap.clear();
policy.mStatusBarDisabled = false;
policy.mSecondaryLockscreenEnabled = false;
- policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
+ policy.mUserProvisioningState = STATE_USER_UNMANAGED;
policy.mAffiliationIds.clear();
resetAffiliationCacheLocked();
policy.mLockTaskPackages.clear();
@@ -10376,7 +10491,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public int getUserProvisioningState(int userHandle) {
if (!mHasFeature) {
- return DevicePolicyManager.STATE_USER_UNMANAGED;
+ return STATE_USER_UNMANAGED;
}
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(canManageUsers(caller)
@@ -10431,7 +10546,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// ADB shell can only move directly from un-managed to finalized as part of
// directly setting profile-owner or device-owner.
if (getUserProvisioningState(userId)
- != DevicePolicyManager.STATE_USER_UNMANAGED
+ != STATE_USER_UNMANAGED
|| newState != STATE_USER_SETUP_FINALIZED) {
throw new IllegalStateException("Not allowed to change provisioning state "
+ "unless current provisioning state is unmanaged, and new state"
@@ -10469,9 +10584,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
// Valid transitions for normal use-cases.
switch (currentState) {
- case DevicePolicyManager.STATE_USER_UNMANAGED:
+ case STATE_USER_UNMANAGED:
// Can move to any state from unmanaged (except itself as an edge case)..
- if (newState != DevicePolicyManager.STATE_USER_UNMANAGED) {
+ if (newState != STATE_USER_UNMANAGED) {
return;
}
break;
@@ -10495,7 +10610,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
break;
case DevicePolicyManager.STATE_USER_PROFILE_FINALIZED:
// Should only move to an unmanaged state after removing the work profile.
- if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) {
+ if (newState == STATE_USER_UNMANAGED) {
return;
}
break;
@@ -10867,7 +10982,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
UserHandle userHandle = UserHandle.of(userId);
userContext = mContext.createPackageContextAsUser(packageName, /* flags= */ 0,
userHandle);
- } catch (PackageManager.NameNotFoundException nnfe) {
+ } catch (NameNotFoundException nnfe) {
Slogf.w(LOG_TAG, nnfe, "%s is not installed for user %d", packageName, userId);
return null;
}
@@ -11087,20 +11202,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private boolean canQueryAdminPolicy(CallerIdentity caller) {
- return hasCallingOrSelfPermission(permission.QUERY_ADMIN_POLICY);
+ return hasCallingOrSelfPermission(QUERY_ADMIN_POLICY);
}
private boolean hasPermission(String permission, int pid, int uid) {
- return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED;
+ return mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED;
}
private boolean hasCallingPermission(String permission) {
- return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
+ return mContext.checkCallingPermission(permission) == PERMISSION_GRANTED;
}
private boolean hasCallingOrSelfPermission(String permission) {
return mContext.checkCallingOrSelfPermission(permission)
- == PackageManager.PERMISSION_GRANTED;
+ == PERMISSION_GRANTED;
}
private boolean hasPermissionForPreflight(CallerIdentity caller, String permission) {
@@ -11406,7 +11521,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private String getEncryptionStatusName(int encryptionStatus) {
switch (encryptionStatus) {
- case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER:
+ case ENCRYPTION_STATUS_ACTIVE_PER_USER:
return "per-user";
case DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED:
return "unsupported";
@@ -12488,7 +12603,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle);
+ USER_SETUP_COMPLETE, 1, userHandle);
}
sendProvisioningCompletedBroadcast(
@@ -13301,10 +13416,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Objects.requireNonNull(systemEntity);
CallerIdentity caller = getCallerIdentity();
- if (caller.getUid() != Process.SYSTEM_UID) {
+ if (!isSystemUid(caller)) {
throw new SecurityException("Only system services can call setUserRestrictionForUser"
+ " on a target user: " + targetUser);
}
+ if (!UserRestrictionsUtils.isValidRestriction(key)) {
+ throw new IllegalArgumentException("Invalid restriction key: " + key);
+ }
if (VERBOSE_LOG) {
Slogf.v(LOG_TAG, "Creating SystemEnforcingAdmin %s for calling package %s",
systemEntity, caller.getPackageName());
@@ -13437,6 +13555,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller,
UserHandle.USER_ALL);
}
+
+ @Override
+ public void setUserRestrictionGloballyFromSystem(@NonNull String systemEntity, String key,
+ boolean enabled) {
+ Objects.requireNonNull(systemEntity);
+
+ CallerIdentity caller = getCallerIdentity();
+ if (!isSystemUid(caller)) {
+ throw new SecurityException("Only system services can call"
+ + " setUserRestrictionGloballyFromSystem");
+ }
+ if (!UserRestrictionsUtils.isValidRestriction(key)) {
+ throw new IllegalArgumentException("Invalid restriction key: " + key);
+ }
+ if (VERBOSE_LOG) {
+ Slogf.v(LOG_TAG, "Creating SystemEnforcingAdmin %s for calling package %s",
+ systemEntity, caller.getPackageName());
+ }
+ EnforcingAdmin admin = EnforcingAdmin.createSystemEnforcingAdmin(systemEntity);
+
+ setGlobalUserRestrictionInternal(admin, key, enabled);
+
+ logUserRestrictionCall(key, enabled, /* parent= */ false, caller, UserHandle.USER_ALL);
+ }
+
private void setLocalUserRestrictionInternal(
EnforcingAdmin admin, String key, boolean enabled, int userId) {
PolicyDefinition<Boolean> policyDefinition =
@@ -13454,6 +13597,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
userId);
}
}
+
private void setGlobalUserRestrictionInternal(
EnforcingAdmin admin, String key, boolean enabled) {
PolicyDefinition<Boolean> policyDefinition =
@@ -13875,8 +14019,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
List<ResolveInfo> activitiesToEnable = mIPackageManager
.queryIntentActivities(intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE,
parentUserId)
.getList();
@@ -14495,34 +14639,76 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private boolean hasActiveSupervisionTestAdminLocked(@UserIdInt int userId) {
+ ensureLocked();
+ if (mConstants.USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT) {
+ final DevicePolicyData policy = getUserData(userId);
+ for (ActiveAdmin admin : policy.mAdminMap.values()) {
+ if (admin != null && admin.testOnlyAdmin) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
@Override
public void setSecondaryLockscreenEnabled(ComponentName who, boolean enabled,
PersistableBundle options) {
- Objects.requireNonNull(who, "ComponentName is null");
-
- // Check can set secondary lockscreen enabled
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isProfileOwner(caller));
- Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()),
- "User %d is not allowed to call setSecondaryLockscreenEnabled",
+ if (Flags.secondaryLockscreenApiEnabled()) {
+ final CallerIdentity caller = getCallerIdentity();
+ final boolean isRoleHolder = isCallerSystemSupervisionRoleHolder(caller);
+ synchronized (getLockObject()) {
+ // TODO(b/378102594): Remove access for test admins.
+ final boolean isTestAdmin = hasActiveSupervisionTestAdminLocked(caller.getUserId());
+ Preconditions.checkCallAuthorization(isRoleHolder || isTestAdmin,
+ "Caller (%d) is not the SYSTEM_SUPERVISION role holder",
caller.getUserId());
+ }
- synchronized (getLockObject()) {
- // Allow testOnly admins to bypass supervision config requirement.
- Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
- || isSupervisionComponentLocked(caller.getComponentName()), "Admin %s is not "
- + "the default supervision component", caller.getComponentName());
- DevicePolicyData policy = getUserData(caller.getUserId());
- policy.mSecondaryLockscreenEnabled = enabled;
- saveSettingsLocked(caller.getUserId());
+ if (mSupervisionManagerInternal != null) {
+ mSupervisionManagerInternal.setSupervisionLockscreenEnabledForUser(
+ caller.getUserId(), enabled, options);
+ } else {
+ synchronized (getLockObject()) {
+ DevicePolicyData policy = getUserData(caller.getUserId());
+ policy.mSecondaryLockscreenEnabled = enabled;
+ saveSettingsLocked(caller.getUserId());
+ }
+ }
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+
+ // Check can set secondary lockscreen enabled
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(
+ isDefaultDeviceOwner(caller) || isProfileOwner(caller));
+ Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()),
+ "User %d is not allowed to call setSecondaryLockscreenEnabled",
+ caller.getUserId());
+
+ synchronized (getLockObject()) {
+ // Allow testOnly admins to bypass supervision config requirement.
+ Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
+ || isSupervisionComponentLocked(caller.getComponentName()),
+ "Admin %s is not the default supervision component",
+ caller.getComponentName());
+ DevicePolicyData policy = getUserData(caller.getUserId());
+ policy.mSecondaryLockscreenEnabled = enabled;
+ saveSettingsLocked(caller.getUserId());
+ }
}
}
@Override
public boolean isSecondaryLockscreenEnabled(@NonNull UserHandle userHandle) {
- synchronized (getLockObject()) {
- return getUserData(userHandle.getIdentifier()).mSecondaryLockscreenEnabled;
+ if (Flags.secondaryLockscreenApiEnabled() && mSupervisionManagerInternal != null) {
+ return mSupervisionManagerInternal.isSupervisionLockscreenEnabledForUser(
+ userHandle.getIdentifier());
+ } else {
+ synchronized (getLockObject()) {
+ return getUserData(userHandle.getIdentifier()).mSecondaryLockscreenEnabled;
+ }
}
}
@@ -14721,7 +14907,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (policy == null) {
// We default on the power button menu, in order to be consistent with pre-P
// behaviour.
- return DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
+ return LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
}
return policy.getFlags();
}
@@ -14850,7 +15036,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"Permission denial: device owners cannot update %1$s", setting));
}
- if (Settings.Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) {
+ if (Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) {
// ignore if it contradicts an existing policy
long timeMs = getMaximumTimeToLock(
who, mInjector.userHandleGetCallingUserId(), /* parent */ false);
@@ -15355,7 +15541,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int N = users.size();
for (int i = 0; i < N; i++) {
int userHandle = users.get(i).id;
- if (mInjector.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
+ if (mInjector.settingsSecureGetIntForUser(USER_SETUP_COMPLETE, 0,
userHandle) != 0) {
DevicePolicyData policy = getUserData(userHandle);
if (!policy.mUserSetupComplete) {
@@ -15383,7 +15569,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private class SetupContentObserver extends ContentObserver {
private final Uri mUserSetupComplete = Settings.Secure.getUriFor(
- Settings.Secure.USER_SETUP_COMPLETE);
+ USER_SETUP_COMPLETE);
private final Uri mPaired = Settings.Secure.getUriFor(Settings.Secure.DEVICE_PAIRED);
private final Uri mDefaultImeChanged = Settings.Secure.getUriFor(
Settings.Secure.DEFAULT_INPUT_METHOD);
@@ -15431,7 +15617,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private class DevicePolicyConstantsObserver extends ContentObserver {
final Uri mConstantsUri =
- Settings.Global.getUriFor(Settings.Global.DEVICE_POLICY_CONSTANTS);
+ Global.getUriFor(Global.DEVICE_POLICY_CONSTANTS);
DevicePolicyConstantsObserver(Handler handler) {
super(handler);
@@ -15724,9 +15910,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int uid = Objects.requireNonNull(
mInjector.getPackageManager().getApplicationInfoAsUser(
Objects.requireNonNull(packageName), /* flags= */ 0, userId)).uid;
- return PackageManager.PERMISSION_GRANTED
+ return PERMISSION_GRANTED
== ActivityManager.checkComponentPermission(
- android.Manifest.permission.MODIFY_QUIET_MODE, uid, /* owningUid= */
+ permission.MODIFY_QUIET_MODE, uid, /* owningUid= */
-1, /* exported= */ true);
} catch (NameNotFoundException ex) {
Slogf.w(LOG_TAG, "Cannot find the package %s to check for permissions.",
@@ -15863,7 +16049,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private @Mode int findInteractAcrossProfilesResetMode(String packageName) {
return getDefaultCrossProfilePackages().contains(packageName)
- ? AppOpsManager.MODE_ALLOWED
+ ? MODE_ALLOWED
: AppOpsManager.opToDefaultMode(AppOpsManager.OP_INTERACT_ACROSS_PROFILES);
}
@@ -16182,7 +16368,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (admin.mPasswordPolicy.quality < minPasswordQuality) {
return false;
}
- return admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ return (!Flags.activeAdminCleanup() && admin.isPermissionBased)
+ || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
}
@Override
@@ -16588,13 +16775,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (getLockObject()) {
long ident = mInjector.binderClearCallingIdentity();
boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
- >= android.os.Build.VERSION_CODES.Q;
+ >= Build.VERSION_CODES.Q;
try {
if (!isPostQAdmin) {
// Legacy admins assume that they cannot control pre-M apps
if (getTargetSdk(packageName, caller.getUserId())
- < android.os.Build.VERSION_CODES.M) {
+ < Build.VERSION_CODES.M) {
callback.sendResult(null);
return;
}
@@ -16605,7 +16792,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (grantState == PERMISSION_GRANT_STATE_GRANTED
|| grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
- || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
+ || grantState == PERMISSION_GRANT_STATE_DEFAULT) {
AdminPermissionControlParams permissionParams =
new AdminPermissionControlParams(packageName, permission,
grantState,
@@ -16640,26 +16827,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final List<String> SENSOR_PERMISSIONS = new ArrayList<>();
{
- SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
- SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
- SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
- SENSOR_PERMISSIONS.add(Manifest.permission.CAMERA);
- SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
- SENSOR_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION);
- SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
- SENSOR_PERMISSIONS.add(Manifest.permission.BACKGROUND_CAMERA);
- SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_BACKGROUND_AUDIO);
- SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
+ SENSOR_PERMISSIONS.add(permission.ACCESS_FINE_LOCATION);
+ SENSOR_PERMISSIONS.add(permission.ACCESS_BACKGROUND_LOCATION);
+ SENSOR_PERMISSIONS.add(permission.ACCESS_COARSE_LOCATION);
+ SENSOR_PERMISSIONS.add(permission.CAMERA);
+ SENSOR_PERMISSIONS.add(permission.RECORD_AUDIO);
+ SENSOR_PERMISSIONS.add(permission.ACTIVITY_RECOGNITION);
+ SENSOR_PERMISSIONS.add(permission.BODY_SENSORS);
+ SENSOR_PERMISSIONS.add(permission.BACKGROUND_CAMERA);
+ SENSOR_PERMISSIONS.add(permission.RECORD_BACKGROUND_AUDIO);
+ SENSOR_PERMISSIONS.add(permission.BODY_SENSORS_BACKGROUND);
}
private boolean canGrantPermission(CallerIdentity caller, String permission,
String targetPackageName) {
boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
- >= android.os.Build.VERSION_CODES.Q;
+ >= Build.VERSION_CODES.Q;
if (!isPostQAdmin) {
// Legacy admins assume that they cannot control pre-M apps
if (getTargetSdk(targetPackageName, caller.getUserId())
- < android.os.Build.VERSION_CODES.M) {
+ < Build.VERSION_CODES.M) {
return false;
}
}
@@ -16706,7 +16893,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throws RemoteException {
int granted;
if (getTargetSdk(caller.getPackageName(), caller.getUserId())
- < android.os.Build.VERSION_CODES.Q) {
+ < Build.VERSION_CODES.Q) {
// The per-Q behavior was to not check the app-ops state.
granted = mIPackageManager.checkPermission(permission, packageName, userId);
} else {
@@ -16715,11 +16902,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (packageState == null) {
Slog.w(LOG_TAG, "Can't get permission state for missing package "
+ packageName);
- return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+ return PERMISSION_GRANT_STATE_DEFAULT;
} else if (!packageState.getUserStateOrDefault(userId).isInstalled()) {
Slog.w(LOG_TAG, "Can't get permission state for uninstalled package "
+ packageName);
- return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+ return PERMISSION_GRANT_STATE_DEFAULT;
} else {
if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
PermissionChecker.PID_UNKNOWN,
@@ -16727,7 +16914,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
!= PermissionChecker.PERMISSION_GRANTED) {
granted = PackageManager.PERMISSION_DENIED;
} else {
- granted = PackageManager.PERMISSION_GRANTED;
+ granted = PERMISSION_GRANTED;
}
}
@@ -16738,11 +16925,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
!= PackageManager.FLAG_PERMISSION_POLICY_FIXED) {
// Not controlled by policy
- return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+ return PERMISSION_GRANT_STATE_DEFAULT;
} else {
// Policy controlled so return result based on permission grant state
- return granted == PackageManager.PERMISSION_GRANTED
- ? DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
+ return granted == PERMISSION_GRANTED
+ ? PERMISSION_GRANT_STATE_GRANTED
: DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
}
}
@@ -16862,9 +17049,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (action != null) {
switch (action) {
- case DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE:
+ case ACTION_PROVISION_MANAGED_PROFILE:
return checkManagedProfileProvisioningPreCondition(packageName, userId);
- case DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE:
+ case ACTION_PROVISION_MANAGED_DEVICE:
case DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE:
return checkDeviceOwnerProvisioningPreCondition(componentName, userId);
}
@@ -18211,7 +18398,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
boolean isUserCompleted = mInjector.settingsSecureGetIntForUser(
- Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0;
+ USER_SETUP_COMPLETE, 0, userId) != 0;
DevicePolicyData policy = getUserData(userId);
policy.mUserSetupComplete = isUserCompleted;
mStateCache.setDeviceProvisioned(isUserCompleted);
@@ -19058,13 +19245,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private boolean isAnyResetPasswordTokenActiveForUserLocked(int userId) {
+ return mDevicePolicyEngine
+ .getLocalPoliciesSetByAdmins(PolicyDefinition.RESET_PASSWORD_TOKEN, userId)
+ .entrySet()
+ .stream()
+ .anyMatch((e) -> {
+ EnforcingAdmin admin = e.getKey();
+ PolicyValue<Long> policyValue = e.getValue();
+ return isResetPasswordTokenActiveForUserLocked(policyValue.getValue(), userId)
+ && isEncryptionAware(admin.getPackageName(), userId);
+ });
+ }
+
private boolean isResetPasswordTokenActiveForUserLocked(
long passwordTokenHandle, int userHandle) {
- if (passwordTokenHandle != 0) {
- return mInjector.binderWithCleanCallingIdentity(() ->
+ return passwordTokenHandle != 0 && mInjector.binderWithCleanCallingIdentity(() ->
mLockPatternUtils.isEscrowTokenActive(passwordTokenHandle, userHandle));
- }
- return false;
}
@Override
@@ -19834,7 +20031,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private boolean isDeviceAB() {
- return "true".equalsIgnoreCase(android.os.SystemProperties
+ return "true".equalsIgnoreCase(SystemProperties
.get(AB_DEVICE_KEY, ""));
}
@@ -20101,7 +20298,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return mOwners.hasDeviceOwner()
&& mInjector.getIActivityManager().getLockTaskModeState()
== ActivityManager.LOCK_TASK_MODE_LOCKED
- && !isLockTaskFeatureEnabled(DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO)
+ && !isLockTaskFeatureEnabled(LOCK_TASK_FEATURE_SYSTEM_INFO)
&& !deviceHasKeyguard()
&& !inEphemeralUserSession();
}
@@ -20112,7 +20309,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int lockTaskFeatures = policy == null
// We default on the power button menu, in order to be consistent with pre-P
// behaviour.
- ? DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS
+ ? LOCK_TASK_FEATURE_GLOBAL_ACTIONS
: policy.getFlags();
return (lockTaskFeatures & lockTaskFeature) == lockTaskFeature;
}
@@ -20858,7 +21055,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean canHandleCheckPolicyComplianceIntent(CallerIdentity caller) {
mInjector.binderWithCleanCallingIdentity(() -> {
- final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
+ final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE);
intent.setPackage(caller.getPackageName());
final List<ResolveInfo> handlers =
mInjector.getPackageManager().queryIntentActivitiesAsUser(intent, /* flags= */
@@ -20914,6 +21111,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
String.format(NOT_SYSTEM_CALLER_MSG,
"call canProfileOwnerResetPasswordWhenLocked"));
synchronized (getLockObject()) {
+ if (Flags.resetPasswordWithTokenCoexistence()) {
+ return isAnyResetPasswordTokenActiveForUserLocked(userId);
+ }
final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(userId);
DevicePolicyData policy = getUserData(userId);
if (poAdmin == null
@@ -20922,26 +21122,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mPasswordTokenHandle, userId)) {
return false;
}
- final ApplicationInfo poAppInfo;
- try {
- poAppInfo = mIPackageManager.getApplicationInfo(
- poAdmin.info.getPackageName(), 0 /* flags */, userId);
- } catch (RemoteException e) {
- Slogf.e(LOG_TAG, "Failed to query PO app info", e);
- return false;
- }
- if (poAppInfo == null) {
- Slogf.wtf(LOG_TAG, "Cannot find AppInfo for profile owner");
- return false;
- }
- if (!poAppInfo.isEncryptionAware()) {
- return false;
- }
- Slogf.d(LOG_TAG, "PO should be able to reset password from direct boot");
- return true;
+ return isEncryptionAware(poAdmin.info.getPackageName(), userId);
}
}
+ private boolean isEncryptionAware(String packageName, int userId) {
+ final ApplicationInfo poAppInfo;
+ try {
+ poAppInfo = mIPackageManager.getApplicationInfo(packageName, 0 /* flags */, userId);
+ } catch (RemoteException e) {
+ Slogf.e(LOG_TAG, "Failed to query PO / role holder's app info", e);
+ return false;
+ }
+ if (poAppInfo == null) {
+ Slogf.wtf(LOG_TAG, "Cannot find AppInfo for PO / role holder");
+ return false;
+ }
+ if (!poAppInfo.isEncryptionAware()) {
+ return false;
+ }
+ Slogf.d(LOG_TAG, "PO / role holder should be able to reset password from direct boot");
+ return true;
+ }
+
@Override
public String getEnrollmentSpecificId(String callerPackage) {
if (!mHasFeature) {
@@ -21064,6 +21267,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkCallAuthorization(
hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
+ if (Flags.splitCreateManagedProfileEnabled()) {
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ UserHandle managedProfileUser =
+ createManagedProfileInternal(provisioningParams, caller);
+ maybeMigrateAccount(managedProfileUser.getIdentifier(), caller.getUserId(),
+ provisioningParams.getAccountToMigrate(),
+ provisioningParams.isKeepingAccountOnMigration(), callerPackage);
+ finalizeCreateManagedProfileInternal(provisioningParams, managedProfileUser);
+ return managedProfileUser;
+ });
+ }
provisioningParams.logParams(callerPackage);
UserInfo userInfo = null;
@@ -21157,6 +21371,130 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
+ public UserHandle createManagedProfile(
+ @NonNull ManagedProfileProvisioningParams provisioningParams,
+ @NonNull String callerPackage) {
+ Objects.requireNonNull(provisioningParams, "provisioningParams is null");
+ Objects.requireNonNull(callerPackage, "callerPackage is null");
+ Objects.requireNonNull(provisioningParams.getProfileAdminComponentName(), "admin is null");
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
+ CallerIdentity caller = getCallerIdentity(callerPackage);
+
+ return mInjector.binderWithCleanCallingIdentity(() ->
+ createManagedProfileInternal(provisioningParams, caller));
+ }
+
+ private UserHandle createManagedProfileInternal(
+ @NonNull ManagedProfileProvisioningParams provisioningParams,
+ @NonNull CallerIdentity caller) {
+ provisioningParams.logParams(caller.getPackageName());
+ final ComponentName admin = provisioningParams.getProfileAdminComponentName();
+ final int callingUserId = caller.getUserId();
+ UserInfo userInfo = null;
+ try {
+ final int result = checkProvisioningPreconditionSkipPermission(
+ ACTION_PROVISION_MANAGED_PROFILE, admin, callingUserId);
+ if (result != STATUS_OK) {
+ throw new ServiceSpecificException(
+ ERROR_PRE_CONDITION_FAILED,
+ "Provisioning preconditions failed with result: " + result);
+ }
+
+ final long startTime = SystemClock.elapsedRealtime();
+
+ onCreateAndProvisionManagedProfileStarted(provisioningParams);
+
+ userInfo = createProfileForUser(provisioningParams, callingUserId);
+ if (userInfo == null) {
+ throw new ServiceSpecificException(
+ ERROR_PROFILE_CREATION_FAILED,
+ "Error creating profile, createProfileForUserEvenWhenDisallowed "
+ + "returned null.");
+ }
+ resetInteractAcrossProfilesAppOps(caller.getUserId());
+ logEventDuration(
+ DevicePolicyEnums.PLATFORM_PROVISIONING_CREATE_PROFILE_MS,
+ startTime,
+ caller.getPackageName());
+
+ maybeInstallDevicePolicyManagementRoleHolderInUser(userInfo.id);
+ installExistingAdminPackage(userInfo.id, admin.getPackageName());
+
+ if (!enableAdminAndSetProfileOwner(userInfo.id, caller.getUserId(), admin)) {
+ throw new ServiceSpecificException(
+ ERROR_SETTING_PROFILE_OWNER_FAILED,
+ "Error setting profile owner.");
+ }
+ setUserSetupComplete(userInfo.id);
+ startProfileForSetup(userInfo.id, caller.getPackageName());
+
+ if (provisioningParams.isOrganizationOwnedProvisioning()) {
+ synchronized (getLockObject()) {
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id,
+ true);
+ }
+ }
+ return userInfo.getUserHandle();
+ } catch (Exception e) {
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.PLATFORM_PROVISIONING_ERROR)
+ .setStrings(caller.getPackageName())
+ .write();
+ // In case of any errors during provisioning, remove the newly created profile.
+ if (userInfo != null) {
+ mUserManager.removeUserEvenWhenDisallowed(userInfo.id);
+ }
+ throw e;
+ }
+ }
+
+ private UserInfo createProfileForUser(ManagedProfileProvisioningParams params, int userId) {
+ final Set<String> nonRequiredApps = params.isLeaveAllSystemAppsEnabled()
+ ? Collections.emptySet()
+ : mOverlayPackagesProvider.getNonRequiredApps(params.getProfileAdminComponentName(),
+ userId, ACTION_PROVISION_MANAGED_PROFILE);
+ if (nonRequiredApps.isEmpty()) {
+ Slogf.i(LOG_TAG, "No disallowed packages for the managed profile.");
+ } else {
+ for (String packageName : nonRequiredApps) {
+ Slogf.i(LOG_TAG, "Disallowed package [" + packageName + "]");
+ }
+ }
+ return mUserManager.createProfileForUserEvenWhenDisallowed(
+ params.getProfileName(),
+ UserManager.USER_TYPE_PROFILE_MANAGED,
+ UserInfo.FLAG_DISABLED,
+ userId,
+ nonRequiredApps.toArray(new String[nonRequiredApps.size()]));
+ }
+
+ @Override
+ public void finalizeCreateManagedProfile(
+ @NonNull ManagedProfileProvisioningParams provisioningParams,
+ @NonNull UserHandle managedProfileUser) {
+ Objects.requireNonNull(provisioningParams, "provisioningParams is null");
+ Objects.requireNonNull(managedProfileUser, "managedProfileUser is null");
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ finalizeCreateManagedProfileInternal(provisioningParams, managedProfileUser);
+ });
+ }
+
+ private void finalizeCreateManagedProfileInternal(
+ @NonNull ManagedProfileProvisioningParams provisioningParams,
+ @NonNull UserHandle managedProfileUser
+ ) {
+ onCreateAndProvisionManagedProfileCompleted(provisioningParams);
+ sendProvisioningCompletedBroadcast(
+ managedProfileUser.getIdentifier(),
+ ACTION_PROVISION_MANAGED_PROFILE,
+ provisioningParams.isLeaveAllSystemAppsEnabled());
+ }
+
+ @Override
public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser,
Account migratedAccount) {
Preconditions.checkCallAuthorization(
@@ -21326,7 +21664,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void pregrantDefaultInteractAcrossProfilesAppOps(@UserIdInt int userId) {
final String op =
- AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES);
+ AppOpsManager.permissionToOp(permission.INTERACT_ACROSS_PROFILES);
for (String packageName : getConfigurableDefaultCrossProfilePackages(userId)) {
if (!appOpIsDefaultOrAllowed(userId, op, packageName)) {
continue;
@@ -21529,7 +21867,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slogf.i(LOG_TAG, "Account removed from the primary user.");
} else {
// TODO(174768447): Revisit start activity logic.
- final Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class);
+ final Intent removeIntent =
+ result.getParcelable(AccountManager.KEY_INTENT, Intent.class);
removeIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
if (removeIntent != null) {
Slogf.i(LOG_TAG, "Starting activity to remove account");
@@ -21825,7 +22164,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
synchronized (getLockObject()) {
mInjector.settingsGlobalPutStringForUser(
- Settings.Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId);
+ Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId);
}
setUserProvisioningState(STATE_USER_SETUP_FINALIZED, userId);
@@ -22088,7 +22427,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean isDevicePotentiallyStolen(String callerPackageName) {
final CallerIdentity caller = getCallerIdentity(callerPackageName);
- if (!android.app.admin.flags.Flags.deviceTheftImplEnabled()) {
+ if (!Flags.deviceTheftImplEnabled()) {
return false;
}
enforcePermission(QUERY_DEVICE_STOLEN_STATE, caller.getPackageName(),
@@ -22124,7 +22463,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+ permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
Objects.requireNonNull(drawables, "drawables must be provided.");
@@ -22140,7 +22479,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void resetDrawables(@NonNull List<String> drawableIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+ permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
Objects.requireNonNull(drawableIds, "drawableIds must be provided.");
@@ -22166,7 +22505,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void setStrings(@NonNull List<DevicePolicyStringResource> strings) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+ permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
Objects.requireNonNull(strings, "strings must be provided.");
@@ -22181,7 +22520,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void resetStrings(@NonNull List<String> stringIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+ permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
mInjector.binderWithCleanCallingIdentity(() -> {
if (mDeviceManagementResourcesProvider.removeStrings(stringIds)) {
@@ -22251,7 +22590,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState() {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+ permission.MANAGE_ROLE_HOLDERS));
setBypassDevicePolicyManagementRoleQualificationStateInternal(
/* currentRoleHolder= */ null, /* allowBypass= */ false);
}
@@ -22259,7 +22598,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+ permission.MANAGE_ROLE_HOLDERS));
return mInjector.binderWithCleanCallingIdentity(() -> {
if (getUserData(
UserHandle.USER_SYSTEM).mBypassDevicePolicyManagementRoleQualifications) {
@@ -23255,7 +23594,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(admin.info.getComponent(), userId,
admin);
}
- admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
+ admin = Flags.activeAdminCleanup()
+ ? null : getUserData(userId).createOrGetPermissionBasedAdmin(userId);
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
@@ -23278,8 +23618,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
}
-
- admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
+ admin = Flags.activeAdminCleanup()
+ ? null : getUserData(userId).createOrGetPermissionBasedAdmin(userId);
return EnforcingAdmin.createEnforcingAdmin(packageName, userId, admin);
}
@@ -23786,9 +24126,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slogf.i(LOG_TAG,
"Started device policies migration to the device policy engine.");
// TODO(b/359188869): Move this to the current migration method.
- if (Flags.setAutoTimeZoneEnabledCoexistence()) {
- migrateAutoTimezonePolicy();
- }
if (Flags.setPermissionGrantStateCoexistence()) {
migratePermissionGrantStatePolicies();
}
@@ -23837,11 +24174,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Additional migration steps should repeat the pattern above with a new backupId.
}
- private void migrateAutoTimezonePolicy() {
- Slogf.i(LOG_TAG, "Skipping Migration of AUTO_TIMEZONE policy to device policy engine,"
- + "as no way to identify if the value was set by the admin or the user.");
- }
-
private void migratePermissionGrantStatePolicies() {
Slogf.i(LOG_TAG, "Migrating PERMISSION_GRANT policy to device policy engine.");
for (UserInfo userInfo : mUserManager.getUsers()) {
@@ -23859,7 +24191,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!isRuntimePermission(permission)) {
continue;
}
- int grantState = DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+ int grantState = PERMISSION_GRANT_STATE_DEFAULT;
try {
grantState = getPermissionGrantStateForUser(
packageInfo.packageName, permission,
@@ -23872,7 +24204,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slogf.e(LOG_TAG, e, "Error retrieving permission grant state for %s "
+ "and %s", packageInfo.packageName, permission);
}
- if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
+ if (grantState == PERMISSION_GRANT_STATE_DEFAULT) {
// Not Controlled by a policy
continue;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index 634f1bc97772..1fd628a20afa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
@@ -23,6 +23,7 @@ import android.app.admin.DeviceAdminAuthority;
import android.app.admin.DpcAuthority;
import android.app.admin.RoleAuthority;
import android.app.admin.UnknownAuthority;
+import android.app.admin.flags.Flags;
import android.content.ComponentName;
import android.os.UserHandle;
@@ -280,6 +281,10 @@ final class EnforcingAdmin {
return getAuthorities().contains(authority);
}
+ boolean isSystemAuthority() {
+ return mIsSystemAuthority;
+ }
+
@NonNull
String getPackageName() {
return mPackageName;
@@ -291,9 +296,17 @@ final class EnforcingAdmin {
@Nullable
public ActiveAdmin getActiveAdmin() {
+ if (Flags.activeAdminCleanup()) {
+ throw new UnsupportedOperationException("getActiveAdmin() no longer supported");
+ }
return mActiveAdmin;
}
+ @Nullable
+ ComponentName getComponentName() {
+ return mComponentName;
+ }
+
@NonNull
android.app.admin.EnforcingAdmin getParcelableAdmin() {
Authority authority;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index f1711f5f8c0b..24b16b7c2c60 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -17,6 +17,7 @@
package com.android.server.devicepolicy;
import static com.android.server.devicepolicy.DevicePolicyEngine.DEVICE_LOCK_CONTROLLER_ROLE;
+import static com.android.server.devicepolicy.DevicePolicyEngine.SYSTEM_SUPERVISION_ROLE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -94,14 +95,18 @@ final class PolicyDefinition<V> {
private static final MostRestrictive<Boolean> TRUE_MORE_RESTRICTIVE = new MostRestrictive<>(
List.of(new BooleanPolicyValue(true), new BooleanPolicyValue(false)));
- static PolicyDefinition<Boolean> AUTO_TIMEZONE = new PolicyDefinition<>(
+ static PolicyDefinition<Integer> AUTO_TIME_ZONE = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY),
- // auto timezone is disabled by default, hence enabling it is more restrictive.
- TRUE_MORE_RESTRICTIVE,
+ // Auto time zone is enabled by default. Enabled state has higher priority given it
+ // means the time will be more precise and other applications can rely on that for
+ // their purposes.
+ new TopPriority<>(List.of(
+ EnforcingAdmin.getRoleAuthorityOf(SYSTEM_SUPERVISION_ROLE),
+ EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE),
+ EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_GLOBAL_ONLY_POLICY,
- (Boolean value, Context context, Integer userId, PolicyKey policyKey) ->
- PolicyEnforcerCallbacks.setAutoTimezoneEnabled(value, context),
- new BooleanPolicySerializer());
+ PolicyEnforcerCallbacks::setAutoTimeZonePolicy,
+ new IntegerPolicySerializer());
static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
new PolicyDefinition<>(
@@ -344,12 +349,22 @@ final class PolicyDefinition<V> {
PolicyEnforcerCallbacks::setMtePolicy,
new IntegerPolicySerializer());
+ static PolicyDefinition<Integer> AUTO_TIME = new PolicyDefinition<>(
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIME_POLICY),
+ new TopPriority<>(List.of(
+ EnforcingAdmin.getRoleAuthorityOf(SYSTEM_SUPERVISION_ROLE),
+ EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE),
+ EnforcingAdmin.DPC_AUTHORITY)),
+ POLICY_FLAG_GLOBAL_ONLY_POLICY,
+ PolicyEnforcerCallbacks::setAutoTimePolicy,
+ new IntegerPolicySerializer());
+
private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
// TODO(b/277218360): Revisit policies that should be marked as global-only.
static {
- POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIME_ZONE);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
GENERIC_PERMISSION_GRANT);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SECURITY_LOGGING_POLICY,
@@ -392,6 +407,7 @@ final class PolicyDefinition<V> {
PACKAGES_SUSPENDED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY,
MEMORY_TAGGING);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIME_POLICY, AUTO_TIME);
// User Restriction Policies
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index fdc0ec1a0471..8f80004a7ea5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -81,20 +81,24 @@ final class PolicyEnforcerCallbacks {
return AndroidFuture.completedFuture(true);
}
- static CompletableFuture<Boolean> setAutoTimezoneEnabled(@Nullable Boolean enabled,
- @NonNull Context context) {
+ static CompletableFuture<Boolean> setAutoTimeZonePolicy(
+ @Nullable Integer policy, @NonNull Context context, int userId,
+ @NonNull PolicyKey policyKey) {
if (!Flags.setAutoTimeZoneEnabledCoexistence()) {
- Slogf.w(LOG_TAG, "Trying to enforce setAutoTimezoneEnabled while flag is off.");
+ Slogf.w(LOG_TAG, "Trying to enforce setAutoTimeZonePolicy while flag is off.");
return AndroidFuture.completedFuture(true);
}
return Binder.withCleanCallingIdentity(() -> {
Objects.requireNonNull(context);
-
- int value = enabled != null && enabled ? 1 : 0;
- return AndroidFuture.completedFuture(
- Settings.Global.putInt(
- context.getContentResolver(), Settings.Global.AUTO_TIME_ZONE,
- value));
+ if (policy != null &&
+ policy == DevicePolicyManager.AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY) {
+ return AndroidFuture.completedFuture(false);
+ }
+ int enabled = policy != null &&
+ policy == DevicePolicyManager.AUTO_TIME_ZONE_ENABLED ? 1 : 0;
+ return AndroidFuture.completedFuture(Settings.Global.putInt(
+ context.getContentResolver(), Settings.Global.AUTO_TIME_ZONE,
+ enabled));
});
}
@@ -208,6 +212,25 @@ final class PolicyEnforcerCallbacks {
return AndroidFuture.completedFuture(true);
}
+ public static CompletableFuture<Boolean> setAutoTimePolicy(
+ Integer policy, Context context, Integer userId, PolicyKey policyKey) {
+ if (!Flags.setAutoTimeEnabledCoexistence()) {
+ Slogf.w(LOG_TAG, "Trying to enforce setAutoTimePolicy while flag is off.");
+ return AndroidFuture.completedFuture(true);
+ }
+ return Binder.withCleanCallingIdentity(() -> {
+ Objects.requireNonNull(context);
+ if (policy != null
+ && policy == DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY) {
+ return AndroidFuture.completedFuture(false);
+ }
+ int enabled = policy != null && policy == DevicePolicyManager.AUTO_TIME_ENABLED ? 1 : 0;
+ return AndroidFuture.completedFuture(
+ Settings.Global.putInt(
+ context.getContentResolver(), Settings.Global.AUTO_TIME, enabled));
+ });
+ }
+
private static class BlockingCallback {
private final CountDownLatch mLatch = new CountDownLatch(1);
private final AtomicReference<Boolean> mValue = new AtomicReference<>();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 19b03437292f..82d49fcac305 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -27,6 +27,7 @@ import static android.system.OsConstants.O_CLOEXEC;
import static android.system.OsConstants.O_RDONLY;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.hardware.input.Flags.inputManagerLifecycleSupport;
import static com.android.server.utils.TimingsTraceAndSlog.SYSTEM_SERVER_TIMING_TAG;
import static com.android.tradeinmode.flags.Flags.enableTradeInMode;
@@ -249,8 +250,10 @@ import com.android.server.security.AttestationVerificationManagerService;
import com.android.server.security.FileIntegrityService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
-import com.android.server.security.adaptiveauthentication.AdaptiveAuthenticationService;
import com.android.server.security.advancedprotection.AdvancedProtectionService;
+import com.android.server.security.authenticationpolicy.AuthenticationPolicyService;
+import com.android.server.security.authenticationpolicy.SecureLockDeviceService;
+import com.android.server.security.intrusiondetection.IntrusionDetectionService;
import com.android.server.security.rkp.RemoteProvisioningService;
import com.android.server.selinux.SelinuxAuditLogsService;
import com.android.server.sensorprivacy.SensorPrivacyService;
@@ -1652,7 +1655,12 @@ public final class SystemServer implements Dumpable {
t.traceEnd();
t.traceBegin("StartInputManagerService");
- inputManager = new InputManagerService(context);
+ if (inputManagerLifecycleSupport()) {
+ inputManager = mSystemServiceManager.startService(
+ InputManagerService.Lifecycle.class).getService();
+ } else {
+ inputManager = new InputManagerService(context);
+ }
t.traceEnd();
t.traceBegin("DeviceStateManagerService");
@@ -1673,8 +1681,10 @@ public final class SystemServer implements Dumpable {
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
| DUMP_FLAG_PROTO);
- ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
- /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
+ if (!inputManagerLifecycleSupport()) {
+ ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
+ /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
+ }
t.traceEnd();
t.traceBegin("SetWindowManagerService");
@@ -1760,6 +1770,13 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(LogcatManagerService.class);
t.traceEnd();
+ if (!isWatch && !isTv && !isAutomotive
+ && android.security.Flags.aflApi()) {
+ t.traceBegin("StartIntrusionDetectionService");
+ mSystemServiceManager.startService(IntrusionDetectionService.class);
+ t.traceEnd();
+ }
+
if (AppFunctionManagerConfiguration.isSupported(context)) {
t.traceBegin("StartAppFunctionManager");
mSystemServiceManager.startService(AppFunctionManagerService.class);
@@ -2651,9 +2668,15 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(AuthService.class);
t.traceEnd();
+ if (android.security.Flags.secureLockdown()) {
+ t.traceBegin("StartSecureLockDeviceService.Lifecycle");
+ mSystemServiceManager.startService(SecureLockDeviceService.Lifecycle.class);
+ t.traceEnd();
+ }
+
if (android.adaptiveauth.Flags.enableAdaptiveAuth()) {
- t.traceBegin("StartAdaptiveAuthenticationService");
- mSystemServiceManager.startService(AdaptiveAuthenticationService.class);
+ t.traceBegin("StartAuthenticationPolicyService");
+ mSystemServiceManager.startService(AuthenticationPolicyService.class);
t.traceEnd();
}
@@ -2761,8 +2784,9 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(WEAR_MODE_SERVICE_CLASS);
t.traceEnd();
- boolean enableWristOrientationService = SystemProperties.getBoolean(
- "config.enable_wristorientation", false);
+ boolean enableWristOrientationService =
+ !android.server.Flags.migrateWristOrientation()
+ && SystemProperties.getBoolean("config.enable_wristorientation", false);
if (enableWristOrientationService) {
t.traceBegin("StartWristOrientationService");
mSystemServiceManager.startService(WRIST_ORIENTATION_SERVICE_CLASS);
@@ -3053,7 +3077,10 @@ public final class SystemServer implements Dumpable {
if (com.android.ranging.flags.Flags.rangingStackEnabled()) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)
|| context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_RTT)) {
+ PackageManager.FEATURE_WIFI_RTT)
+ || (com.android.ranging.flags.Flags.rangingCsEnabled()
+ && context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING))) {
t.traceBegin("RangingService");
// TODO: b/375264320 - Remove after RELEASE_RANGING_STACK is ramped to next.
try {
@@ -3331,16 +3358,18 @@ public final class SystemServer implements Dumpable {
reportWtf("Notifying NetworkTimeService running", e);
}
t.traceEnd();
- t.traceBegin("MakeInputManagerServiceReady");
- try {
- // TODO(BT) Pass parameter to input manager
- if (inputManagerF != null) {
- inputManagerF.systemRunning();
+ if (!inputManagerLifecycleSupport()) {
+ t.traceBegin("MakeInputManagerServiceReady");
+ try {
+ // TODO(BT) Pass parameter to input manager
+ if (inputManagerF != null) {
+ inputManagerF.systemRunning();
+ }
+ } catch (Throwable e) {
+ reportWtf("Notifying InputManagerService running", e);
}
- } catch (Throwable e) {
- reportWtf("Notifying InputManagerService running", e);
+ t.traceEnd();
}
- t.traceEnd();
t.traceBegin("MakeTelephonyRegistryReady");
try {
if (telephonyRegistryF != null) {
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index e2ac22de29a4..4412968999e5 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -39,6 +39,14 @@ flag {
}
flag {
+ name: "migrate_wrist_orientation"
+ namespace: "wear_frameworks"
+ description: "Migrate wrist orientation service functionality to wear settings service"
+ bug: "352725980"
+ is_fixed_read_only: true
+}
+
+flag {
name: "allow_network_time_update_service"
namespace: "wear_systems"
description: "Allow NetworkTimeUpdateService on Wear"
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 4e868887ea1b..228e32e98cc7 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -70,6 +70,7 @@ public final class ProfcollectForwardingService extends SystemService {
private int mUsageSetting;
private boolean mUploadEnabled;
+ private static boolean sVerityEnforced;
private boolean mAdbActive;
private IProfCollectd mIProfcollect;
@@ -117,6 +118,13 @@ public final class ProfcollectForwardingService extends SystemService {
mUsageSetting = -1;
}
+ // Check verity, disable profile upload if not enforced.
+ final String verityMode = SystemProperties.get("ro.boot.veritymode");
+ sVerityEnforced = verityMode.equals("enforcing");
+ if (!sVerityEnforced) {
+ Log.d(LOG_TAG, "verity is not enforced: " + verityMode);
+ }
+
mUploadEnabled =
context.getResources().getBoolean(R.bool.config_profcollectReportUploaderEnabled);
@@ -144,6 +152,10 @@ public final class ProfcollectForwardingService extends SystemService {
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
UsbManager usbManager = getContext().getSystemService(UsbManager.class);
+ if (usbManager == null) {
+ mAdbActive = false;
+ return;
+ }
mAdbActive = ((usbManager.getCurrentFunctions() & UsbManager.FUNCTION_ADB) == 1);
Log.d(LOG_TAG, "ADB is " + mAdbActive + " on system startup");
}
@@ -369,6 +381,10 @@ public final class ProfcollectForwardingService extends SystemService {
Log.i(LOG_TAG, "Upload is not enabled.");
return;
}
+ if (!sVerityEnforced) {
+ Log.i(LOG_TAG, "Verity is not enforced.");
+ return;
+ }
Intent intent = new Intent()
.setPackage("com.android.shell")
.setAction("com.android.shell.action.PROFCOLLECT_UPLOAD")
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index a547d0f94ea3..4e9fff230bac 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import static org.testng.Assert.expectThrows;
@@ -96,6 +97,7 @@ public class BackupManagerServiceRoboTest {
@UserIdInt private int mUserTwoId;
@Mock private UserBackupManagerService mUserSystemService;
@Mock private UserBackupManagerService mUserOneService;
+ @Mock private BackupAgentConnectionManager mUserOneBackupAgentConnectionManager;
@Mock private UserBackupManagerService mUserTwoService;
/** Setup */
@@ -116,6 +118,9 @@ public class BackupManagerServiceRoboTest {
mShadowContext.grantPermissions(BACKUP);
mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
+ when(mUserOneService.getBackupAgentConnectionManager()).thenReturn(
+ mUserOneBackupAgentConnectionManager);
+
ShadowBinder.setCallingUid(Process.SYSTEM_UID);
}
@@ -226,7 +231,7 @@ public class BackupManagerServiceRoboTest {
backupManagerService.agentConnected(mUserOneId, TEST_PACKAGE, agentBinder);
- verify(mUserOneService).agentConnected(TEST_PACKAGE, agentBinder);
+ verify(mUserOneBackupAgentConnectionManager).agentConnected(TEST_PACKAGE, agentBinder);
}
/** Test that the backup service does not route methods for non-registered users. */
@@ -239,7 +244,8 @@ public class BackupManagerServiceRoboTest {
backupManagerService.agentConnected(mUserTwoId, TEST_PACKAGE, agentBinder);
- verify(mUserOneService, never()).agentConnected(TEST_PACKAGE, agentBinder);
+ verify(mUserOneBackupAgentConnectionManager, never()).agentConnected(TEST_PACKAGE,
+ agentBinder);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 7349c14ef62b..aeb1ba93f049 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -107,6 +107,7 @@ import com.android.internal.backup.IBackupTransport;
import com.android.internal.infra.AndroidFuture;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
+import com.android.server.backup.BackupAgentConnectionManager;
import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.DataChangedJournal;
import com.android.server.backup.KeyValueBackupJob;
@@ -167,7 +168,6 @@ import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
-// TODO: Test agents timing out
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
@@ -195,6 +195,7 @@ public class KeyValueBackupTaskTest {
@Mock private IBackupManagerMonitor mMonitor;
@Mock private OnTaskFinishedListener mListener;
@Mock private PackageManagerInternal mPackageManagerInternal;
+ @Mock private BackupAgentConnectionManager mBackupAgentConnectionManager;
private UserBackupManagerService mBackupManagerService;
private TransportData mTransport;
@@ -257,6 +258,8 @@ public class KeyValueBackupTaskTest {
when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
when(mBackupManagerService.getDataDir()).thenReturn(mDataDir);
when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
+ when(mBackupManagerService.getBackupAgentConnectionManager()).thenReturn(
+ mBackupAgentConnectionManager);
mBackupHandler = mBackupManagerService.getBackupHandler();
mShadowBackupLooper = shadowOf(mBackupHandler.getLooper());
@@ -749,7 +752,8 @@ public class KeyValueBackupTaskTest {
/**
* Agent unavailable means {@link
- * UserBackupManagerService#bindToAgentSynchronous(ApplicationInfo, int)} returns {@code null}.
+ * BackupAgentConnectionManager#bindToAgentSynchronous(ApplicationInfo, int, int)} returns
+ * {@code null}.
*
* @see #setUpAgent(PackageData)
*/
@@ -805,7 +809,7 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
doThrow(SecurityException.class)
- .when(mBackupManagerService)
+ .when(mBackupAgentConnectionManager)
.bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt(), anyInt());
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
@@ -823,7 +827,7 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
doThrow(SecurityException.class)
- .when(mBackupManagerService)
+ .when(mBackupAgentConnectionManager)
.bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt(), anyInt());
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
@@ -861,7 +865,7 @@ public class KeyValueBackupTaskTest {
runTask(task);
verify(mBackupManagerService).setWorkSource(null);
- verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
+ verify(mBackupAgentConnectionManager).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
}
@Test
@@ -1097,7 +1101,7 @@ public class KeyValueBackupTaskTest {
runTask(task);
verify(agentMock.agentBinder).fail(any());
- verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
+ verify(mBackupAgentConnectionManager).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
}
@Test
@@ -1418,7 +1422,8 @@ public class KeyValueBackupTaskTest {
.isEqualTo("newState".getBytes());
assertCleansUpFiles(mTransport, PM_PACKAGE);
// We don't unbind PM
- verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+ verify(mBackupAgentConnectionManager, never()).unbindAgent(
+ argThat(applicationInfo(PM_PACKAGE)));
}
@Test
@@ -1439,7 +1444,8 @@ public class KeyValueBackupTaskTest {
runTask(task);
- verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+ verify(mBackupAgentConnectionManager, never()).unbindAgent(
+ argThat(applicationInfo(PM_PACKAGE)));
}
@Test
@@ -1642,9 +1648,10 @@ public class KeyValueBackupTaskTest {
runTask(task);
- InOrder inOrder = inOrder(agentMock.agent, mBackupManagerService);
+ InOrder inOrder = inOrder(agentMock.agent, mBackupAgentConnectionManager);
inOrder.verify(agentMock.agent).onQuotaExceeded(anyLong(), eq(1234L));
- inOrder.verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
+ inOrder.verify(mBackupAgentConnectionManager).unbindAgent(
+ argThat(applicationInfo(PACKAGE_1)));
}
@Test
@@ -2634,12 +2641,12 @@ public class KeyValueBackupTaskTest {
doNothing().when(backupAgentBinder).fail(any());
if (packageData.available) {
doReturn(backupAgentBinder)
- .when(mBackupManagerService)
+ .when(mBackupAgentConnectionManager)
.bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt(),
anyInt());
} else {
doReturn(null)
- .when(mBackupManagerService)
+ .when(mBackupAgentConnectionManager)
.bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt(),
anyInt());
}
@@ -2976,7 +2983,7 @@ public class KeyValueBackupTaskTest {
private void assertCleansUpFilesAndAgent(TransportData transport, PackageData packageData) {
assertCleansUpFiles(transport, packageData);
- verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(packageData)));
+ verify(mBackupAgentConnectionManager).unbindAgent(argThat(applicationInfo(packageData)));
}
private void assertCleansUpFiles(TransportData transport, PackageData packageData) {
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java
index 67e254782f6d..53a25dd454ef 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionService.java
+++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java
@@ -21,10 +21,11 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.supervision.ISupervisionManager;
+import android.app.supervision.SupervisionManagerInternal;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.os.Bundle;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
@@ -179,8 +180,15 @@ public class SupervisionService extends ISupervisionManager.Stub {
}
@Override
+ public boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId) {
+ synchronized (getLockObject()) {
+ return getUserDataLocked(userId).supervisionLockScreenEnabled;
+ }
+ }
+
+ @Override
public void setSupervisionLockscreenEnabledForUser(
- @UserIdInt int userId, boolean enabled, @Nullable Bundle options) {
+ @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options) {
synchronized (getLockObject()) {
SupervisionUserData data = getUserDataLocked(userId);
data.supervisionLockScreenEnabled = enabled;
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionUserData.java b/services/supervision/java/com/android/server/supervision/SupervisionUserData.java
index 56162372f740..1dd48f581bf4 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionUserData.java
+++ b/services/supervision/java/com/android/server/supervision/SupervisionUserData.java
@@ -19,7 +19,7 @@ package com.android.server.supervision;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.os.Bundle;
+import android.os.PersistableBundle;
import android.util.IndentingPrintWriter;
/** User specific data, used internally by the {@link SupervisionService}. */
@@ -27,7 +27,7 @@ public class SupervisionUserData {
public final @UserIdInt int userId;
public boolean supervisionEnabled;
public boolean supervisionLockScreenEnabled;
- @Nullable public Bundle supervisionLockScreenOptions;
+ @Nullable public PersistableBundle supervisionLockScreenOptions;
public SupervisionUserData(@UserIdInt int userId) {
this.userId = userId;
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 5bb6b19cd63e..d08715586580 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -194,7 +194,13 @@ public class InputMethodServiceTest {
() -> assertThat(mActivity.hideImeWithWindowInsetsController()).isTrue(),
true /* expected */,
false /* inputViewStarted */);
- assertThat(mInputMethodService.isInputViewShown()).isFalse();
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ // The IME visibility is only sent at the end of the animation. Therefore, we have to
+ // wait until the visibility was sent to the server and the IME window hidden.
+ eventually(() -> assertThat(mInputMethodService.isInputViewShown()).isFalse());
+ } else {
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
+ }
}
/**
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
index 1be5cef28244..acd34e323dc2 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
@@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -60,6 +61,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.List;
@AppModeFull
@AppModeNonSdkSandbox
@@ -124,7 +126,8 @@ public class BroadcastHelperTest {
@Test
public void changeNonExportedComponent_sendPackageChangedBroadcastToSystem_withPermission()
throws Exception {
- changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */);
+ changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
+ new String[0] /* sharedPackages */);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mMockActivityManagerInternal).broadcastIntentWithCallback(
@@ -140,7 +143,8 @@ public class BroadcastHelperTest {
@Test
public void changeNonExportedComponent_sendPackageChangedBroadcastToApplicationItself()
throws Exception {
- changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */);
+ changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
+ new String[0] /* sharedPackages */);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null),
@@ -150,9 +154,45 @@ public class BroadcastHelperTest {
assertThat(intent.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
}
+ @RequiresFlagsEnabled(FLAG_REDUCE_BROADCASTS_FOR_COMPONENT_STATE_CHANGES)
+ @Test
+ public void changeNonExportedComponent_sendPackageChangedBroadcastToSharedUserIdApplications()
+ throws Exception {
+ changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
+ new String[]{"shared.package"} /* sharedPackages */);
+
+ ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
+ ArgumentCaptor<String[]> captorRequiredPermissions = ArgumentCaptor.forClass(
+ String[].class);
+ verify(mMockActivityManagerInternal, times(3)).broadcastIntentWithCallback(
+ captorIntent.capture(), eq(null), captorRequiredPermissions.capture(), anyInt(),
+ eq(null), eq(null), eq(null));
+ List<Intent> intents = captorIntent.getAllValues();
+ List<String[]> requiredPermissions = captorRequiredPermissions.getAllValues();
+ assertNotNull(intents);
+ assertThat(intents.size()).isEqualTo(3);
+
+ final Intent intent1 = intents.get(0);
+ final String[] requiredPermission1 = requiredPermissions.get(0);
+ assertThat(intent1.getPackage()).isEqualTo("android");
+ assertThat(requiredPermission1).isEqualTo(
+ new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
+
+ final Intent intent2 = intents.get(1);
+ final String[] requiredPermission2 = requiredPermissions.get(1);
+ assertThat(intent2.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
+ assertThat(requiredPermission2).isNull();
+
+ final Intent intent3 = intents.get(2);
+ final String[] requiredPermission3 = requiredPermissions.get(2);
+ assertThat(intent3.getPackage()).isEqualTo("shared.package");
+ assertThat(requiredPermission3).isNull();
+ }
+
@Test
public void changeExportedComponent_sendPackageChangedBroadcastToAll() throws Exception {
- changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */);
+ changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */,
+ new String[0] /* sharedPackages */);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null),
@@ -162,11 +202,14 @@ public class BroadcastHelperTest {
assertNull(intent.getPackage());
}
- private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent) {
+ private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent,
+ String[] sharedPackages) {
when(mMockSnapshot.getPackageStateInternal(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME),
anyInt())).thenReturn(mMockPackageStateInternal);
when(mMockSnapshot.isInstantAppInternal(any(), anyInt(), anyInt())).thenReturn(false);
when(mMockSnapshot.getVisibilityAllowLists(any(), any())).thenReturn(null);
+ when(mMockSnapshot.getSharedUserPackagesForPackage(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME),
+ anyInt())).thenReturn(sharedPackages);
when(mMockPackageStateInternal.getPkg()).thenReturn(mMockAndroidPackageInternal);
when(mMockParsedActivity.getClassName()).thenReturn(
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
index 5a59c57ddf28..14dce103fc90 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
@@ -21,8 +21,6 @@ import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DEFAULT
import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DENIED
import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
-import android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED
-import android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_OPEN
import android.content.pm.PackageManager
import android.content.pm.verify.domain.DomainSet
import android.os.Parcel
@@ -32,14 +30,8 @@ import android.util.AtomicFile
import android.util.Slog
import android.util.Xml
import com.android.internal.os.BackgroundThread
-import com.android.server.pm.verify.pkg.VerifierController
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
-import java.io.File
-import java.io.FileInputStream
-import java.io.FileNotFoundException
-import java.io.FileOutputStream
-import java.io.IOException
import libcore.io.IoUtils
import org.junit.Before
import org.junit.Rule
@@ -53,6 +45,11 @@ import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileNotFoundException
+import java.io.FileOutputStream
+import java.io.IOException
@Presubmit
class PackageInstallerSessionTest {
@@ -199,9 +196,6 @@ class PackageInstallerSessionTest {
/* stagedSessionErrorCode */ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
/* stagedSessionErrorMessage */ "some error",
/* preVerifiedDomains */ DomainSet(setOf("com.foo", "com.bar")),
- /* VerifierController */ mock(VerifierController::class.java),
- /* initialVerificationPolicy */ VERIFICATION_POLICY_BLOCK_FAIL_OPEN,
- /* currentVerificationPolicy */ VERIFICATION_POLICY_BLOCK_FAIL_CLOSED,
/* installDependencyHelper */ null
)
}
@@ -257,7 +251,6 @@ class PackageInstallerSessionTest {
mTmpDir,
mock(PackageSessionProvider::class.java),
mock(SilentUpdatePolicy::class.java),
- mock(VerifierController::class.java),
mock(InstallDependencyHelper::class.java)
)
ret.add(session)
@@ -295,7 +288,6 @@ class PackageInstallerSessionTest {
assertThat(expected.installerPackageName).isEqualTo(actual.installerPackageName)
assertThat(expected.isMultiPackage).isEqualTo(actual.isMultiPackage)
assertThat(expected.isStaged).isEqualTo(actual.isStaged)
- assertThat(expected.forceVerification).isEqualTo(actual.forceVerification)
}
private fun assertEquals(
@@ -346,8 +338,6 @@ class PackageInstallerSessionTest {
assertThat(expected.childSessionIds).asList()
.containsExactlyElementsIn(actual.childSessionIds.toList())
assertThat(expected.preVerifiedDomains).isEqualTo(actual.preVerifiedDomains)
- assertThat(expected.initialVerificationPolicy).isEqualTo(actual.initialVerificationPolicy)
- assertThat(expected.currentVerificationPolicy).isEqualTo(actual.currentVerificationPolicy)
}
private fun assertInstallSourcesEquivalent(expected: InstallSource, actual: InstallSource) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index 5da202f109d4..f5c0de034483 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -20,6 +20,7 @@ import static android.content.UriRelativeFilter.QUERY;
import static android.content.UriRelativeFilter.FRAGMENT;
import static android.content.UriRelativeFilterGroup.ACTION_ALLOW;
import static android.content.UriRelativeFilterGroup.ACTION_BLOCK;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS;
import static android.os.PatternMatcher.PATTERN_ADVANCED_GLOB;
import static android.os.PatternMatcher.PATTERN_LITERAL;
import static android.os.PatternMatcher.PATTERN_PREFIX;
@@ -111,6 +112,8 @@ import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageUserStateInternal;
+import com.google.android.collect.Sets;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -212,6 +215,30 @@ public class PackageParserTest {
}
@Test
+ public void testParse_withCache_hiddenApiAllowlist() throws Exception {
+ CachePackageNameParser pp = new CachePackageNameParser(null);
+
+ pp.setCacheDir(mTmpDir);
+ // The first parse will write this package to the cache.
+ pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+
+ // Now attempt to parse the package again, should return the
+ // cached result.
+ ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+ true /* useCaches */);
+ assertEquals("cache_android", pkg.getPackageName());
+
+ // Create application info
+ pkg.hideAsFinal();
+ ApplicationInfo aInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0,
+ PackageUserStateInternal.DEFAULT, 0, mockPkgSetting(pkg));
+
+ // verify ext flag for hidden APIs allowlist
+ assertEquals(PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS,
+ aInfo.privateFlagsExt & PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS);
+ }
+
+ @Test
public void test_serializePackage() throws Exception {
try (PackageParser2 pp = PackageParserUtils.forParsingFileWithDefaults()) {
AndroidPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
@@ -856,35 +883,37 @@ public class PackageParserTest {
*/
public static class CachePackageNameParser extends PackageParser2 {
- CachePackageNameParser(@Nullable File cacheDir) {
- super(null, null, null, new Callback() {
- @Override
- public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
- return true;
- }
+ private static final Callback CALLBACK = new Callback() {
+ @Override
+ public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
+ return true;
+ }
- @Override
- public boolean hasFeature(String feature) {
- return false;
- }
+ @Override
+ public boolean hasFeature(String feature) {
+ return false;
+ }
- @Override
- public Set<String> getHiddenApiWhitelistedApps() {
- return new ArraySet<>();
- }
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return Sets.newArraySet("cache_android");
+ }
- @Override
- public Set<String> getInstallConstraintsAllowlist() {
- return new ArraySet<>();
- }
- });
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return new ArraySet<>();
+ }
+ };
+
+ CachePackageNameParser(@Nullable File cacheDir) {
+ super(null, null, null, CALLBACK);
if (cacheDir != null) {
setCacheDir(cacheDir);
}
}
void setCacheDir(@NonNull File cacheDir) {
- this.mCacher = new PackageCacher(cacheDir) {
+ this.mCacher = new PackageCacher(cacheDir, CALLBACK) {
@Override
public ParsedPackage fromCacheEntry(byte[] cacheEntry) {
ParsedPackage parsed = super.fromCacheEntry(cacheEntry);
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerificationStatusTrackerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerificationStatusTrackerTest.java
deleted file mode 100644
index 787fb5a4e524..000000000000
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerificationStatusTrackerTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2024 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.verify.pkg;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.concurrent.TimeUnit;
-
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VerificationStatusTrackerTest {
- private static final String TEST_PACKAGE_NAME = "com.foo";
- private static final long TEST_REQUEST_START_TIME = 100L;
- private static final long TEST_TIMEOUT_DURATION_MILLIS = TimeUnit.MINUTES.toMillis(1);
- private static final long TEST_TIMEOUT_EXTENDED_MILLIS = TimeUnit.MINUTES.toMillis(2);
- private static final long TEST_MAX_TIMEOUT_DURATION_MILLIS =
- TimeUnit.MINUTES.toMillis(10);
-
- @Mock
- VerifierController.Injector mInjector;
- private VerificationStatusTracker mTracker;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mInjector.getVerificationRequestTimeoutMillis()).thenReturn(
- TEST_TIMEOUT_DURATION_MILLIS);
- when(mInjector.getMaxVerificationExtendedTimeoutMillis()).thenReturn(
- TEST_MAX_TIMEOUT_DURATION_MILLIS);
- // Mock time forward as the code continues to check for the current time
- when(mInjector.getCurrentTimeMillis())
- .thenReturn(TEST_REQUEST_START_TIME)
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS - 1)
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS)
- .thenReturn(TEST_REQUEST_START_TIME + TEST_MAX_TIMEOUT_DURATION_MILLIS - 100)
- .thenReturn(TEST_REQUEST_START_TIME + TEST_MAX_TIMEOUT_DURATION_MILLIS);
- mTracker = new VerificationStatusTracker(TEST_TIMEOUT_DURATION_MILLIS,
- TEST_MAX_TIMEOUT_DURATION_MILLIS, mInjector);
- }
-
- @Test
- public void testTimeout() {
- assertThat(mTracker.getTimeoutTime()).isEqualTo(
- TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS);
- // It takes two calls to set the timeout, because the timeout time hasn't been reached for
- // the first calls
- assertThat(mTracker.isTimeout()).isFalse();
- assertThat(mTracker.isTimeout()).isTrue();
- }
-
- @Test
- public void testTimeoutExtended() {
- assertThat(mTracker.getTimeoutTime()).isEqualTo(
- TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS);
- assertThat(mTracker.extendTimeRemaining(TEST_TIMEOUT_EXTENDED_MILLIS))
- .isEqualTo(TEST_TIMEOUT_EXTENDED_MILLIS);
- assertThat(mTracker.getTimeoutTime()).isEqualTo(
- TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS
- + TEST_TIMEOUT_EXTENDED_MILLIS);
-
- // It would take 3 calls to set the timeout, because the timeout time hasn't been reached
- // for the first 2 time checks, but querying the remaining time also does a time check.
- assertThat(mTracker.isTimeout()).isFalse();
- assertThat(mTracker.getRemainingTime()).isGreaterThan(0);
- assertThat(mTracker.isTimeout()).isTrue();
- assertThat(mTracker.getRemainingTime()).isEqualTo(0);
- }
-
- @Test
- public void testTimeoutExtendedExceedsMax() {
- assertThat(mTracker.getTimeoutTime()).isEqualTo(
- TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS);
- assertThat(mTracker.extendTimeRemaining(TEST_MAX_TIMEOUT_DURATION_MILLIS))
- .isEqualTo(TEST_MAX_TIMEOUT_DURATION_MILLIS - TEST_TIMEOUT_DURATION_MILLIS);
- assertThat(mTracker.getTimeoutTime()).isEqualTo(
- TEST_REQUEST_START_TIME + TEST_MAX_TIMEOUT_DURATION_MILLIS);
- // It takes 4 calls to set the timeout, because the timeout time hasn't been reached for
- // the first 3 calls
- assertThat(mTracker.isTimeout()).isFalse();
- assertThat(mTracker.isTimeout()).isFalse();
- assertThat(mTracker.isTimeout()).isFalse();
- assertThat(mTracker.isTimeout()).isTrue();
- assertThat(mTracker.getRemainingTime()).isEqualTo(0);
- }
-}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java
deleted file mode 100644
index 3046d4beb7a3..000000000000
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright (C) 2024 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.verify.pkg;
-
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
-import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_OPEN;
-
-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.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningInfo;
-import android.content.pm.VersionedPackage;
-import android.content.pm.verify.pkg.IVerifierService;
-import android.content.pm.verify.pkg.VerificationSession;
-import android.content.pm.verify.pkg.VerificationStatus;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PersistableBundle;
-import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.infra.ServiceConnector;
-import com.android.server.pm.Computer;
-import com.android.server.pm.PackageInstallerSession;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VerifierControllerTest {
- private static final int TEST_ID = 100;
- private static final String TEST_PACKAGE_NAME = "com.foo";
- private static final ComponentName TEST_VERIFIER_COMPONENT_NAME =
- new ComponentName("com.verifier", "com.verifier.Service");
- private static final Uri TEST_PACKAGE_URI = Uri.parse("test://test");
- private static final SigningInfo TEST_SIGNING_INFO = new SigningInfo();
- private static final SharedLibraryInfo TEST_SHARED_LIBRARY_INFO1 =
- new SharedLibraryInfo("sharedLibPath1", TEST_PACKAGE_NAME,
- Collections.singletonList("path1"), "sharedLib1", 101,
- SharedLibraryInfo.TYPE_DYNAMIC, new VersionedPackage(TEST_PACKAGE_NAME, 1),
- null, null, false);
- private static final SharedLibraryInfo TEST_SHARED_LIBRARY_INFO2 =
- new SharedLibraryInfo("sharedLibPath2", TEST_PACKAGE_NAME,
- Collections.singletonList("path2"), "sharedLib2", 102,
- SharedLibraryInfo.TYPE_DYNAMIC,
- new VersionedPackage(TEST_PACKAGE_NAME, 2), null, null, false);
- private static final String TEST_KEY = "test key";
- private static final String TEST_VALUE = "test value";
- private static final String TEST_FAILURE_MESSAGE = "verification failed!";
- private static final long TEST_REQUEST_START_TIME = 0L;
- private static final long TEST_TIMEOUT_DURATION_MILLIS = TimeUnit.MINUTES.toMillis(1);
- private static final long TEST_MAX_TIMEOUT_DURATION_MILLIS =
- TimeUnit.MINUTES.toMillis(10);
- private static final long TEST_VERIFIER_CONNECTION_TIMEOUT_DURATION_MILLIS =
- TimeUnit.SECONDS.toMillis(10);
- private static final int TEST_POLICY = VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
-
- private final ArrayList<SharedLibraryInfo> mTestDeclaredLibraries = new ArrayList<>();
- private final PersistableBundle mTestExtensionParams = new PersistableBundle();
- @Mock
- Context mContext;
- @Mock
- Handler mHandler;
- @Mock
- VerifierController.Injector mInjector;
- @Mock
- ServiceConnector<IVerifierService> mMockServiceConnector;
- @Mock
- IVerifierService mMockService;
- @Mock
- Computer mSnapshot;
- Supplier<Computer> mSnapshotSupplier = () -> mSnapshot;
- @Mock
- PackageInstallerSession.VerifierCallback mSessionCallback;
-
- private VerifierController mVerifierController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- // Mock that the UID of this test becomes the UID of the verifier
- when(mSnapshot.getPackageUidInternal(anyString(), anyLong(), anyInt(), anyInt()))
- .thenReturn(InstrumentationRegistry.getInstrumentation().getContext()
- .getApplicationInfo().uid);
- when(mInjector.getVerifierPackageName(any(Computer.class), anyInt())).thenReturn(
- TEST_VERIFIER_COMPONENT_NAME.getPackageName());
- when(mInjector.getRemoteService(
- any(Computer.class), any(Context.class), anyInt(), any(Handler.class)
- )).thenReturn(new Pair<>(mMockServiceConnector, TEST_VERIFIER_COMPONENT_NAME));
- when(mInjector.getVerificationRequestTimeoutMillis()).thenReturn(
- TEST_TIMEOUT_DURATION_MILLIS);
- when(mInjector.getMaxVerificationExtendedTimeoutMillis()).thenReturn(
- TEST_MAX_TIMEOUT_DURATION_MILLIS);
- when(mInjector.getVerifierConnectionTimeoutMillis()).thenReturn(
- TEST_VERIFIER_CONNECTION_TIMEOUT_DURATION_MILLIS
- );
- // Mock time forward as the code continues to check for the current time
- when(mInjector.getCurrentTimeMillis())
- .thenReturn(TEST_REQUEST_START_TIME)
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS + 1);
- when(mMockServiceConnector.post(any(ServiceConnector.VoidJob.class)))
- .thenAnswer(
- i -> {
- ((ServiceConnector.VoidJob) i.getArguments()[0]).run(mMockService);
- return new AndroidFuture<>();
- });
- when(mMockServiceConnector.run(any(ServiceConnector.VoidJob.class)))
- .thenAnswer(
- i -> {
- ((ServiceConnector.VoidJob) i.getArguments()[0]).run(mMockService);
- return true;
- });
-
- mTestDeclaredLibraries.add(TEST_SHARED_LIBRARY_INFO1);
- mTestDeclaredLibraries.add(TEST_SHARED_LIBRARY_INFO2);
- mTestExtensionParams.putString(TEST_KEY, TEST_VALUE);
-
- mVerifierController = new VerifierController(mContext, mHandler, mInjector);
- }
-
- @Test
- public void testVerifierNotInstalled() {
- when(mInjector.getVerifierPackageName(any(Computer.class), anyInt())).thenReturn(null);
- when(mInjector.getRemoteService(
- any(Computer.class), any(Context.class), anyInt(), any(Handler.class)
- )).thenReturn(null);
- assertThat(mVerifierController.getVerifierPackageName(mSnapshotSupplier, 0)).isNull();
- assertThat(mVerifierController.bindToVerifierServiceIfNeeded(mSnapshotSupplier, 0))
- .isFalse();
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isFalse();
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ true)).isFalse();
- verifyZeroInteractions(mSessionCallback);
- }
-
- @Test
- public void testRebindService() {
- assertThat(mVerifierController.bindToVerifierServiceIfNeeded(mSnapshotSupplier, 0))
- .isTrue();
- }
-
- @Test
- public void testVerifierAvailableButNotConnected() {
- assertThat(mVerifierController.getVerifierPackageName(mSnapshotSupplier, 0)).isNotNull();
- when(mInjector.getRemoteService(
- any(Computer.class), any(Context.class), anyInt(), any(Handler.class)
- )).thenReturn(null);
- assertThat(mVerifierController.bindToVerifierServiceIfNeeded(mSnapshotSupplier, 0))
- .isFalse();
- // Test that nothing crashes if the verifier is available even though there's no bound
- mVerifierController.notifyPackageNameAvailable(TEST_PACKAGE_NAME);
- mVerifierController.notifyVerificationCancelled(TEST_PACKAGE_NAME);
- mVerifierController.notifyVerificationTimeout(-1);
- // Since there was no bound, no call is made to the verifier
- verifyZeroInteractions(mMockService);
- }
-
- @Test
- public void testUnbindService() throws Exception {
- ArgumentCaptor<ServiceConnector.ServiceLifecycleCallbacks> captor = ArgumentCaptor.forClass(
- ServiceConnector.ServiceLifecycleCallbacks.class);
- assertThat(mVerifierController.bindToVerifierServiceIfNeeded(mSnapshotSupplier, 0))
- .isTrue();
- verify(mMockServiceConnector).setServiceLifecycleCallbacks(captor.capture());
- ServiceConnector.ServiceLifecycleCallbacks<IVerifierService> callbacks = captor.getValue();
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mMockService, times(1)).onVerificationRequired(any(VerificationSession.class));
- callbacks.onBinderDied();
- // Test that nothing crashes if the service connection is lost
- assertThat(mVerifierController.getVerifierPackageName(mSnapshotSupplier, 0)).isNotNull();
- mVerifierController.notifyPackageNameAvailable(TEST_PACKAGE_NAME);
- mVerifierController.notifyVerificationCancelled(TEST_PACKAGE_NAME);
- mVerifierController.notifyVerificationTimeout(TEST_ID);
- verifyNoMoreInteractions(mMockService);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ true)).isTrue();
- mVerifierController.notifyVerificationTimeout(TEST_ID);
- verify(mMockService, times(1)).onVerificationTimeout(eq(TEST_ID));
- }
-
- @Test
- public void testNotifyPackageNameAvailable() throws Exception {
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- mVerifierController.notifyPackageNameAvailable(TEST_PACKAGE_NAME);
- verify(mMockService).onPackageNameAvailable(eq(TEST_PACKAGE_NAME));
- }
-
- @Test
- public void testNotifyVerificationCancelled() throws Exception {
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- mVerifierController.notifyVerificationCancelled(TEST_PACKAGE_NAME);
- verify(mMockService).onVerificationCancelled(eq(TEST_PACKAGE_NAME));
- }
-
- @Test
- public void testStartVerificationSession() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- assertThat(session.getId()).isEqualTo(TEST_ID);
- assertThat(session.getInstallSessionId()).isEqualTo(TEST_ID);
- assertThat(session.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
- assertThat(session.getStagedPackageUri()).isEqualTo(TEST_PACKAGE_URI);
- assertThat(session.getSigningInfo().getSigningDetails())
- .isEqualTo(TEST_SIGNING_INFO.getSigningDetails());
- List<SharedLibraryInfo> declaredLibraries = session.getDeclaredLibraries();
- // SharedLibraryInfo doesn't have a "equals" method, so we have to check it indirectly
- assertThat(declaredLibraries.getFirst().toString())
- .isEqualTo(TEST_SHARED_LIBRARY_INFO1.toString());
- assertThat(declaredLibraries.get(1).toString())
- .isEqualTo(TEST_SHARED_LIBRARY_INFO2.toString());
- // We can't directly test with PersistableBundle.equals() because the parceled bundle's
- // structure is different, but all the key/value pairs should be preserved as before.
- assertThat(session.getExtensionParams().getString(TEST_KEY))
- .isEqualTo(mTestExtensionParams.getString(TEST_KEY));
- }
-
- @Test
- public void testNotifyVerificationRetry() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ true)).isTrue();
- verify(mMockService).onVerificationRetry(captor.capture());
- VerificationSession session = captor.getValue();
- assertThat(session.getId()).isEqualTo(TEST_ID);
- assertThat(session.getInstallSessionId()).isEqualTo(TEST_ID);
- assertThat(session.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
- assertThat(session.getStagedPackageUri()).isEqualTo(TEST_PACKAGE_URI);
- assertThat(session.getSigningInfo().getSigningDetails())
- .isEqualTo(TEST_SIGNING_INFO.getSigningDetails());
- List<SharedLibraryInfo> declaredLibraries = session.getDeclaredLibraries();
- // SharedLibraryInfo doesn't have a "equals" method, so we have to check it indirectly
- assertThat(declaredLibraries.getFirst().toString())
- .isEqualTo(TEST_SHARED_LIBRARY_INFO1.toString());
- assertThat(declaredLibraries.get(1).toString())
- .isEqualTo(TEST_SHARED_LIBRARY_INFO2.toString());
- // We can't directly test with PersistableBundle.equals() because the parceled bundle's
- // structure is different, but all the key/value pairs should be preserved as before.
- assertThat(session.getExtensionParams().getString(TEST_KEY))
- .isEqualTo(mTestExtensionParams.getString(TEST_KEY));
- }
-
- @Test
- public void testNotifyVerificationTimeout() throws Exception {
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ true)).isTrue();
- mVerifierController.notifyVerificationTimeout(TEST_ID);
- verify(mMockService).onVerificationTimeout(eq(TEST_ID));
- }
-
- @Test
- public void testRequestTimeout() {
- // Let the mock handler set request to TIMEOUT, immediately after the request is sent.
- // We can't mock postDelayed because it's final, but we can mock the method it calls.
- when(mHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
- i -> {
- ((Message) i.getArguments()[0]).getCallback().run();
- return true;
- });
- ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong());
- verify(mSessionCallback, times(1)).onTimeout();
- verify(mInjector, times(2)).getCurrentTimeMillis();
- verify(mInjector, times(1)).stopTimeoutCountdown(eq(mHandler), any());
- }
-
- @Test
- public void testRequestTimeoutWithRetryPass() throws Exception {
- // Only let the first request timeout and let the second one pass
- when(mHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
- i -> {
- ((Message) i.getArguments()[0]).getCallback().run();
- return true;
- })
- .thenAnswer(i -> true);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong());
- verify(mSessionCallback, times(1)).onTimeout();
- verify(mInjector, times(2)).getCurrentTimeMillis();
- verify(mInjector, times(1)).stopTimeoutCountdown(eq(mHandler), any());
- // Then retry
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ true)).isTrue();
- verify(mMockService).onVerificationRetry(captor.capture());
- VerificationSession session = captor.getValue();
- VerificationStatus status = new VerificationStatus.Builder().setVerified(true).build();
- session.reportVerificationComplete(status);
- verify(mSessionCallback, times(1)).onVerificationCompleteReceived(
- eq(status), eq(null));
- verify(mInjector, times(2)).stopTimeoutCountdown(eq(mHandler), any());
- }
-
- @Test
- public void testRequestIncomplete() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- session.reportVerificationIncomplete(VerificationSession.VERIFICATION_INCOMPLETE_UNKNOWN);
- verify(mSessionCallback, times(1)).onVerificationIncompleteReceived(
- eq(VerificationSession.VERIFICATION_INCOMPLETE_UNKNOWN));
- verify(mInjector, times(1)).stopTimeoutCountdown(eq(mHandler), any());
- }
-
- @Test
- public void testRequestCompleteWithSuccessWithExtensionResponse() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- VerificationStatus status = new VerificationStatus.Builder().setVerified(true).build();
- PersistableBundle bundle = new PersistableBundle();
- session.reportVerificationComplete(status, bundle);
- verify(mSessionCallback, times(1)).onVerificationCompleteReceived(
- eq(status), eq(bundle));
- verify(mInjector, times(1)).stopTimeoutCountdown(eq(mHandler), any());
- }
-
- @Test
- public void testRequestCompleteWithFailure() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- VerificationStatus status = new VerificationStatus.Builder()
- .setVerified(false)
- .setFailureMessage(TEST_FAILURE_MESSAGE)
- .build();
- session.reportVerificationComplete(status);
- verify(mSessionCallback, times(1)).onVerificationCompleteReceived(
- eq(status), eq(null));
- verify(mInjector, times(1)).stopTimeoutCountdown(eq(mHandler), any());
- }
-
- @Test
- public void testRepeatedRequestCompleteShouldThrow() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- assertThat(mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false)).isTrue();
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- VerificationStatus status = new VerificationStatus.Builder().setVerified(true).build();
- session.reportVerificationComplete(status);
- // getters should throw after the report
- expectThrows(IllegalStateException.class, () -> session.getTimeoutTime());
- // Report again should fail with exception
- expectThrows(IllegalStateException.class, () -> session.reportVerificationComplete(status));
- }
-
- @Test
- public void testExtendTimeRemaining() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false);
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- final long initialTimeoutTime = TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS;
- assertThat(session.getTimeoutTime()).isEqualTo(initialTimeoutTime);
- final long extendTimeMillis = TEST_TIMEOUT_DURATION_MILLIS;
- assertThat(session.extendTimeRemaining(extendTimeMillis)).isEqualTo(extendTimeMillis);
- assertThat(session.getTimeoutTime()).isEqualTo(initialTimeoutTime + extendTimeMillis);
- }
-
- @Test
- public void testExtendTimeExceedsMax() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false);
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- final long initialTimeoutTime = TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS;
- final long maxTimeoutTime = TEST_REQUEST_START_TIME + TEST_MAX_TIMEOUT_DURATION_MILLIS;
- assertThat(session.getTimeoutTime()).isEqualTo(initialTimeoutTime);
- final long extendTimeMillis = TEST_MAX_TIMEOUT_DURATION_MILLIS;
- assertThat(session.extendTimeRemaining(extendTimeMillis)).isEqualTo(
- TEST_MAX_TIMEOUT_DURATION_MILLIS - TEST_TIMEOUT_DURATION_MILLIS);
- assertThat(session.getTimeoutTime()).isEqualTo(maxTimeoutTime);
- }
-
- @Test
- public void testTimeoutChecksMultipleTimes() {
- // Mock message handling
- when(mHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
- i -> {
- ((Message) i.getArguments()[0]).getCallback().run();
- return true;
- });
- // Mock time forward as the code continues to check for the current time
- when(mInjector.getCurrentTimeMillis())
- // First called when the tracker is created
- .thenReturn(TEST_REQUEST_START_TIME)
- // Then mock the first timeout check when the timeout time isn't reached yet
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS - 1000)
- // Then mock the same time used to check the remaining time
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS - 1000)
- // Then mock the second timeout check when the timeout time isn't reached yet
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS - 100)
- // Then mock the same time used to check the remaining time
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS - 100)
- // Then mock the third timeout check when the timeout time has been reached
- .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS + 1);
- mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false);
- verify(mHandler, times(3)).sendMessageAtTime(any(Message.class), anyLong());
- verify(mInjector, times(6)).getCurrentTimeMillis();
- verify(mSessionCallback, times(1)).onTimeout();
- }
-
- @Test
- public void testPolicyOverride() throws Exception {
- ArgumentCaptor<VerificationSession> captor =
- ArgumentCaptor.forClass(VerificationSession.class);
- mVerifierController.startVerificationSession(
- mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI,
- TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams,
- mSessionCallback, /* retry= */ false);
- verify(mMockService).onVerificationRequired(captor.capture());
- VerificationSession session = captor.getValue();
- final int policy = VERIFICATION_POLICY_BLOCK_FAIL_OPEN;
- when(mSessionCallback.setVerificationPolicy(eq(policy))).thenReturn(true);
- assertThat(session.setVerificationPolicy(policy)).isTrue();
- assertThat(session.getVerificationPolicy()).isEqualTo(policy);
- verify(mSessionCallback, times(1)).setVerificationPolicy(eq(policy));
- }
-}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 69714f3ecb5b..3fdb53f5ab59 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -582,6 +582,34 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
PackageImpl::setSystemExt,
true
),
+ getSetByValue(
+ AndroidPackage::getAlternateLauncherIconResIds,
+ PackageImpl::setAlternateLauncherIconResIds,
+ intArrayOf(3, 5, 7),
+ compare = { first, second ->
+ equalBy(
+ first, second,
+ { it.size },
+ { it[0] },
+ { it[1] },
+ { it[2] }
+ )
+ }
+ ),
+ getSetByValue(
+ AndroidPackage::getAlternateLauncherLabelResIds,
+ PackageImpl::setAlternateLauncherLabelResIds,
+ intArrayOf(3, 5, 7),
+ compare = { first, second ->
+ equalBy(
+ first, second,
+ { it.size },
+ { it[0] },
+ { it[1] },
+ { it[2] }
+ )
+ }
+ ),
)
override fun initialObject() = PackageImpl.forParsing(
diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
index 08155c7b3f98..9772ef929eae 100644
--- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
+++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
@@ -2380,10 +2380,14 @@ public class VpnTest extends VpnTestBase {
@Test
public void doTestMigrateIkeSession_Vcn() throws Exception {
final int expectedKeepalive = 2097; // Any unlikely number will do
- final NetworkCapabilities vcnNc = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .setTransportInfo(new VcnTransportInfo(TEST_SUB_ID, expectedKeepalive))
- .build();
+ final NetworkCapabilities vcnNc =
+ new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .setTransportInfo(
+ new VcnTransportInfo.Builder()
+ .setMinUdpPort4500NatTimeoutSeconds(expectedKeepalive)
+ .build())
+ .build();
final Ikev2VpnProfile ikev2VpnProfile = makeIkeV2VpnProfile(
true /* isAutomaticIpVersionSelectionEnabled */,
true /* isAutomaticNattKeepaliveTimerEnabled */,
diff --git a/services/tests/apexsystemservices/services/Android.bp b/services/tests/apexsystemservices/services/Android.bp
index 477ea4cdad37..70d84dcf6007 100644
--- a/services/tests/apexsystemservices/services/Android.bp
+++ b/services/tests/apexsystemservices/services/Android.bp
@@ -17,4 +17,5 @@ java_library {
],
visibility: ["//frameworks/base/services/tests/apexsystemservices:__subpackages__"],
apex_available: ["//apex_available:anyapex"],
+ compile_dex: true,
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 312df4391e2d..0e9dfedac0c9 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -1118,7 +1118,8 @@ public class AutomaticBrightnessControllerTest {
@Test
public void testAutoBrightnessInDoze_useNormalBrightnessForDozeFalse_scaleScreenOn()
throws Exception {
- when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)).thenReturn(
+ true);
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
@@ -1154,7 +1155,8 @@ public class AutomaticBrightnessControllerTest {
@Test
public void testAutoBrightnessInDoze_useNormalBrightnessForDozeTrue_notScaleScreenOn()
throws Exception {
- when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)).thenReturn(
+ true);
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 80e5ee39c13d..47e96d378149 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
+import static android.Manifest.permission.ADD_MIRROR_DISPLAY;
import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
@@ -122,6 +123,7 @@ import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserManager;
import android.os.test.FakePermissionEnforcer;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -226,6 +228,9 @@ public class DisplayManagerServiceTest {
"EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED";
private static final String EVENT_DISPLAY_CONNECTED = "EVENT_DISPLAY_CONNECTED";
private static final String EVENT_DISPLAY_DISCONNECTED = "EVENT_DISPLAY_DISCONNECTED";
+ private static final String EVENT_DISPLAY_REFRESH_RATE_CHANGED =
+ "EVENT_DISPLAY_REFRESH_RATE_CHANGED";
+ private static final String EVENT_DISPLAY_STATE_CHANGED = "EVENT_DISPLAY_STATE_CHANGED";
private static final String DISPLAY_GROUP_EVENT_ADDED = "DISPLAY_GROUP_EVENT_ADDED";
private static final String DISPLAY_GROUP_EVENT_REMOVED = "DISPLAY_GROUP_EVENT_REMOVED";
private static final String DISPLAY_GROUP_EVENT_CHANGED = "DISPLAY_GROUP_EVENT_CHANGED";
@@ -1385,6 +1390,7 @@ public class DisplayManagerServiceTest {
* Tests that it's not allowed to create an auto-mirror virtual display without
* CAPTURE_VIDEO_OUTPUT permission or a virtual device that can mirror displays
*/
+ @EnableFlags(android.companion.virtualdevice.flags.Flags.FLAG_ENABLE_LIMITED_VDM_ROLE)
@Test
public void createAutoMirrorDisplay_withoutPermissionOrAllowedVirtualDevice_throwsException()
throws Exception {
@@ -1394,7 +1400,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
- when(virtualDevice.canCreateMirrorDisplays()).thenReturn(false);
+ when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
when(mContext.checkCallingPermission(CAPTURE_VIDEO_OUTPUT)).thenReturn(
PackageManager.PERMISSION_DENIED);
@@ -1425,7 +1432,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
- when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+ when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create an auto-mirror virtual display using a virtual device.
@@ -1458,7 +1466,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
- when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+ when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create an auto-mirror virtual display using a virtual device.
@@ -1525,7 +1534,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
- when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+ when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
when(mContext.checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY))
.thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -1561,7 +1571,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
- when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+ when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create an auto-mirror virtual display using a virtual device.
@@ -4234,6 +4245,10 @@ public class DisplayManagerServiceTest {
return EVENT_DISPLAY_CONNECTED;
case DisplayManagerGlobal.EVENT_DISPLAY_DISCONNECTED:
return EVENT_DISPLAY_DISCONNECTED;
+ case DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+ return EVENT_DISPLAY_REFRESH_RATE_CHANGED;
+ case DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED:
+ return EVENT_DISPLAY_STATE_CHANGED;
default:
return "UNKNOWN: " + eventType;
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index e64d9855bc54..91f1aaf603e6 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -121,8 +121,8 @@ public final class DisplayPowerControllerTest {
private static final float PROX_SENSOR_MAX_RANGE = 5;
private static final float DOZE_SCALE_FACTOR = 0.34f;
private static final float DEFAULT_DOZE_BRIGHTNESS = 0.121f;
+ private static final float OVERRIDE_BRIGHTNESS = 0.567f;
- private static final float BRIGHTNESS_RAMP_RATE_MINIMUM = 0.0f;
private static final float BRIGHTNESS_RAMP_RATE_FAST_DECREASE = 0.3f;
private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
@@ -2119,7 +2119,8 @@ public final class DisplayPowerControllerTest {
@Test
public void testManualBrightness_stateOnPolicyDozeUseNormalBrightnessForDozeFalse_brightnessDoze() {
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlagsMock.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true);
+ when(mDisplayManagerFlagsMock.isNormalBrightnessForDozeParameterEnabled(
+ mContext)).thenReturn(true);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
@@ -2154,7 +2155,8 @@ public final class DisplayPowerControllerTest {
@Test
public void testManualBrightness_stateOnPolicyDozeUseNormalBrightnessForDozeTrue_brightnessNormal() {
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlagsMock.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true);
+ when(mDisplayManagerFlagsMock.isNormalBrightnessForDozeParameterEnabled(
+ mContext)).thenReturn(true);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
@@ -2188,7 +2190,8 @@ public final class DisplayPowerControllerTest {
@Test
public void testManualBrightness_stateDozePolicyOnUseNormalBrightnessForDozeTrue_brightnessDoze() {
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlagsMock.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true);
+ when(mDisplayManagerFlagsMock.isNormalBrightnessForDozeParameterEnabled(
+ mContext)).thenReturn(true);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
@@ -2438,6 +2441,36 @@ public final class DisplayPowerControllerTest {
any(BrightnessEvent.class));
}
+ @Test
+ public void brightnessOverrideInPowerRequest_enablesOverrideBrightnessStrategy() {
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.screenBrightnessOverride = OVERRIDE_BRIGHTNESS;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.animator).animateTo(eq(OVERRIDE_BRIGHTNESS), anyFloat(), anyFloat(),
+ eq(false));
+ }
+
+ @Test
+ public void brightnessOverrideRequest_enablesOverrideBrightnessStrategy() {
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ var dbor = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+ dbor.brightness = OVERRIDE_BRIGHTNESS;
+ mHolder.dpc.setBrightnessOverrideRequest(dbor);
+ advanceTime(1); // Process the WM brightness override request
+
+ verify(mHolder.animator).animateTo(eq(OVERRIDE_BRIGHTNESS), anyFloat(), anyFloat(),
+ eq(false));
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index b6da3ae6a5cd..ad30f22fe060 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+import static android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import static android.view.Display.FLAG_REAR;
@@ -35,7 +36,9 @@ import static com.android.server.display.DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DE
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CONNECTED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DISCONNECTED;
+import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED;
+import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_STATE_CHANGED;
import static com.android.server.display.layout.Layout.Display.POSITION_REAR;
import static com.android.server.display.layout.Layout.Display.POSITION_UNKNOWN;
import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SELECTIVE_STAY_AWAKE;
@@ -75,6 +78,9 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.test.TestLooper;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayInfo;
@@ -142,6 +148,9 @@ public class LogicalDisplayMapperTest {
@Rule
public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock LogicalDisplayMapper.Listener mListenerMock;
@Mock Context mContextMock;
@@ -689,6 +698,7 @@ public class LogicalDisplayMapperTest {
}
@Test
+ @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
public void testDeviceShouldNotBeWokenWhenExitingEmulatedState() {
assertFalse(mLogicalDisplayMapper.shouldDeviceBeWoken(DEVICE_STATE_OPEN,
DEVICE_STATE_EMULATED,
@@ -1158,6 +1168,29 @@ public class LogicalDisplayMapperTest {
mLogicalDisplayMapper.getDisplayLocked(device2).getDevicePositionLocked());
}
+ @Test
+ public void updateAndGetMaskForDisplayPropertyChanges_getsPropertyChangedFlags() {
+ // Change the display state
+ DisplayInfo newDisplayInfo = new DisplayInfo();
+ newDisplayInfo.state = STATE_OFF;
+ assertEquals(LOGICAL_DISPLAY_EVENT_STATE_CHANGED,
+ mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
+
+ // Change the refresh rate override
+ newDisplayInfo = new DisplayInfo();
+ newDisplayInfo.refreshRateOverride = 30;
+ assertEquals(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED,
+ mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
+
+ // Change multiple properties
+ newDisplayInfo = new DisplayInfo();
+ newDisplayInfo.refreshRateOverride = 30;
+ newDisplayInfo.state = STATE_OFF;
+ assertEquals(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED
+ | LOGICAL_DISPLAY_EVENT_STATE_CHANGED,
+ mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
+ }
+
/////////////////
// Helper Methods
/////////////////
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index 4f875c38b92f..49de80179683 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -52,6 +52,7 @@ import com.android.server.display.brightness.strategy.AutoBrightnessFallbackStra
import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy;
+import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy;
import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -155,6 +156,27 @@ public final class DisplayBrightnessControllerTest {
}
@Test
+ public void updateWindowManagerBrightnessOverride() {
+ var request = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+ request.brightness = 0.4f;
+ request.tag = "cts";
+ OverrideBrightnessStrategy overrideBrightnessStrategy = mock(
+ OverrideBrightnessStrategy.class);
+ when(mDisplayBrightnessStrategySelector.getOverrideBrightnessStrategy()).thenReturn(
+ overrideBrightnessStrategy);
+
+ when(overrideBrightnessStrategy.updateWindowManagerBrightnessOverride(any()))
+ .thenReturn(false);
+ assertFalse(mDisplayBrightnessController.updateWindowManagerBrightnessOverride(request));
+ verify(overrideBrightnessStrategy).updateWindowManagerBrightnessOverride(request);
+
+ when(overrideBrightnessStrategy.updateWindowManagerBrightnessOverride(any()))
+ .thenReturn(true);
+ assertTrue(mDisplayBrightnessController.updateWindowManagerBrightnessOverride(request));
+ verify(overrideBrightnessStrategy, times(2)).updateWindowManagerBrightnessOverride(request);
+ }
+
+ @Test
public void setCurrentScreenBrightness() {
// Current Screen brightness is set as expected when a different value than the current
// is set
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index b99a18c8e68c..2ebb6c2a3ce4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -183,6 +183,8 @@ public final class DisplayBrightnessStrategySelectorTest {
when(mContext.getContentResolver()).thenReturn(contentResolver);
when(mContext.getResources()).thenReturn(mResources);
when(mInvalidBrightnessStrategy.getName()).thenReturn("InvalidBrightnessStrategy");
+ when(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+ .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
mInjector, DISPLAY_ID, mDisplayManagerFlags);
@@ -205,7 +207,8 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void selectStrategyWhenValid_useNormalBrightnessForDozeTrue_doNotSelectsDozeStrategy() {
- when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)).thenReturn(
+ true);
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
DisplayManagerInternal.DisplayPowerRequest.class);
displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
@@ -284,6 +287,20 @@ public final class DisplayBrightnessStrategySelectorTest {
}
@Test
+ public void selectStrategySelectsOverrideStrategyWhenWindowManagerOverrideIsValid() {
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+ DisplayManagerInternal.DisplayPowerRequest.class);
+ displayPowerRequest.screenBrightnessOverride = Float.NaN;
+ when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
+ when(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride()).thenReturn(0.4f);
+ assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
+ new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+ 0.1f, false, mDisplayOffloadSession,
+ STYLUS_IS_NOT_BEING_USED, /* isBedtimeModeWearEnabled= */ false)),
+ mOverrideBrightnessStrategy);
+ }
+
+ @Test
public void selectStrategySelectsTemporaryStrategyWhenValid() {
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
DisplayManagerInternal.DisplayPowerRequest.class);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 65f8ea7bfdfc..4be96c2a2eb3 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.res.Resources;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.DisplayManagerInternal;
import android.os.PowerManager;
@@ -76,6 +77,9 @@ public class AutomaticBrightnessStrategyTest {
@Mock
private DisplayManagerFlags mDisplayManagerFlags;
+ @Mock
+ private Resources mMockResources;
+
private BrightnessConfiguration mBrightnessConfiguration;
private float mDefaultScreenAutoBrightnessAdjustment;
private Context mContext;
@@ -378,7 +382,8 @@ public class AutomaticBrightnessStrategyTest {
reset(mAutomaticBrightnessController);
when(mAutomaticBrightnessController.isInIdleMode()).thenReturn(false);
- when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)).thenReturn(
+ true);
policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
// Validate interaction when automaticBrightnessController is in non-idle mode, display
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
index cc21af19722b..414f274a9b58 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
@@ -16,8 +16,9 @@
package com.android.server.display.brightness.strategy;
+import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
import android.hardware.display.DisplayManagerInternal;
@@ -34,7 +35,6 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-
public class OverrideBrightnessStrategyTest {
private OverrideBrightnessStrategy mOverrideBrightnessStrategy;
@@ -62,7 +62,56 @@ public class OverrideBrightnessStrategyTest {
new StrategyExecutionRequest(displayPowerRequest, 0.2f,
/* userSetBrightnessChanged= */ false,
/* isStylusBeingUsed */ false));
- assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+ assertThat(updatedDisplayBrightnessState).isEqualTo(expectedDisplayBrightnessState);
}
+ @Test
+ public void testUpdateBrightnessWhenWindowManagerOverrideIsRequested() {
+ var overrideRequest = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+ overrideRequest.brightness = 0.2f;
+ mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(overrideRequest);
+ DisplayManagerInternal.DisplayPowerRequest
+ displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
+ displayPowerRequest.screenBrightnessOverride = BRIGHTNESS_INVALID_FLOAT;
+ BrightnessReason brightnessReason = new BrightnessReason();
+ brightnessReason.setReason(BrightnessReason.REASON_OVERRIDE);
+ DisplayBrightnessState expectedDisplayBrightnessState =
+ new DisplayBrightnessState.Builder()
+ .setBrightness(overrideRequest.brightness)
+ .setBrightnessReason(brightnessReason)
+ .setDisplayBrightnessStrategyName(mOverrideBrightnessStrategy.getName())
+ .build();
+ DisplayBrightnessState updatedDisplayBrightnessState =
+ mOverrideBrightnessStrategy.updateBrightness(
+ new StrategyExecutionRequest(displayPowerRequest, 0.2f,
+ /* userSetBrightnessChanged= */ false,
+ /* isStylusBeingUsed */ false));
+ assertThat(updatedDisplayBrightnessState).isEqualTo(expectedDisplayBrightnessState);
+ }
+
+ @Test
+ public void testUpdateWindowManagerBrightnessOverride() {
+ var request = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+ assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(request))
+ .isFalse();
+ assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+ .isEqualTo(BRIGHTNESS_INVALID_FLOAT);
+
+ request.brightness = 0.2f;
+ assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(request))
+ .isTrue();
+ assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+ .isEqualTo(0.2f);
+
+ // Passing the same request doesn't result in an update.
+ assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(request))
+ .isFalse();
+ assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+ .isEqualTo(0.2f);
+
+ assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(null))
+ .isTrue();
+ assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+ .isEqualTo(BRIGHTNESS_INVALID_FLOAT);
+ }
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
index 9ea7ea7ef23d..56e4048c842e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
@@ -27,6 +27,7 @@ import org.junit.runner.RunWith
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.clearInvocations
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
@@ -149,6 +150,29 @@ class SystemRequestObserverTest {
}
@Test
+ fun testTokenUnlinkToDeath_noVotes() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+
+ verify(mockToken, never()).unlinkToDeath(any(), eq(0))
+ }
+
+ @Test
+ fun testTokenUnlinkToDeath_removedVotes() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+ clearInvocations(mockToken)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+
+ verify(mockToken, never()).unlinkToDeath(any(), eq(0))
+ }
+
+ @Test
fun testTokenUnlinkToDeathNotCalled_votesForOtherDisplayInStorage() {
val systemRequestObserver = SystemRequestObserver(storage)
val requestedModes = intArrayOf(1, 2, 3)
diff --git a/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt
new file mode 100644
index 000000000000..01061f16c279
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.plugin
+
+import android.content.Context
+import androidx.test.filters.SmallTest
+import com.android.server.display.feature.DisplayManagerFlags
+import com.android.server.display.plugin.PluginManager.PluginChangeListener
+
+import org.junit.Test
+
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+private val TEST_PLUGIN_TYPE = PluginType(Int::class.java, "test_type")
+
+@SmallTest
+class PluginManagerTest {
+
+ private val mockContext = mock<Context>()
+ private val mockFlags = mock<DisplayManagerFlags>()
+ private val mockListener = mock<PluginChangeListener<Int>>()
+ private val testInjector = TestInjector()
+
+ @Test
+ fun testBootCompleted_enabledPluginManager() {
+ val pluginManager = createPluginManager()
+
+ pluginManager.onBootCompleted()
+
+ verify(testInjector.mockPlugin1).onBootCompleted()
+ verify(testInjector.mockPlugin2).onBootCompleted()
+ }
+
+ @Test
+ fun testBootCompleted_disabledPluginManager() {
+ val pluginManager = createPluginManager(false)
+
+ pluginManager.onBootCompleted()
+
+ verify(testInjector.mockPlugin1, never()).onBootCompleted()
+ verify(testInjector.mockPlugin2, never()).onBootCompleted()
+ }
+
+ @Test
+ fun testSubscribe() {
+ val pluginManager = createPluginManager()
+
+ pluginManager.subscribe(TEST_PLUGIN_TYPE, mockListener)
+
+ verify(testInjector.mockStorage).addListener(TEST_PLUGIN_TYPE, mockListener)
+ }
+
+ @Test
+ fun testUnsubscribe() {
+ val pluginManager = createPluginManager()
+
+ pluginManager.unsubscribe(TEST_PLUGIN_TYPE, mockListener)
+
+ verify(testInjector.mockStorage).removeListener(TEST_PLUGIN_TYPE, mockListener)
+ }
+
+ private fun createPluginManager(enabled: Boolean = true): PluginManager {
+ whenever(mockFlags.isPluginManagerEnabled).thenReturn(enabled)
+ return PluginManager(mockContext, mockFlags, testInjector)
+ }
+
+ private class TestInjector : PluginManager.Injector() {
+ val mockStorage = mock<PluginStorage>()
+ val mockPlugin1 = mock<Plugin>()
+ val mockPlugin2 = mock<Plugin>()
+
+ override fun getPluginStorage(): PluginStorage {
+ return mockStorage
+ }
+
+ override fun loadPlugins(context: Context?, storage: PluginStorage?): List<Plugin> {
+ return listOf(mockPlugin1, mockPlugin2)
+ }
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt
new file mode 100644
index 000000000000..218e34134e93
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.plugin
+
+import androidx.test.filters.SmallTest
+import com.android.server.display.plugin.PluginManager.PluginChangeListener
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+private val TEST_PLUGIN_TYPE1 = PluginType(String::class.java, "test_type1")
+private val TEST_PLUGIN_TYPE2 = PluginType(String::class.java, "test_type2")
+
+@SmallTest
+class PluginStorageTest {
+
+ val storage = PluginStorage()
+
+ @Test
+ fun testUpdateValue() {
+ val type1Value = "value1"
+ val testChangeListener = TestPluginChangeListener<String>()
+ storage.addListener(TEST_PLUGIN_TYPE1, testChangeListener)
+
+ storage.updateValue(TEST_PLUGIN_TYPE1, type1Value)
+
+ assertThat(testChangeListener.receivedValue).isEqualTo(type1Value)
+ }
+
+ @Test
+ fun testAddListener() {
+ val type1Value = "value1"
+ val testChangeListener = TestPluginChangeListener<String>()
+ storage.updateValue(TEST_PLUGIN_TYPE1, type1Value)
+
+ storage.addListener(TEST_PLUGIN_TYPE1, testChangeListener)
+
+ assertThat(testChangeListener.receivedValue).isEqualTo(type1Value)
+ }
+
+ @Test
+ fun testRemoveListener() {
+ val type1Value = "value1"
+ val testChangeListener = TestPluginChangeListener<String>()
+ storage.addListener(TEST_PLUGIN_TYPE1, testChangeListener)
+ storage.removeListener(TEST_PLUGIN_TYPE1, testChangeListener)
+
+ storage.updateValue(TEST_PLUGIN_TYPE1, type1Value)
+
+ assertThat(testChangeListener.receivedValue).isNull()
+ }
+
+ @Test
+ fun testAddListener_multipleValues() {
+ val type1Value = "value1"
+ val type2Value = "value2"
+ val testChangeListener = TestPluginChangeListener<String>()
+ storage.updateValue(TEST_PLUGIN_TYPE1, type1Value)
+ storage.updateValue(TEST_PLUGIN_TYPE2, type2Value)
+
+ storage.addListener(TEST_PLUGIN_TYPE1, testChangeListener)
+
+ assertThat(testChangeListener.receivedValue).isEqualTo(type1Value)
+ }
+
+ @Test
+ fun testUpdateValue_multipleListeners() {
+ val type1Value = "value1"
+ val testChangeListener1 = TestPluginChangeListener<String>()
+ val testChangeListener2 = TestPluginChangeListener<String>()
+ storage.addListener(TEST_PLUGIN_TYPE1, testChangeListener1)
+ storage.addListener(TEST_PLUGIN_TYPE2, testChangeListener2)
+
+ storage.updateValue(TEST_PLUGIN_TYPE1, type1Value)
+
+ assertThat(testChangeListener1.receivedValue).isEqualTo(type1Value)
+ assertThat(testChangeListener2.receivedValue).isNull()
+ }
+
+ private class TestPluginChangeListener<T> : PluginChangeListener<T> {
+ var receivedValue: T? = null
+
+ override fun onChanged(value: T?) {
+ receivedValue = value
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 95acd75f32cc..993569fb17fe 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -78,7 +78,7 @@ android_test {
"am_flags_lib",
"device_policy_aconfig_flags_lib",
] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
- "true": ["service-crashrecovery.impl"],
+ "true": ["service-crashrecovery-pre-jarjar"],
default: [],
}),
diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index 00543a8a9871..94d4b9522d60 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -22,8 +22,8 @@ cc_library_shared {
srcs: [
":lib_cachedAppOptimizer_native",
":lib_freezer_native",
- ":lib_gameManagerService_native",
":lib_oomConnection_native",
+ ":lib_lazilyRegisteredServices_native",
"onload.cpp",
],
@@ -54,6 +54,8 @@ cc_library_shared {
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@4.0",
+ "android.hardware.ir@1.0",
+ "android.hardware.vr@1.0",
"android.hidl.token@1.0-utils",
],
}
diff --git a/services/tests/mockingservicestests/jni/onload.cpp b/services/tests/mockingservicestests/jni/onload.cpp
index cb246d15fce8..9b4c8178b092 100644
--- a/services/tests/mockingservicestests/jni/onload.cpp
+++ b/services/tests/mockingservicestests/jni/onload.cpp
@@ -26,8 +26,8 @@
namespace android {
int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
int register_android_server_am_Freezer(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
int register_android_server_am_OomConnection(JNIEnv* env);
+int register_android_server_utils_LazyJniRegistrar(JNIEnv* env);
};
using namespace android;
@@ -44,7 +44,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
ALOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_am_CachedAppOptimizer(env);
register_android_server_am_Freezer(env);
- register_android_server_app_GameManagerService(env);
register_android_server_am_OomConnection(env);
+ register_android_server_utils_LazyJniRegistrar(env);
return JNI_VERSION_1_4;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 30de0e8c7981..8dc8c14f8948 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -67,7 +67,6 @@ import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
-import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TEMPORARY_QUOTA_CHANGED;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
@@ -152,7 +151,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.flag.util.FlagSetException;
@@ -436,8 +434,7 @@ public final class AlarmManagerServiceTest {
*/
private void disableFlagsNotSetByAnnotation() {
try {
- mSetFlagsRule.disableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS,
- Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS);
+ mSetFlagsRule.disableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS);
} catch (FlagSetException fse) {
// Expected if the test about to be run requires this enabled.
}
@@ -523,13 +520,11 @@ public final class AlarmManagerServiceTest {
mService.onStart();
- if (Flags.useFrozenStateToDropListenerAlarms()) {
- final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor =
- ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class);
- verify(mActivityManager).registerUidFrozenStateChangedCallback(
- any(HandlerExecutor.class), frozenCaptor.capture());
- mUidFrozenStateCallback = frozenCaptor.getValue();
- }
+ final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor =
+ ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class);
+ verify(mActivityManager).registerUidFrozenStateChangedCallback(
+ any(HandlerExecutor.class), frozenCaptor.capture());
+ mUidFrozenStateCallback = frozenCaptor.getValue();
// Unable to mock mMockContext to return a mock stats manager.
// So just mocking the whole MetricsHelper instance.
@@ -3744,79 +3739,11 @@ public final class AlarmManagerServiceTest {
testTemporaryQuota_bumpedBeforeDeferral(STANDBY_BUCKET_RARE);
}
- @Test
- public void exactListenerAlarmsRemovedOnCached() {
- mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true);
-
- setTestAlarmWithListener(ELAPSED_REALTIME, 31, getNewListener(() -> {}), WINDOW_EXACT,
- TEST_CALLING_UID);
- setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID);
- setTestAlarm(ELAPSED_REALTIME, 54, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0,
- TEST_CALLING_UID, null);
- setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null);
-
- setTestAlarmWithListener(ELAPSED_REALTIME, 21, getNewListener(() -> {}), WINDOW_EXACT,
- TEST_CALLING_UID_2);
- setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2);
- setTestAlarm(ELAPSED_REALTIME, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0,
- TEST_CALLING_UID_2, null);
- setTestAlarm(RTC, 549, 234, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null);
-
- assertEquals(8, mService.mAlarmStore.size());
-
- mListener.handleUidCachedChanged(TEST_CALLING_UID, true);
- assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
- assertEquals(7, mService.mAlarmStore.size());
-
- mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true);
- assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
- assertEquals(6, mService.mAlarmStore.size());
- }
-
- @Test
- public void alarmCountOnListenerCached() {
- mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true);
-
- // Set some alarms for TEST_CALLING_UID.
- final int numExactListenerUid1 = 14;
- for (int i = 0; i < numExactListenerUid1; i++) {
- setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i,
- getNewListener(() -> {}));
- }
- setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID);
- setTestAlarm(ELAPSED_REALTIME, 54, getNewMockPendingIntent());
- setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null);
-
- // Set some alarms for TEST_CALLING_UID_2.
- final int numExactListenerUid2 = 9;
- for (int i = 0; i < numExactListenerUid2; i++) {
- setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i,
- getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID_2);
- }
- setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2);
- setTestAlarm(RTC_WAKEUP, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0,
- TEST_CALLING_UID_2, null);
-
- assertEquals(numExactListenerUid1 + 3, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
- assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2));
-
- mListener.handleUidCachedChanged(TEST_CALLING_UID, true);
- assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
- assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
- assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2));
-
- mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true);
- assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
- assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
- assertEquals(2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2));
- }
-
private void executeUidFrozenStateCallback(int[] uids, int[] frozenStates) {
assertNotNull(mUidFrozenStateCallback);
mUidFrozenStateCallback.onUidFrozenStateChanged(uids, frozenStates);
}
- @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS)
@DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS)
@Test
public void exactListenerAlarmsRemovedOnFrozen() {
@@ -3848,7 +3775,6 @@ public final class AlarmManagerServiceTest {
assertEquals(6, mService.mAlarmStore.size());
}
- @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS)
@DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS)
@Test
public void alarmCountOnListenerFrozen() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index dcbc23410fdb..ace6aae1a8fc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -47,10 +47,8 @@ import static com.android.server.am.Flags.FLAG_AVOID_RESOLVING_TYPE;
import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK;
import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE;
import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -80,6 +78,7 @@ import android.Manifest;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.ApplicationThreadConstants;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.ForegroundServiceDelegationOptions;
@@ -87,6 +86,7 @@ import android.app.IUidObserver;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.SyncNotedAppOp;
+import android.app.backup.BackupAnnotations;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -111,6 +111,7 @@ import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.permission.IPermissionManager;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -133,6 +134,7 @@ import com.android.server.am.ProcessList.IsolatedUidRange;
import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
import com.android.server.am.UidObserverController.ChangeRecord;
import com.android.server.appop.AppOpsService;
+import com.android.server.job.JobSchedulerInternal;
import com.android.server.notification.NotificationManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerService;
@@ -228,6 +230,7 @@ public class ActivityManagerServiceTest {
@Mock private PackageManagerInternal mPackageManagerInternal;
@Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal;
@Mock private NotificationManagerInternal mNotificationManagerInternal;
+ @Mock private JobSchedulerInternal mJobSchedulerInternal;
@Mock private ContentResolver mContentResolver;
private TestInjector mInjector;
@@ -249,6 +252,7 @@ public class ActivityManagerServiceTest {
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
LocalServices.addService(ActivityTaskManagerInternal.class, mActivityTaskManagerInternal);
LocalServices.addService(NotificationManagerInternal.class, mNotificationManagerInternal);
+ LocalServices.addService(JobSchedulerInternal.class, mJobSchedulerInternal);
doReturn(new ComponentName("", "")).when(mPackageManagerInternal)
.getSystemUiServiceComponent();
@@ -279,9 +283,9 @@ public class ActivityManagerServiceTest {
// Required for updating DeviceConfig.
InstrumentationRegistry.getInstrumentation()
.getUiAutomation()
- .adoptShellPermissionIdentity(
- Manifest.permission.READ_DEVICE_CONFIG,
- Manifest.permission.WRITE_DEVICE_CONFIG);
+ .adoptShellPermissionIdentity(Manifest.permission.READ_DEVICE_CONFIG,
+ Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG);
sProcessListSettingsListener = mAms.mProcessList.getProcessListSettingsListener();
assertThat(sProcessListSettingsListener).isNotNull();
}
@@ -308,6 +312,7 @@ public class ActivityManagerServiceTest {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
LocalServices.removeServiceForTest(NotificationManagerInternal.class);
+ LocalServices.removeServiceForTest(JobSchedulerInternal.class);
if (mMockingSession != null) {
mMockingSession.finishMocking();
@@ -1548,6 +1553,50 @@ public class ActivityManagerServiceTest {
eq(notificationId), anyInt());
}
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void bindBackupAgent_fullBackup_shouldUseRestrictedMode_setsInFullBackup()
+ throws Exception {
+ ActivityManagerService spyAms = spy(mAms);
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.packageName = TEST_PACKAGE;
+ applicationInfo.processName = TEST_PACKAGE;
+ applicationInfo.uid = TEST_UID;
+ doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(TEST_PACKAGE),
+ anyLong(), anyInt());
+ ProcessRecord appRec = new ProcessRecord(mAms, applicationInfo, TAG, TEST_UID);
+ doReturn(appRec).when(spyAms).getProcessRecordLocked(eq(TEST_PACKAGE), eq(TEST_UID));
+
+ spyAms.bindBackupAgent(TEST_PACKAGE, ApplicationThreadConstants.BACKUP_MODE_FULL,
+ UserHandle.USER_SYSTEM,
+ BackupAnnotations.BackupDestination.CLOUD, /* shouldUseRestrictedMode= */
+ true);
+
+ assertThat(appRec.isInFullBackup()).isTrue();
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void bindBackupAgent_fullBackup_shouldNotUseRestrictedMode_doesNotSetInFullBackup()
+ throws Exception {
+ ActivityManagerService spyAms = spy(mAms);
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.packageName = TEST_PACKAGE;
+ applicationInfo.processName = TEST_PACKAGE;
+ applicationInfo.uid = TEST_UID;
+ doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(TEST_PACKAGE),
+ anyLong(), anyInt());
+ ProcessRecord appRec = new ProcessRecord(mAms, applicationInfo, TAG, TEST_UID);
+ doReturn(appRec).when(spyAms).getProcessRecordLocked(eq(TEST_PACKAGE), eq(TEST_UID));
+
+ spyAms.bindBackupAgent(TEST_PACKAGE, ApplicationThreadConstants.BACKUP_MODE_FULL,
+ UserHandle.USER_SYSTEM,
+ BackupAnnotations.BackupDestination.CLOUD, /* shouldUseRestrictedMode= */
+ false);
+
+ assertThat(appRec.isInFullBackup()).isFalse();
+ }
+
private static class TestHandler extends Handler {
private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec
private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
index a1a8b0ec7d2f..5eb23a24908d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
@@ -58,6 +58,7 @@ import com.android.server.compat.PlatformCompat;
import com.android.server.wm.ActivityTaskManagerService;
import org.junit.Rule;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -185,10 +186,10 @@ public abstract class BaseBroadcastQueueTest {
doReturn(mAppStartInfoTracker).when(mProcessList).getAppStartInfoTracker();
- doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
- doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), anyInt());
+ doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class));
+ doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), any(ApplicationInfo.class));
}
public void tearDown() throws Exception {
@@ -298,7 +299,7 @@ public abstract class BaseBroadcastQueueTest {
filter.setPriority(priority);
final BroadcastFilter res = new BroadcastFilter(filter, receiverList,
receiverList.app.info.packageName, null, null, null, receiverList.uid,
- receiverList.userId, false, false, true,
+ receiverList.userId, false, false, true, receiverList.app.info,
mock(PlatformCompat.class));
receiverList.add(res);
return res;
@@ -308,4 +309,8 @@ public abstract class BaseBroadcastQueueTest {
app.mOptRecord.setPendingFreeze(pendingFreeze);
app.mOptRecord.setFrozen(frozen);
}
+
+ ArgumentMatcher<ApplicationInfo> appInfoEquals(int uid) {
+ return test -> (test.uid == uid);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java
index e977a7d46f30..5d106ace71dd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java
@@ -20,10 +20,13 @@ import static android.content.IntentFilter.SYSTEM_LOW_PRIORITY;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import android.content.pm.ApplicationInfo;
import android.os.Process;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
@@ -53,14 +56,14 @@ public class BroadcastFilterTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class));
}
@Test
@EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
public void testCalculateAdjustedPriority() {
- doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
-
{
// Pairs of {initial-priority, expected-adjusted-priority}
final Pair<Integer, Integer>[] priorities = new Pair[] {
@@ -95,8 +98,8 @@ public class BroadcastFilterTest {
@Test
@EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
public void testCalculateAdjustedPriority_withChangeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class));
{
// Pairs of {initial-priority, expected-adjusted-priority}
@@ -132,9 +135,6 @@ public class BroadcastFilterTest {
@Test
@DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
public void testCalculateAdjustedPriority_withFlagDisabled() {
- doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
-
{
// Pairs of {initial-priority, expected-adjusted-priority}
final Pair<Integer, Integer>[] priorities = new Pair[] {
@@ -170,7 +170,7 @@ public class BroadcastFilterTest {
@DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
public void testCalculateAdjustedPriority_withFlagDisabled_withChangeIdDisabled() {
doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
+ eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), anyInt());
{
// Pairs of {initial-priority, expected-adjusted-priority}
@@ -215,6 +215,7 @@ public class BroadcastFilterTest {
final String errorMsg = String.format("owner=%d; actualPriority=%d; expectedPriority=%d",
owningUid, priority, expectedAdjustedPriority);
assertWithMessage(errorMsg).that(BroadcastFilter.calculateAdjustedPriority(
- owningUid, priority, mPlatformCompat)).isEqualTo(expectedAdjustedPriority);
+ owningUid, priority, mock(ApplicationInfo.class), mPlatformCompat))
+ .isEqualTo(expectedAdjustedPriority);
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 1481085c5f71..82237bca2e34 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -47,6 +47,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
@@ -184,7 +185,10 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest {
}
private static BroadcastFilter makeMockRegisteredReceiver() {
- return mock(BroadcastFilter.class);
+ final BroadcastFilter filter = mock(BroadcastFilter.class);
+ final ApplicationInfo info = makeApplicationInfo(PACKAGE_ORANGE);
+ doReturn(info).when(filter).getApplicationInfo();
+ return filter;
}
private BroadcastRecord makeBroadcastRecord(Intent intent) {
@@ -716,9 +720,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest {
@EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
@Test
public void testRunnableAt_Cached_Prioritized_NonDeferrable_changeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
- eq(getUidForPackage(PACKAGE_GREEN)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+ argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
final List receivers = List.of(
withPriority(makeManifestReceiver(PACKAGE_RED, PACKAGE_RED), 10),
withPriority(makeManifestReceiver(PACKAGE_GREEN, PACKAGE_GREEN), -10));
@@ -1288,9 +1292,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest {
@SuppressWarnings("GuardedBy")
@Test
public void testDeliveryGroupPolicy_prioritized_diffReceivers_changeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
- eq(getUidForPackage(PACKAGE_GREEN)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+ argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
final Intent screenOn = new Intent(Intent.ACTION_SCREEN_ON);
final Intent screenOff = new Intent(Intent.ACTION_SCREEN_OFF);
@@ -1823,9 +1827,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest {
@SuppressWarnings("GuardedBy")
@Test
public void testDeliveryDeferredForCached_changeIdDisabled() throws Exception {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
- eq(getUidForPackage(PACKAGE_GREEN)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+ argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
final ProcessRecord greenProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_GREEN));
final ProcessRecord redProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_RED));
@@ -2027,9 +2031,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest {
@Test
public void testDeliveryDeferredForCached_withInfiniteDeferred_changeIdDisabled()
throws Exception {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
- eq(getUidForPackage(PACKAGE_GREEN)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+ argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
final ProcessRecord greenProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_GREEN));
final ProcessRecord redProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_RED));
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 9d92d5fe4f60..ea80f283793e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -1659,8 +1659,9 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(receiverBlueApp.uid));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+ argThat(appInfoEquals(receiverBlueApp.uid)));
// Enqueue a normal broadcast that will go to several processes, and
// then enqueue a foreground broadcast that risks reordering
@@ -2471,8 +2472,9 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(receiverBlueApp.uid));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+ argThat(appInfoEquals(receiverBlueApp.uid)));
mUidObserver.onUidStateChanged(receiverGreenApp.info.uid,
ActivityManager.PROCESS_STATE_TOP, 0, ActivityManager.PROCESS_CAPABILITY_NONE);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
index a424bfdb8df4..8482fd609d05 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -19,12 +19,12 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.server.am.BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE;
import static com.android.server.am.BroadcastRecord.DELIVERY_DEFERRED;
import static com.android.server.am.BroadcastRecord.DELIVERY_DELIVERED;
import static com.android.server.am.BroadcastRecord.DELIVERY_PENDING;
import static com.android.server.am.BroadcastRecord.DELIVERY_SKIPPED;
import static com.android.server.am.BroadcastRecord.DELIVERY_TIMEOUT;
+import static com.android.server.am.BroadcastRecord.LIMIT_PRIORITY_SCOPE;
import static com.android.server.am.BroadcastRecord.calculateBlockedUntilBeyondCount;
import static com.android.server.am.BroadcastRecord.calculateDeferUntilActive;
import static com.android.server.am.BroadcastRecord.calculateUrgent;
@@ -35,7 +35,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import android.app.BackgroundStartPrivileges;
@@ -63,6 +64,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
@@ -108,8 +110,8 @@ public class BroadcastRecordTest {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), anyInt());
+ doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), any(ApplicationInfo.class));
}
@Test
@@ -222,8 +224,8 @@ public class BroadcastRecordTest {
@EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
@Test
public void testIsPrioritized_withDifferentPriorities_withFirstUidChangeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
assertTrue(isPrioritized(List.of(
createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -256,8 +258,8 @@ public class BroadcastRecordTest {
@EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
@Test
public void testIsPrioritized_withDifferentPriorities_withLastUidChangeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(3)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(3))));
assertTrue(isPrioritized(List.of(
createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -294,8 +296,8 @@ public class BroadcastRecordTest {
@EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
@Test
public void testIsPrioritized_withDifferentPriorities_withUidChangeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2))));
assertTrue(isPrioritized(List.of(
createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -328,10 +330,10 @@ public class BroadcastRecordTest {
@EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
@Test
public void testIsPrioritized_withDifferentPriorities_withMultipleUidChangeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2))));
assertTrue(isPrioritized(List.of(
createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -362,10 +364,10 @@ public class BroadcastRecordTest {
assertArrayEquals(new int[] {0, 0, 1, 1, 3},
calculateBlockedUntilBeyondCount(List.of(
createResolveInfo(PACKAGE1, getAppId(1), 20),
- createResolveInfo(PACKAGE2, getAppId(3), 20),
+ createResolveInfo(PACKAGE3, getAppId(3), 20),
createResolveInfo(PACKAGE3, getAppId(3), 10),
createResolveInfo(PACKAGE3, getAppId(3), 0),
- createResolveInfo(PACKAGE3, getAppId(2), 0)), false, mPlatformCompat));
+ createResolveInfo(PACKAGE2, getAppId(2), 0)), false, mPlatformCompat));
}
@Test
@@ -592,8 +594,8 @@ public class BroadcastRecordTest {
@EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
@Test
public void testSetDeliveryState_DeferUntilActive_changeIdDisabled() {
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
final BroadcastRecord r = createBroadcastRecord(
new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of(
createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -960,8 +962,8 @@ public class BroadcastRecordTest {
createResolveInfo(PACKAGE2, getAppId(2)),
createResolveInfo(PACKAGE3, getAppId(3)))));
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
assertArrayEquals(new boolean[] {false, true, true}, calculateChangeState(
List.of(createResolveInfo(PACKAGE1, getAppId(1)),
createResolveInfo(PACKAGE2, getAppId(2)),
@@ -969,11 +971,11 @@ public class BroadcastRecordTest {
assertArrayEquals(new boolean[] {false, true, false, true}, calculateChangeState(
List.of(createResolveInfo(PACKAGE1, getAppId(1)),
createResolveInfo(PACKAGE2, getAppId(2)),
- createResolveInfo(PACKAGE2, getAppId(1)),
+ createResolveInfo(PACKAGE1, getAppId(1)),
createResolveInfo(PACKAGE3, getAppId(3)))));
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2))));
assertArrayEquals(new boolean[] {false, false, true}, calculateChangeState(
List.of(createResolveInfo(PACKAGE1, getAppId(1)),
createResolveInfo(PACKAGE2, getAppId(2)),
@@ -987,8 +989,8 @@ public class BroadcastRecordTest {
createResolveInfo(PACKAGE2, getAppId(2)),
createResolveInfo(PACKAGE3, getAppId(3)))));
- doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
- eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(3)));
+ doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+ eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(3))));
assertArrayEquals(new boolean[] {false, false, false}, calculateChangeState(
List.of(createResolveInfo(PACKAGE1, getAppId(1)),
createResolveInfo(PACKAGE2, getAppId(2)),
@@ -998,14 +1000,14 @@ public class BroadcastRecordTest {
List.of(createResolveInfo(PACKAGE1, getAppId(1)),
createResolveInfo(PACKAGE3, getAppId(3)),
createResolveInfo(PACKAGE2, getAppId(2)),
- createResolveInfo(PACKAGE2, getAppId(1)),
+ createResolveInfo(PACKAGE1, getAppId(1)),
createResolveInfo(PACKAGE2, getAppId(2)),
createResolveInfo(PACKAGE3, getAppId(3)))));
}
private boolean[] calculateChangeState(List<Object> receivers) {
return BroadcastRecord.calculateChangeStateForReceivers(receivers,
- CHANGE_LIMIT_PRIORITY_SCOPE, mPlatformCompat);
+ LIMIT_PRIORITY_SCOPE, mPlatformCompat);
}
private static void cleanupDisabledPackageReceivers(BroadcastRecord record,
@@ -1185,4 +1187,8 @@ public class BroadcastRecordTest {
assertEquals("deferred", expectedDeferredCount, r.deferredCount);
assertEquals("beyond", expectedBeyondCount, r.beyondCount);
}
+
+ private ArgumentMatcher<ApplicationInfo> appInfoEquals(int uid) {
+ return test -> (test.uid == uid);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 4a1315583ad4..1efe4707fc11 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -105,10 +105,12 @@ import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.server.LocalServices;
@@ -175,6 +177,7 @@ public class MockingOomAdjusterTests {
private ActiveUids mActiveUids;
private PackageManagerInternal mPackageManagerInternal;
private ActivityManagerService mService;
+ private TestCachedAppOptimizer mTestCachedAppOptimizer;
private OomAdjusterInjector mInjector = new OomAdjusterInjector();
private int mUiTierSize;
@@ -242,9 +245,11 @@ public class MockingOomAdjusterTests {
doNothing().when(pr).enqueueProcessChangeItemLocked(anyInt(), anyInt(), anyInt(),
anyBoolean());
mActiveUids = new ActiveUids(mService, false);
+ mTestCachedAppOptimizer = new TestCachedAppOptimizer(mService);
mProcessStateController = new ProcessStateController.Builder(mService,
mService.mProcessList, mActiveUids)
.useModernOomAdjuster(mService.mConstants.ENABLE_NEW_OOMADJ)
+ .setCachedAppOptimizer(mTestCachedAppOptimizer)
.setOomAdjusterInjector(mInjector)
.build();
mService.mProcessStateController = mProcessStateController;
@@ -1423,6 +1428,31 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
@Test
+ public void testUpdateOomAdj_DoOne_Service_NotPerceptible_AboveClient() {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ ProcessRecord service = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+ MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+ bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
+ bindService(service, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+ mProcessStateController.setRunningRemoteAnimation(client, true);
+ mProcessStateController.updateHasAboveClientLocked(app.mServices);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ updateOomAdj(client, app, service);
+
+ final int expectedAdj;
+ if (Flags.addModifyRawOomAdjServiceLevel()) {
+ expectedAdj = SERVICE_ADJ;
+ } else {
+ expectedAdj = CACHED_APP_MIN_ADJ;
+ }
+ assertEquals(expectedAdj, app.mState.getSetAdj());
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
public void testUpdateOomAdj_DoOne_Service_NotVisible() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
@@ -2902,7 +2932,7 @@ public class MockingOomAdjusterTests {
// Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and
// verify that its OOM adjustment level is unaffected.
bindService(service, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
- app.mServices.updateHasAboveClientLocked();
+ mProcessStateController.updateHasAboveClientLocked(app.mServices);
assertTrue(app.mServices.hasAboveClient());
updateOomAdj(app);
@@ -2924,7 +2954,7 @@ public class MockingOomAdjusterTests {
// Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and
// verify that its OOM adjustment level is unaffected.
bindService(app, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
- app.mServices.updateHasAboveClientLocked();
+ mProcessStateController.updateHasAboveClientLocked(app.mServices);
assertFalse(app.mServices.hasAboveClient());
updateOomAdj(app);
@@ -2979,7 +3009,7 @@ public class MockingOomAdjusterTests {
// Since sr.app is null, this service cannot be in the same process as the
// client so we expect the BIND_ABOVE_CLIENT adjustment to take effect.
- app.mServices.updateHasAboveClientLocked();
+ mProcessStateController.updateHasAboveClientLocked(app.mServices);
updateOomAdj(app);
assertTrue(app.mServices.hasAboveClient());
assertNotEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -3110,13 +3140,13 @@ public class MockingOomAdjusterTests {
mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
assertEquals(true, app.getUidRecord().isSetAllowListed());
- assertEquals(true, app.mOptRecord.shouldNotFreeze());
- assertEquals(true, app2.mOptRecord.shouldNotFreeze());
+ assertFreezeState(app, false);
+ assertFreezeState(app2, false);
mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
- assertEquals(false, app.mOptRecord.shouldNotFreeze());
- assertEquals(false, app2.mOptRecord.shouldNotFreeze());
+ assertFreezeState(app, true);
+ assertFreezeState(app2, true);
}
@SuppressWarnings("GuardedBy")
@@ -3138,25 +3168,25 @@ public class MockingOomAdjusterTests {
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
- assertEquals(true, app.mOptRecord.shouldNotFreeze());
- assertEquals(true, app2.mOptRecord.shouldNotFreeze());
- assertEquals(true, app3.mOptRecord.shouldNotFreeze());
+ assertFreezeState(app, false);
+ assertFreezeState(app2, false);
+ assertFreezeState(app3, false);
// Remove app1 from allowlist.
mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
- assertEquals(false, app.mOptRecord.shouldNotFreeze());
- assertEquals(true, app2.mOptRecord.shouldNotFreeze());
- assertEquals(true, app3.mOptRecord.shouldNotFreeze());
+ assertFreezeState(app, true);
+ assertFreezeState(app2, false);
+ assertFreezeState(app3, false);
// Now remove app2 from allowlist.
mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(false, app2.getUidRecord().isSetAllowListed());
- assertEquals(false, app.mOptRecord.shouldNotFreeze());
- assertEquals(false, app2.mOptRecord.shouldNotFreeze());
- assertEquals(false, app3.mOptRecord.shouldNotFreeze());
+ assertFreezeState(app, true);
+ assertFreezeState(app2, true);
+ assertFreezeState(app3, true);
}
@SuppressWarnings("GuardedBy")
@@ -3231,6 +3261,24 @@ public class MockingOomAdjusterTests {
"cch-empty");
}
+ @SuppressWarnings("GuardedBy")
+ @Test
+ @EnableFlags(Flags.FLAG_FIX_APPLY_OOMADJ_ORDER)
+ public void testUpdateOomAdj_ApplyOomAdjInCorrectOrder() {
+ final int numberOfApps = 5;
+ final ProcessRecord[] apps = new ProcessRecord[numberOfApps];
+ for (int i = 0; i < numberOfApps; i++) {
+ apps[i] = spy(makeDefaultProcessRecord(MOCKAPP_PID + i, MOCKAPP_UID + i,
+ MOCKAPP_PROCESSNAME + i, MOCKAPP_PACKAGENAME + i, true));
+ }
+ updateOomAdj(apps);
+ for (int i = 1; i < numberOfApps; i++) {
+ final int pre = mInjector.mSetOomAdjAppliedAt.get(apps[i - 1].mPid);
+ final int cur = mInjector.mSetOomAdjAppliedAt.get(apps[i].mPid);
+ assertTrue("setOomAdj is called in wrong order", pre < cur);
+ }
+ }
+
private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
String packageName, boolean hasShownUi) {
return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(
@@ -3302,7 +3350,7 @@ public class MockingOomAdjusterTests {
if (Flags.pushGlobalStateToOomadjuster()) {
mProcessStateController.setBackupTarget(app, app.userId);
} else {
- BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
+ BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0, true);
backupTarget.app = app;
doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
}
@@ -3370,6 +3418,14 @@ public class MockingOomAdjusterTests {
assertEquals(expectedCached, state.isCached());
}
+ @SuppressWarnings("GuardedBy")
+ private void assertFreezeState(ProcessRecord app, boolean expectedFreezeState) {
+ boolean actualFreezeState = mTestCachedAppOptimizer.mLastSetFreezeState.get(app.getPid(),
+ false);
+ assertEquals("Unexcepted freeze state for " + app.processName, expectedFreezeState,
+ actualFreezeState);
+ }
+
private class ProcessRecordBuilder {
@SuppressWarnings("UnusedVariable")
int mPid;
@@ -3513,18 +3569,57 @@ public class MockingOomAdjusterTests {
return app;
}
}
+ private static final class TestProcessDependencies
+ implements CachedAppOptimizer.ProcessDependencies {
+ @Override
+ public long[] getRss(int pid) {
+ return new long[]{/*totalRSS*/ 0, /*fileRSS*/ 0, /*anonRSS*/ 0, /*swap*/ 0};
+ }
+
+ @Override
+ public void performCompaction(CachedAppOptimizer.CompactProfile action, int pid) {}
+ }
+
+ private static class TestCachedAppOptimizer extends CachedAppOptimizer {
+ private SparseBooleanArray mLastSetFreezeState = new SparseBooleanArray();
+
+ TestCachedAppOptimizer(ActivityManagerService ams) {
+ super(ams, null, new TestProcessDependencies());
+ }
+
+ @Override
+ public boolean useFreezer() {
+ return true;
+ }
+
+ @Override
+ public void freezeAppAsyncLSP(ProcessRecord app) {
+ mLastSetFreezeState.put(app.getPid(), true);
+ }
+
+ @Override
+ public void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) {
+ mLastSetFreezeState.put(app.getPid(), false);
+ }
+ }
static class OomAdjusterInjector extends OomAdjuster.Injector {
// Jump ahead in time by this offset amount.
long mTimeOffsetMillis = 0;
private SparseIntArray mLastSetOomAdj = new SparseIntArray();
+ // A sequence number that increases every time setOomAdj is called
+ int mLastAppliedAt = 0;
+ // Holds the last sequence number setOomAdj is called for a pid
+ private SparseIntArray mSetOomAdjAppliedAt = new SparseIntArray();
+
void reset() {
mTimeOffsetMillis = 0;
mLastSetOomAdj.clear();
+ mLastAppliedAt = 0;
+ mSetOomAdjAppliedAt.clear();
}
-
void jumpUptimeAheadTo(long uptimeMillis) {
final long jumpMs = uptimeMillis - getUptimeMillis();
if (jumpMs <= 0) return;
@@ -3547,6 +3642,7 @@ public class MockingOomAdjusterTests {
final int pid = proc.getPid();
if (pid <= 0) continue;
mLastSetOomAdj.put(pid, proc.mState.getCurAdj());
+ mSetOomAdjAppliedAt.put(pid, mLastAppliedAt++);
}
}
@@ -3554,6 +3650,7 @@ public class MockingOomAdjusterTests {
void setOomAdj(int pid, int uid, int adj) {
if (pid <= 0) return;
mLastSetOomAdj.put(pid, adj);
+ mSetOomAdjAppliedAt.put(pid, mLastAppliedAt++);
}
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
new file mode 100644
index 000000000000..19e43b6fa851
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
@@ -0,0 +1,381 @@
+/*
+ * 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.backup;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ApplicationThreadConstants;
+import android.app.IActivityManager;
+import android.app.IBackupAgent;
+import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.backup.internal.LifecycleOperationStorage;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupAgentConnectionManagerTest {
+ private static final String TEST_PACKAGE = "com.test.package";
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Mock
+ IActivityManager mActivityManager;
+ @Mock
+ ActivityManagerInternal mActivityManagerInternal;
+ @Mock
+ LifecycleOperationStorage mOperationStorage;
+ @Mock
+ UserBackupManagerService mUserBackupManagerService;
+ @Mock
+ IBackupAgent.Stub mBackupAgentStub;
+ @Mock
+ PackageManager mPackageManager;
+
+ private BackupAgentConnectionManager mConnectionManager;
+ private MockitoSession mSession;
+ private ApplicationInfo mTestApplicationInfo;
+ private IBackupAgent mBackupAgentResult;
+ private Thread mTestThread;
+
+ @Before
+ public void setUp() throws Exception {
+ mSession = mockitoSession().initMocks(this).mockStatic(ActivityManager.class).mockStatic(
+ LocalServices.class).strictness(Strictness.LENIENT).startMocking();
+ MockitoAnnotations.initMocks(this);
+
+ doReturn(mActivityManager).when(ActivityManager::getService);
+ doReturn(mActivityManagerInternal).when(
+ () -> LocalServices.getService(ActivityManagerInternal.class));
+ // Real package manager throws if a property is not defined.
+ when(mPackageManager.getPropertyAsUser(any(), any(), any(), anyInt())).thenThrow(
+ new PackageManager.NameNotFoundException());
+
+ mConnectionManager = spy(
+ new BackupAgentConnectionManager(mOperationStorage, mPackageManager,
+ mUserBackupManagerService, UserHandle.USER_SYSTEM));
+
+ mTestApplicationInfo = new ApplicationInfo();
+ mTestApplicationInfo.packageName = TEST_PACKAGE;
+
+ mBackupAgentResult = null;
+ mTestThread = null;
+ }
+
+ @After
+ public void tearDown() {
+ if (mSession != null) {
+ mSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void bindToAgentSynchronous_amReturnsFailure_returnsNullAndClearsPendingBackups()
+ throws Exception {
+ when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(),
+ anyInt(), anyBoolean())).thenReturn(false);
+
+ IBackupAgent result = mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+ assertThat(result).isNull();
+ verify(mActivityManagerInternal).clearPendingBackup(UserHandle.USER_SYSTEM);
+ }
+
+ @Test
+ public void bindToAgentSynchronous_agentDisconnectedCalled_returnsNullAndClearsPendingBackups()
+ throws Exception {
+ when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(),
+ anyInt(), anyBoolean())).thenReturn(true);
+ // This is so that IBackupAgent.Stub.asInterface() works.
+ when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub);
+ when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID);
+
+ // This is going to block until it receives the callback so we need to run it on a
+ // separate thread.
+ Thread testThread = new Thread(() -> setBackupAgentResult(
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD)),
+ "backup-agent-connection-manager-test");
+ testThread.start();
+ // Give the testThread a head start, otherwise agentConnected() might run before
+ // bindToAgentSynchronous() is called.
+ Thread.sleep(500);
+ mConnectionManager.agentDisconnected(TEST_PACKAGE);
+ testThread.join();
+
+ assertThat(mBackupAgentResult).isNull();
+ verify(mActivityManagerInternal).clearPendingBackup(UserHandle.USER_SYSTEM);
+ }
+
+ @Test
+ public void bindToAgentSynchronous_agentConnectedCalled_returnsBackupAgent() throws Exception {
+ when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(),
+ anyInt(), anyBoolean())).thenReturn(true);
+ // This is so that IBackupAgent.Stub.asInterface() works.
+ when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub);
+ when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID);
+
+ // This is going to block until it receives the callback so we need to run it on a
+ // separate thread.
+ Thread testThread = new Thread(() -> setBackupAgentResult(
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD)),
+ "backup-agent-connection-manager-test");
+ testThread.start();
+ // Give the testThread a head start, otherwise agentConnected() might run before
+ // bindToAgentSynchronous() is called.
+ Thread.sleep(500);
+ mConnectionManager.agentConnected(TEST_PACKAGE, mBackupAgentStub);
+ testThread.join();
+
+ assertThat(mBackupAgentResult).isEqualTo(mBackupAgentStub);
+ verify(mActivityManagerInternal, never()).clearPendingBackup(anyInt());
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public void bindToAgentSynchronous_restrictedModeChangesFlagOff_shouldUseRestrictedMode()
+ throws Exception {
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(true));
+ // Make sure we never hit the code that checks the property.
+ verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public void bindToAgentSynchronous_keyValueBackup_shouldNotUseRestrictedMode()
+ throws Exception {
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(false));
+ // Make sure we never hit the code that checks the property.
+ verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public void bindToAgentSynchronous_keyValueRestore_shouldNotUseRestrictedMode()
+ throws Exception {
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_RESTORE, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(false));
+ // Make sure we never hit the code that checks the property.
+ verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public void bindToAgentSynchronous_packageOptedIn_shouldUseRestrictedMode() throws Exception {
+ reset(mPackageManager);
+ when(mPackageManager.getPropertyAsUser(
+ eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(),
+ anyInt())).thenReturn(new PackageManager.Property(
+ PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ true,
+ TEST_PACKAGE, /* className= */ null));
+
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(true));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ public void bindToAgentSynchronous_packageOptedOut_shouldNotUseRestrictedMode()
+ throws Exception {
+ reset(mPackageManager);
+ when(mPackageManager.getPropertyAsUser(
+ eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(),
+ anyInt())).thenReturn(new PackageManager.Property(
+ PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ false,
+ TEST_PACKAGE, /* className= */ null));
+
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(false));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ @DisableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+ public void bindToAgentSynchronous_targetSdkBelowB_shouldUseRestrictedMode() throws Exception {
+ reset(mPackageManager);
+ // Mock that the app has not explicitly set the property.
+ when(mPackageManager.getPropertyAsUser(
+ eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(),
+ anyInt())).thenThrow(new PackageManager.NameNotFoundException());
+
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(true));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ @EnableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+ public void bindToAgentSynchronous_targetSdkB_notInList_shouldUseRestrictedMode()
+ throws Exception {
+ reset(mPackageManager);
+ // Mock that the app has not explicitly set the property.
+ when(mPackageManager.getPropertyAsUser(
+ eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(),
+ anyInt())).thenThrow(new PackageManager.NameNotFoundException());
+ mConnectionManager.clearNoRestrictedModePackages();
+
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(true));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ @EnableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+ public void bindToAgentSynchronous_forRestore_targetSdkB_inList_shouldNotUseRestrictedMode()
+ throws Exception {
+ reset(mPackageManager);
+ // Mock that the app has not explicitly set the property.
+ when(mPackageManager.getPropertyAsUser(
+ eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(),
+ anyInt())).thenThrow(new PackageManager.NameNotFoundException());
+ mConnectionManager.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.RESTORE);
+
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(false));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+ @EnableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+ public void bindToAgentSynchronous_forBackup_targetSdkB_inList_shouldNotUseRestrictedMode()
+ throws Exception {
+ reset(mPackageManager);
+ // Mock that the app has not explicitly set the property.
+ when(mPackageManager.getPropertyAsUser(
+ eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(),
+ anyInt())).thenThrow(new PackageManager.NameNotFoundException());
+ mConnectionManager.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.BACKUP);
+
+ mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+ ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+ verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+ /* useRestrictedMode= */ eq(false));
+ }
+
+ @Test
+ public void agentDisconnected_cancelsCurrentOperations() throws Exception {
+ when(mOperationStorage.operationTokensForPackage(eq(TEST_PACKAGE))).thenReturn(
+ ImmutableSet.of(123, 456, 789));
+ when(mConnectionManager.getThreadForCancellation(any())).thenAnswer(invocation -> {
+ Thread testThread = new Thread((Runnable) invocation.getArgument(0),
+ "agent-disconnected-test");
+ setTestThread(testThread);
+ return testThread;
+ });
+
+ mConnectionManager.agentDisconnected(TEST_PACKAGE);
+
+ mTestThread.join();
+ verify(mUserBackupManagerService).handleCancel(eq(123), eq(true));
+ verify(mUserBackupManagerService).handleCancel(eq(456), eq(true));
+ verify(mUserBackupManagerService).handleCancel(eq(789), eq(true));
+ }
+
+ @Test
+ public void unbindAgent_callsAmUnbindBackupAgent() throws Exception {
+ mConnectionManager.unbindAgent(mTestApplicationInfo);
+
+ verify(mActivityManager).unbindBackupAgent(eq(mTestApplicationInfo));
+ }
+
+ // Needed because variables can't be assigned directly inside lambdas in Java.
+ private void setBackupAgentResult(IBackupAgent result) {
+ mBackupAgentResult = result;
+ }
+
+ // Needed because variables can't be assigned directly inside lambdas in Java.
+ private void setTestThread(Thread thread) {
+ mTestThread = thread;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 65286d9aabc7..7a9e96f1bc4c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -21,38 +21,38 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.app.IActivityManager;
import android.app.backup.BackupAgent;
-import android.app.backup.BackupAnnotations;
import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
+import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.testing.TestableContext;
import android.util.FeatureFlagUtils;
import android.util.KeyValueListParser;
import androidx.test.core.app.ApplicationProvider;
-import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.backup.internal.BackupHandler;
@@ -64,11 +64,11 @@ import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.BackupManagerMonitorEventSender;
-import com.google.common.collect.ImmutableSet;
-
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -77,7 +77,6 @@ import org.mockito.quality.Strictness;
import java.util.Arrays;
import java.util.List;
-import java.util.function.IntConsumer;
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -85,9 +84,13 @@ public class UserBackupManagerServiceTest {
private static final String TEST_PACKAGE = "package1";
private static final String[] TEST_PACKAGES = new String[] { TEST_PACKAGE };
private static final String TEST_TRANSPORT = "transport";
- private static final int WORKER_THREAD_TIMEOUT_MILLISECONDS = 100;
@UserIdInt private static final int USER_ID = 0;
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock IBackupManagerMonitor mBackupManagerMonitor;
@Mock IBackupObserver mBackupObserver;
@Mock PackageManager mPackageManager;
@@ -99,10 +102,14 @@ public class UserBackupManagerServiceTest {
@Mock JobScheduler mJobScheduler;
@Mock BackupHandler mBackupHandler;
@Mock BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
+ @Mock IActivityManager mActivityManager;
+ @Mock
+ ActivityManagerInternal mActivityManagerInternal;
private TestableContext mContext;
private MockitoSession mSession;
private TestBackupService mService;
+ private ApplicationInfo mTestPackageApplicationInfo;
@Before
public void setUp() throws Exception {
@@ -120,12 +127,14 @@ public class UserBackupManagerServiceTest {
mContext.getTestablePermissions().setPermission(android.Manifest.permission.BACKUP,
PackageManager.PERMISSION_GRANTED);
- mService = new TestBackupService(mContext, mPackageManager, mOperationStorage,
- mTransportManager, mBackupHandler);
+ mService = new TestBackupService();
mService.setEnabled(true);
mService.setSetupComplete(true);
mService.enqueueFullBackup("com.test.backup.app", /* lastBackedUp= */ 0);
- }
+
+ mTestPackageApplicationInfo = new ApplicationInfo();
+ mTestPackageApplicationInfo.packageName = TEST_PACKAGE;
+ }
@After
public void tearDown() {
@@ -256,33 +265,6 @@ public class UserBackupManagerServiceTest {
}
@Test
- @FlakyTest
- public void testAgentDisconnected_cancelsCurrentOperations() throws Exception {
- when(mOperationStorage.operationTokensForPackage(eq("com.android.foo"))).thenReturn(
- ImmutableSet.of(123, 456, 789)
- );
-
- mService.agentDisconnected("com.android.foo");
-
- mService.waitForAsyncOperation();
- verify(mOperationStorage).cancelOperation(eq(123), eq(true), any(IntConsumer.class));
- verify(mOperationStorage).cancelOperation(eq(456), eq(true), any());
- verify(mOperationStorage).cancelOperation(eq(789), eq(true), any());
- }
-
- @Test
- public void testAgentDisconnected_unknownPackageName_cancelsNothing() throws Exception {
- when(mOperationStorage.operationTokensForPackage(eq("com.android.foo"))).thenReturn(
- ImmutableSet.of()
- );
-
- mService.agentDisconnected("com.android.foo");
-
- verify(mOperationStorage, never())
- .cancelOperation(anyInt(), anyBoolean(), any(IntConsumer.class));
- }
-
- @Test
public void testReportDelayedRestoreResult_sendsLogsToMonitor() throws Exception {
PackageInfo packageInfo = getPackageInfo(TEST_PACKAGE);
when(mPackageManager.getPackageInfoAsUser(anyString(),
@@ -298,9 +280,8 @@ public class UserBackupManagerServiceTest {
new DataTypeResult(/* dataType */ "type_2"));
mService.reportDelayedRestoreResult(TEST_PACKAGE, results);
-
verify(mBackupManagerMonitorEventSender).sendAgentLoggingResults(
- eq(packageInfo), eq(results), eq(BackupAnnotations.OperationType.RESTORE));
+ eq(packageInfo), eq(results), eq(OperationType.RESTORE));
}
private static PackageInfo getPackageInfo(String packageName) {
@@ -314,13 +295,9 @@ public class UserBackupManagerServiceTest {
boolean isEnabledStatePersisted = false;
boolean shouldUseNewBackupEligibilityRules = false;
- private volatile Thread mWorkerThread = null;
-
- TestBackupService(Context context, PackageManager packageManager,
- LifecycleOperationStorage operationStorage, TransportManager transportManager,
- BackupHandler backupHandler) {
- super(context, packageManager, operationStorage, transportManager, backupHandler,
- createConstants(context));
+ TestBackupService() {
+ super(mContext, mPackageManager, mOperationStorage, mTransportManager, mBackupHandler,
+ createConstants(mContext), mActivityManager, mActivityManagerInternal);
}
private static BackupManagerConstants createConstants(Context context) {
@@ -352,26 +329,8 @@ public class UserBackupManagerServiceTest {
}
@Override
- Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
- mWorkerThread = super.getThreadForAsyncOperation(operationName, operation);
- return mWorkerThread;
- }
-
- @Override
BackupManagerMonitorEventSender getBMMEventSender(IBackupManagerMonitor monitor) {
return mBackupManagerMonitorEventSender;
}
-
- private void waitForAsyncOperation() {
- if (mWorkerThread == null) {
- return;
- }
-
- try {
- mWorkerThread.join(/* millis */ WORKER_THREAD_TIMEOUT_MILLISECONDS);
- } catch (InterruptedException e) {
- fail("Failed waiting for worker thread to complete: " + e.getMessage());
- }
- }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
index 94742537ed1a..e618433862f2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
@@ -18,34 +18,100 @@ package com.android.server.backup.fullbackup;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.when;
+import android.app.backup.BackupAnnotations;
+import android.app.backup.BackupTransport;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.backup.BackupAgentConnectionManager;
+import com.android.server.backup.BackupAgentTimeoutParameters;
+import com.android.server.backup.OperationStorage;
import com.android.server.backup.TransportManager;
import com.android.server.backup.UserBackupManagerService;
+import com.android.server.backup.transport.BackupTransportClient;
+import com.android.server.backup.transport.TransportConnection;
+import com.android.server.backup.utils.BackupEligibilityRules;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
@Presubmit
@RunWith(AndroidJUnit4.class)
public class PerformFullTransportBackupTaskTest {
+ private static final String TEST_PACKAGE_1 = "package1";
+ private static final String TEST_PACKAGE_2 = "package2";
+
+ @Mock
+ BackupAgentTimeoutParameters mBackupAgentTimeoutParameters;
+ @Mock
+ BackupEligibilityRules mBackupEligibilityRules;
@Mock
UserBackupManagerService mBackupManagerService;
@Mock
+ BackupAgentConnectionManager mBackupAgentConnectionManager;
+ @Mock
+ BackupTransportClient mBackupTransportClient;
+ @Mock
+ CountDownLatch mLatch;
+ @Mock
+ OperationStorage mOperationStorage;
+ @Mock
+ PackageManager mPackageManager;
+ @Mock
+ TransportConnection mTransportConnection;
+ @Mock
TransportManager mTransportManager;
+ @Mock
+ UserBackupManagerService.BackupWakeLock mWakeLock;
+
+ private final List<String> mEligiblePackages = new ArrayList<>();
+
+ private PerformFullTransportBackupTask mTask;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ when(mBackupManagerService.getPackageManager()).thenReturn(mPackageManager);
+ when(mBackupManagerService.getQueueLock()).thenReturn("something!");
+ when(mBackupManagerService.isEnabled()).thenReturn(true);
+ when(mBackupManagerService.getWakelock()).thenReturn(mWakeLock);
+ when(mBackupManagerService.isSetupComplete()).thenReturn(true);
+ when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(
+ mBackupAgentTimeoutParameters);
+ when(mBackupManagerService.getBackupAgentConnectionManager()).thenReturn(
+ mBackupAgentConnectionManager);
when(mBackupManagerService.getTransportManager()).thenReturn(mTransportManager);
+ when(mTransportManager.getCurrentTransportClient(any())).thenReturn(mTransportConnection);
+ when(mTransportConnection.connectOrThrow(any())).thenReturn(mBackupTransportClient);
+ when(mTransportConnection.connect(any())).thenReturn(mBackupTransportClient);
+ when(mBackupTransportClient.performFullBackup(any(), any(), anyInt())).thenReturn(
+ BackupTransport.TRANSPORT_ERROR);
+ when(mBackupEligibilityRules.appIsEligibleForBackup(
+ argThat(app -> mEligiblePackages.contains(app.packageName)))).thenReturn(
+ true);
+ when(mBackupEligibilityRules.appGetsFullBackup(
+ argThat(app -> mEligiblePackages.contains(app.packageName)))).thenReturn(
+ true);
}
@Test
@@ -70,4 +136,49 @@ public class PerformFullTransportBackupTaskTest {
/* backupEligibilityRules */ null);
});
}
+
+ @Test
+ public void run_setsAndClearsNoRestrictedModePackages() throws Exception {
+ mockPackageEligibleForFullBackup(TEST_PACKAGE_1);
+ mockPackageEligibleForFullBackup(TEST_PACKAGE_2);
+ createTask(new String[] {TEST_PACKAGE_1, TEST_PACKAGE_2});
+ when(mBackupTransportClient.getPackagesThatShouldNotUseRestrictedMode(any(),
+ anyInt())).thenReturn(Set.of("package1"));
+
+ mTask.run();
+
+ InOrder inOrder = inOrder(mBackupAgentConnectionManager);
+ inOrder.verify(mBackupAgentConnectionManager).setNoRestrictedModePackages(
+ eq(Set.of("package1")),
+ eq(BackupAnnotations.OperationType.BACKUP));
+ inOrder.verify(mBackupAgentConnectionManager).clearNoRestrictedModePackages();
+ }
+
+ private void createTask(String[] packageNames) {
+ mTask = PerformFullTransportBackupTask
+ .newWithCurrentTransport(
+ mBackupManagerService,
+ mOperationStorage,
+ /* observer */ null,
+ /* whichPackages */ packageNames,
+ /* updateSchedule */ false,
+ /* runningJob */ null,
+ mLatch,
+ /* backupObserver */ null,
+ /* monitor */ null,
+ /* userInitiated */ false,
+ /* caller */ null,
+ mBackupEligibilityRules);
+ }
+
+ private void mockPackageEligibleForFullBackup(String packageName) throws Exception {
+ mEligiblePackages.add(packageName);
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfo.applicationInfo = appInfo;
+ when(mPackageManager.getPackageInfoAsUser(eq(packageName), anyInt(), anyInt())).thenReturn(
+ packageInfo);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
index 414532b88e22..351aac357c44 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
@@ -23,8 +23,10 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.backup.BackupAnnotations;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupTransport;
@@ -42,6 +44,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.testing.TestableDeviceConfig;
+import com.android.server.backup.BackupAgentConnectionManager;
import com.android.server.backup.Flags;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.internal.BackupHandler;
@@ -91,6 +94,10 @@ public class PerformUnifiedRestoreTaskTest {
private UserBackupManagerService mBackupManagerService;
@Mock
private TransportConnection mTransportConnection;
+ @Mock
+ private BackupTransportClient mBackupTransportClient;
+ @Mock
+ private BackupAgentConnectionManager mBackupAgentConnectionManager;
private Set<String> mExcludedkeys = new HashSet<>();
private Map<String, String> mBackupData = new HashMap<>();
@@ -118,6 +125,9 @@ public class PerformUnifiedRestoreTaskTest {
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ when(mBackupManagerService.getBackupAgentConnectionManager()).thenReturn(
+ mBackupAgentConnectionManager);
+
mBackupDataSource = new ArrayDeque<>(mBackupData.keySet());
when(mBackupDataInput.readNextHeader())
.then((Answer<Boolean>) invocation -> !mBackupDataSource.isEmpty());
@@ -151,6 +161,23 @@ public class PerformUnifiedRestoreTaskTest {
}
@Test
+ public void setNoRestrictedModePackages_callsTransportAndSetsValue() throws Exception {
+ PackageInfo packageInfo1 = new PackageInfo();
+ packageInfo1.packageName = "package1";
+ PackageInfo packageInfo2 = new PackageInfo();
+ packageInfo2.packageName = "package2";
+ when(mBackupTransportClient.getPackagesThatShouldNotUseRestrictedMode(any(),
+ anyInt())).thenReturn(Set.of("package1"));
+
+ mRestoreTask.setNoRestrictedModePackages(mBackupTransportClient,
+ new PackageInfo[]{packageInfo1, packageInfo2});
+
+ verify(mBackupAgentConnectionManager).setNoRestrictedModePackages(
+ eq(Set.of("package1")),
+ eq(BackupAnnotations.OperationType.RESTORE));
+ }
+
+ @Test
public void testFilterExcludedKeys() throws Exception {
when(mBackupManagerService.getExcludedRestoreKeys(eq(PACKAGE_NAME)))
.thenReturn(mExcludedkeys);
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
index 2d7d46f83c47..13e32078f609 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
@@ -19,7 +19,14 @@ package com.android.server.backup.transport;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
-
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+
+import android.app.backup.BackupAnnotations.OperationType;
import android.app.backup.BackupTransport;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.RestoreDescription;
@@ -38,15 +45,31 @@ import com.android.internal.backup.IBackupTransport;
import com.android.internal.backup.ITransportStatusCallback;
import com.android.internal.infra.AndroidFuture;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.List;
+import java.util.Set;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class BackupTransportClientTest {
+ @Mock
+ IBackupTransport mMockBackupTransport;
+
+ private BackupTransportClient mMockingTransportClient;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mMockingTransportClient = new BackupTransportClient(
+ mMockBackupTransport);
+ }
+
private static class TestFuturesFakeTransportBinder extends FakeTransportBinderBase {
public final Object mLock = new Object();
@@ -128,6 +151,70 @@ public class BackupTransportClientTest {
thread.join();
}
+ @Test
+ public void getPackagesThatShouldNotUseRestrictedMode_passesSetAsListToBinder()
+ throws Exception {
+ mockGetPackagesThatShouldNotUseRestrictedModeReturn(List.of("package1", "package2"));
+
+ mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+ Set.of("package1", "package2"),
+ OperationType.BACKUP);
+
+ verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(
+ argThat(list -> Set.copyOf(list).equals(Set.of("package1", "package2"))),
+ eq(OperationType.BACKUP), any());
+ }
+
+ @Test
+ public void getPackagesThatShouldNotUseRestrictedMode_forRestore_callsBinderForRestore()
+ throws Exception {
+ mockGetPackagesThatShouldNotUseRestrictedModeReturn(null);
+
+ mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+ Set.of(),
+ OperationType.RESTORE);
+
+ verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(),
+ eq(OperationType.RESTORE), any());
+ }
+
+ @Test
+ public void getPackagesThatShouldNotUseRestrictedMode_forBackup_callsBinderForBackup()
+ throws Exception {
+ mockGetPackagesThatShouldNotUseRestrictedModeReturn(null);
+
+ mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+ Set.of(),
+ OperationType.BACKUP);
+
+ verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(),
+ eq(OperationType.BACKUP), any());
+ }
+
+ @Test
+ public void getPackagesThatShouldNotUseRestrictedMode_nullResult_returnsEmptySet()
+ throws Exception {
+ mockGetPackagesThatShouldNotUseRestrictedModeReturn(null);
+
+ Set<String> result = mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+ Set.of(),
+ OperationType.BACKUP);
+
+ assertThat(result).isEqualTo(Set.of());
+ }
+
+ @Test
+ public void getPackagesThatShouldNotUseRestrictedMode_returnsResultAsSet()
+ throws Exception {
+ mockGetPackagesThatShouldNotUseRestrictedModeReturn(List.of("package1", "package2"));
+
+ Set<String> result = mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+ Set.of("package1", "package2"),
+ OperationType.BACKUP);
+
+ assertThat(result).isEqualTo(Set.of("package1", "package2"));
+ }
+
private static class TestCallbacksFakeTransportBinder extends FakeTransportBinderBase {
public final Object mLock = new Object();
@@ -158,7 +245,6 @@ public class BackupTransportClientTest {
assertThat(status).isEqualTo(123);
}
-
@Test
public void testFinishBackup_completesLater_returnsStatus() throws Exception {
TestCallbacksFakeTransportBinder binder = new TestCallbacksFakeTransportBinder();
@@ -211,6 +297,14 @@ public class BackupTransportClientTest {
thread.join();
}
+ private void mockGetPackagesThatShouldNotUseRestrictedModeReturn(List<String> returnList)
+ throws Exception {
+ doAnswer(
+ i -> ((AndroidFuture<List<String>>) i.getArguments()[2]).complete(returnList)).when(
+ mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(), anyInt(),
+ any());
+ }
+
// Convenience layer so we only need to fake specific methods useful for each test case.
private static class FakeTransportBinderBase implements IBackupTransport {
@Override public void name(AndroidFuture<String> f) throws RemoteException {}
@@ -258,6 +352,10 @@ public class BackupTransportClientTest {
@Override
public void getBackupManagerMonitor(AndroidFuture<IBackupManagerMonitor> resultFuture)
throws RemoteException {}
+ @Override
+ public void getPackagesThatShouldNotUseRestrictedMode(List<String> packageNames,
+ int operationType, AndroidFuture<List<String>> resultFuture)
+ throws RemoteException {}
@Override public IBinder asBinder() {
return null;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
index 1f88c29e2abc..8eae9c7d71fa 100644
--- a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
@@ -37,7 +37,7 @@ android_test {
"truth",
"flag-junit",
] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
- "true": ["service-crashrecovery.impl"],
+ "true": ["service-crashrecovery-pre-jarjar"],
default: [],
}),
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 d66bb00ae879..c6870adb8464 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
@@ -65,6 +65,7 @@ import android.app.job.JobInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
+import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -103,10 +104,13 @@ import com.android.server.job.controllers.QuotaController.TimedEvent;
import com.android.server.job.controllers.QuotaController.TimingSession;
import com.android.server.usage.AppStandbyInternal;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
@@ -135,6 +139,9 @@ public class QuotaControllerTest {
private static final int SOURCE_USER_ID = 0;
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
private QuotaController mQuotaController;
private QuotaController.QcConstants mQcConstants;
private JobSchedulerService.Constants mConstants = new JobSchedulerService.Constants();
@@ -303,7 +310,7 @@ public class QuotaControllerTest {
private int getProcessStateQuotaFreeThreshold() {
synchronized (mQuotaController.mLock) {
- return mQuotaController.getProcessStateQuotaFreeThreshold();
+ return mQuotaController.getProcessStateQuotaFreeThreshold(mSourceUid);
}
}
@@ -5197,6 +5204,101 @@ public class QuotaControllerTest {
assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
}
+ @Test
+ @EnableCompatChanges({QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+ QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS})
+ @RequiresFlagsEnabled({Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_TOP_STARTED_JOBS,
+ Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_FGS_JOBS})
+ public void testTracking_OutOfQuota_ForegroundAndBackground_CompactChangeOverrides() {
+ setDischarging();
+
+ JobStatus jobBg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 1);
+ JobStatus jobTop = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 2);
+ trackJobs(jobBg, jobTop);
+ setStandbyBucket(WORKING_INDEX, jobTop, jobBg); // 2 hour window
+ // Now the package only has 20 seconds to run.
+ final long remainingTimeMs = 20 * SECOND_IN_MILLIS;
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+ 10 * MINUTE_IN_MILLIS - remainingTimeMs, 1), false);
+
+ InOrder inOrder = inOrder(mJobSchedulerService);
+
+ // UID starts out inactive.
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+ // Start the job.
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.prepareForExecutionLocked(jobBg);
+ }
+ advanceElapsedClock(remainingTimeMs / 2);
+ // New job starts after UID is in the foreground. Since the app is now in the foreground, it
+ // should continue to have remainingTimeMs / 2 time remaining.
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.prepareForExecutionLocked(jobTop);
+ }
+ advanceElapsedClock(remainingTimeMs);
+
+ // Wait for some extra time to allow for job processing.
+ inOrder.verify(mJobSchedulerService,
+ timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+ .onControllerStateChanged(argThat(jobs -> jobs.size() > 0));
+ synchronized (mQuotaController.mLock) {
+ assertEquals(remainingTimeMs / 2,
+ mQuotaController.getRemainingExecutionTimeLocked(jobBg));
+ assertEquals(remainingTimeMs / 2,
+ mQuotaController.getRemainingExecutionTimeLocked(jobTop));
+ }
+ // Go to a background state.
+ setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+ advanceElapsedClock(remainingTimeMs / 2 + 1);
+ // Only Bg job will be changed from in-quota to out-of-quota.
+ inOrder.verify(mJobSchedulerService,
+ timeout(remainingTimeMs / 2 + 2 * SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged(argThat(jobs -> jobs.size() == 1));
+ // Top job should still be allowed to run.
+ assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ // New jobs to run.
+ JobStatus jobBg2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 3);
+ JobStatus jobTop2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 4);
+ JobStatus jobFg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 5);
+ setStandbyBucket(WORKING_INDEX, jobBg2, jobTop2, jobFg);
+
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged(argThat(jobs -> jobs.size() == 1));
+ trackJobs(jobFg, jobTop);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.prepareForExecutionLocked(jobTop);
+ }
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ // App still in foreground so everything should be in quota.
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+ inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged(argThat(jobs -> jobs.size() == 2));
+ // App is now in background and out of quota. Fg should now change to out of quota since it
+ // wasn't started. Top should remain in quota since it started when the app was in TOP.
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertFalse(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ trackJobs(jobBg2);
+ assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ }
+
/**
* Tests that TOP jobs are stopped when an app runs out of quota.
*/
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index 769f071e3ddc..405024cc0e34 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -134,7 +134,7 @@ public class ApexManagerTest {
mMockSystem.system().validateFinalState();
mInstallPackageHelper = new InstallPackageHelper(mPmService, mock(AppDataHelper.class),
mock(RemovePackageHelper.class), mock(DeletePackageHelper.class),
- mock(BroadcastHelper.class));
+ mock(BroadcastHelper.class), mock(InstallDependencyHelper.class));
}
@NonNull
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
index f6c644e3d4d4..0304a74f7654 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.ApkLite;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -34,6 +35,8 @@ import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
import android.os.OutcomeReceiver;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -71,13 +74,19 @@ public class InstallDependencyHelperTest {
private static final String PUSH_FILE_DIR = "/data/local/tmp/tests/smockingservicestest/pm/";
private static final String TEST_APP_USING_SDK1_AND_SDK2 = "HelloWorldUsingSdk1And2.apk";
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
@Mock private SharedLibrariesImpl mSharedLibraries;
+ @Mock private Context mContext;
+ @Mock private Computer mComputer;
+ @Mock private PackageInstallerService mPackageInstallerService;
private InstallDependencyHelper mInstallDependencyHelper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mInstallDependencyHelper = new InstallDependencyHelper(mSharedLibraries);
+ mInstallDependencyHelper = new InstallDependencyHelper(mContext, mSharedLibraries,
+ mPackageInstallerService);
}
@Test
@@ -88,7 +97,8 @@ public class InstallDependencyHelperTest {
PackageLite pkg = getPackageLite(TEST_APP_USING_SDK1_AND_SDK2);
CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false);
- mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback);
+ mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer,
+ 0, mHandler, callback);
callback.assertFailure();
assertThat(callback.error).hasMessageThat().contains("xyz");
@@ -104,11 +114,12 @@ public class InstallDependencyHelperTest {
.thenReturn(missingDependency);
CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false);
- mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback);
+ mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer,
+ 0, mHandler, callback);
callback.assertFailure();
assertThat(callback.error).hasMessageThat().contains(
- "Failed to bind to Dependency Installer");
+ "Dependency Installer Service not found");
}
@@ -121,7 +132,8 @@ public class InstallDependencyHelperTest {
.thenReturn(missingDependency);
CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ true);
- mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback);
+ mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer,
+ 0, mHandler, callback);
callback.assertSuccess();
}
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 0a6edf1b9831..b53dbc834351 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -218,6 +218,8 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
val handler = TestHandler(null)
val defaultAppProvider: DefaultAppProvider = mock()
val backgroundHandler = TestHandler(null)
+ val packageInstallerService: PackageInstallerService = mock()
+ val installDependencyHelper: InstallDependencyHelper = mock()
val updateOwnershipHelper: UpdateOwnershipHelper = mock()
}
@@ -306,6 +308,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
whenever(mocks.injector.handler) { mocks.handler }
whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider }
whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler }
+ whenever(mocks.injector.packageInstallerService) { mocks.packageInstallerService }
whenever(mocks.injector.updateOwnershipHelper) { mocks.updateOwnershipHelper }
whenever(mocks.injector.getSystemService(AppOpsManager::class.java)) { mocks.appOpsManager }
wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
@@ -332,6 +335,8 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
DEVICE_PROVISIONING_PACKAGE_NAME
}
whenever(mocks.apexManager.activeApexInfos).thenReturn(DEFAULT_ACTIVE_APEX_INFO_LIST)
+ whenever(mocks.packageInstallerService.installDependencyHelper).thenReturn(
+ mocks.installDependencyHelper)
whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index 71c60ad02794..6f5e2b713260 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -741,11 +741,6 @@ public class StagingManagerTest {
/* stagedSessionErrorCode */ PackageManager.INSTALL_UNKNOWN,
/* stagedSessionErrorMessage */ "no error",
/* preVerifiedDomains */ null,
- /* verifierController */ null,
- /* initialVerificationPolicy */
- PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED,
- /* currentVerificationPolicy */
- PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED,
/* installDependencyHelper */ null);
StagingManager.StagedSession stagedSession = spy(session.mStagedSession);
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
index 2f23e02f5737..5a802d9de2ff 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
@@ -35,7 +35,7 @@ android_test {
"truth",
"flag-junit",
] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
- "true": ["service-crashrecovery.impl"],
+ "true": ["service-crashrecovery-pre-jarjar"],
default: [],
}),
diff --git a/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java b/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java
index d3943e32ef07..d12579cd6b11 100644
--- a/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java
+++ b/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java
@@ -18,10 +18,10 @@ package com.android.server.ondeviceintelligence;
import static com.google.common.truth.Truth.assertThat;
+import android.app.ondeviceintelligence.InferenceInfo;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService;
-import android.app.ondeviceintelligence.InferenceInfo;
import android.util.Base64;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -32,7 +32,6 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.IOException;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@@ -53,8 +52,8 @@ public class InferenceInfoStoreTest {
List<InferenceInfo> inferenceInfos = inferenceInfoStore.getLatestInferenceInfo(0);
assertThat(inferenceInfos).hasSize(1);
assertThat(inferenceInfos.get(0).getUid()).isEqualTo(1);
- assertThat(inferenceInfos.get(0).getStartTimeMs()).isEqualTo(1);
- assertThat(inferenceInfos.get(0).getEndTimeMs()).isEqualTo(100);
+ assertThat(inferenceInfos.get(0).getStartTimeMillis()).isEqualTo(1);
+ assertThat(inferenceInfos.get(0).getEndTimeMillis()).isEqualTo(100);
}
@Test
@@ -66,8 +65,8 @@ public class InferenceInfoStoreTest {
List<InferenceInfo> inferenceInfos = inferenceInfoStore.getLatestInferenceInfo(0);
assertThat(inferenceInfos).hasSize(1);
assertThat(inferenceInfos.get(0).getUid()).isEqualTo(1);
- assertThat(inferenceInfos.get(0).getStartTimeMs()).isEqualTo(1);
- assertThat(inferenceInfos.get(0).getEndTimeMs()).isEqualTo(100);
+ assertThat(inferenceInfos.get(0).getStartTimeMillis()).isEqualTo(1);
+ assertThat(inferenceInfos.get(0).getEndTimeMillis()).isEqualTo(100);
}
@@ -87,8 +86,8 @@ public class InferenceInfoStoreTest {
List<InferenceInfo> inferenceInfos = inferenceInfoStore.getLatestInferenceInfo(0);
assertThat(inferenceInfos).hasSize(2);
assertThat(inferenceInfos.get(0).getUid()).isEqualTo(1);
- assertThat(inferenceInfos.get(0).getStartTimeMs()).isEqualTo(testStartTime - 10);
- assertThat(inferenceInfos.get(0).getEndTimeMs()).isEqualTo(testStartTime + 100);
+ assertThat(inferenceInfos.get(0).getStartTimeMillis()).isEqualTo(testStartTime - 10);
+ assertThat(inferenceInfos.get(0).getEndTimeMillis()).isEqualTo(testStartTime + 100);
inferenceInfoStore.addInferenceInfoFromBundle(bundle);
List<InferenceInfo> inferenceInfos2 = inferenceInfoStore.getLatestInferenceInfo(0);
assertThat(inferenceInfos2).hasSize(1); //previous entries should have been evicted
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 58489f398775..e631cb66eaf7 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -18,6 +18,7 @@ package com.android.server.power.hint;
import static com.android.server.power.hint.HintManagerService.CLEAN_UP_UID_DELAY_MILLIS;
+import static com.android.server.power.hint.HintManagerService.DEFAULT_HEADROOM_PID;
import static com.google.common.truth.Truth.assertThat;
@@ -51,16 +52,21 @@ import android.content.pm.PackageManager;
import android.hardware.common.fmq.MQDescriptor;
import android.hardware.power.ChannelConfig;
import android.hardware.power.ChannelMessage;
+import android.hardware.power.CpuHeadroomParams;
+import android.hardware.power.GpuHeadroomParams;
import android.hardware.power.IPower;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
import android.hardware.power.WorkDuration;
import android.os.Binder;
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParamsInternal;
import android.os.IBinder;
import android.os.IHintSession;
import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SessionCreationConfig;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -128,11 +134,11 @@ public class HintManagerServiceTest {
private static final long[] TIMESTAMPS_ZERO = new long[] {};
private static final long[] TIMESTAMPS_TWO = new long[] {1L, 2L};
private static final WorkDuration[] WORK_DURATIONS_FIVE = new WorkDuration[] {
- makeWorkDuration(1L, 11L, 1L, 8L, 4L),
- makeWorkDuration(2L, 13L, 2L, 8L, 6L),
- makeWorkDuration(3L, 333333333L, 3L, 8L, 333333333L),
- makeWorkDuration(2L, 13L, 2L, 0L, 6L),
- makeWorkDuration(2L, 13L, 2L, 8L, 0L),
+ makeWorkDuration(1L, 11L, 1L, 8L, 4L),
+ makeWorkDuration(2L, 13L, 2L, 8L, 6L),
+ makeWorkDuration(3L, 333333333L, 3L, 8L, 333333333L),
+ makeWorkDuration(2L, 13L, 2L, 0L, 6L),
+ makeWorkDuration(2L, 13L, 2L, 8L, 0L),
};
private static final String TEST_APP_NAME = "com.android.test.app";
@@ -187,17 +193,17 @@ public class HintManagerServiceTest {
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
eq(SESSION_TIDS_A), eq(DEFAULT_TARGET_DURATION), anyInt(),
any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[0],
- SESSION_IDS[0]));
+ SESSION_IDS[0]));
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
eq(SESSION_TIDS_B), eq(DOUBLED_TARGET_DURATION), anyInt(),
any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[1],
- SESSION_IDS[1]));
+ SESSION_IDS[1]));
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
eq(SESSION_TIDS_C), eq(0L), anyInt(),
any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[2],
SESSION_IDS[2]));
- when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
+ when(mIPowerMock.getInterfaceVersion()).thenReturn(6);
when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
@@ -217,8 +223,8 @@ public class HintManagerServiceTest {
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_C),
eq(0L))).thenReturn(SESSION_PTRS[2]);
when(mNativeWrapperMock.halCreateHintSessionWithConfig(anyInt(), anyInt(),
- any(int[].class), anyLong(), anyInt(),
- any(SessionConfig.class))).thenThrow(new UnsupportedOperationException());
+ any(int[].class), anyLong(), anyInt(),
+ any(SessionConfig.class))).thenThrow(new UnsupportedOperationException());
}
static class NativeWrapperFake extends NativeWrapper {
@@ -300,6 +306,14 @@ public class HintManagerServiceTest {
return mService;
}
+ private SessionCreationConfig makeSessionCreationConfig(int[] tids,
+ long targetWorkDurationNanos) {
+ SessionCreationConfig config = new SessionCreationConfig();
+ config.tids = tids;
+ config.targetWorkDurationNanos = targetWorkDurationNanos;
+ return config;
+ }
+
@Test
public void testInitializeService() {
HintManagerService service = createService();
@@ -311,12 +325,14 @@ public class HintManagerServiceTest {
public void testCreateHintSessionInvalidPid() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(new int[]{TID, 1}, DEFAULT_TARGET_DURATION);
// Make sure we throw exception when adding a TID doesn't belong to the processes
// In this case, we add `init` PID into the list.
SessionConfig config = new SessionConfig();
assertThrows(SecurityException.class,
() -> service.getBinderServiceInstance().createHintSessionWithConfig(token,
- new int[]{TID, 1}, DEFAULT_TARGET_DURATION, SessionTag.OTHER, config));
+ SessionTag.OTHER, creationConfig, config));
}
@Test
@@ -324,42 +340,54 @@ public class HintManagerServiceTest {
HintManagerService service = createService();
IBinder token = new Binder();
makeConfigCreationUnsupported();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertNotNull(a);
+ creationConfig.tids = SESSION_TIDS_B;
+ creationConfig.targetWorkDurationNanos = DOUBLED_TARGET_DURATION;
IHintSession b = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_B, DOUBLED_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertNotEquals(a, b);
+ creationConfig.tids = SESSION_TIDS_C;
+ creationConfig.targetWorkDurationNanos = 0L;
IHintSession c = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_C, 0L, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertNotNull(c);
verify(mNativeWrapperMock, times(3)).halCreateHintSession(anyInt(), anyInt(),
- any(int[].class), anyLong());
+ any(int[].class), anyLong());
}
@Test
public void testCreateHintSessionWithConfig() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
SessionConfig config = new SessionConfig();
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, config);
+ SessionTag.OTHER, creationConfig, config);
assertNotNull(a);
assertEquals(SESSION_IDS[0], config.id);
SessionConfig config2 = new SessionConfig();
+ creationConfig.tids = SESSION_TIDS_B;
+ creationConfig.targetWorkDurationNanos = DOUBLED_TARGET_DURATION;
IHintSession b = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_B, DOUBLED_TARGET_DURATION, SessionTag.APP, config2);
+ SessionTag.APP, creationConfig, config2);
assertNotEquals(a, b);
assertEquals(SESSION_IDS[1], config2.id);
SessionConfig config3 = new SessionConfig();
+ creationConfig.tids = SESSION_TIDS_C;
+ creationConfig.targetWorkDurationNanos = 0L;
IHintSession c = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_C, 0L, SessionTag.GAME, config3);
+ SessionTag.GAME, creationConfig, config3);
assertNotNull(c);
assertEquals(SESSION_IDS[2], config3.id);
verify(mNativeWrapperMock, times(3)).halCreateHintSessionWithConfig(anyInt(), anyInt(),
@@ -367,13 +395,48 @@ public class HintManagerServiceTest {
}
@Test
+ public void testCreateGraphicsPipelineSessions() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+
+ final int threadCount =
+ service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount();
+ long sessionPtr1 = 1111L;
+ long sessionId1 = 11111L;
+ CountDownLatch stopLatch1 = new CountDownLatch(1);
+ int[] tids1 = createThreads(threadCount, stopLatch1);
+ when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(tids1),
+ eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class)))
+ .thenAnswer(fakeCreateWithConfig(sessionPtr1, sessionId1));
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
+
+ creationConfig.modesToEnable = new int[] {1}; // GRAPHICS_PIPELINE
+
+ SessionConfig config = new SessionConfig();
+ IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
+ SessionTag.OTHER, creationConfig, config);
+ assertNotNull(a);
+ assertEquals(sessionId1, config.id);
+
+ creationConfig.tids = createThreads(1, stopLatch1);
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().createHintSessionWithConfig(token,
+ SessionTag.OTHER, creationConfig, config);
+ });
+ }
+
+ @Test
public void testPauseResumeHintSession() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
// Set session to background and calling updateHintAllowedByProcState() would invoke
// pause();
@@ -409,9 +472,11 @@ public class HintManagerServiceTest {
public void testCloseHintSession() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
a.close();
verify(mNativeWrapperMock, times(1)).halCloseHintSession(anyLong());
@@ -421,9 +486,11 @@ public class HintManagerServiceTest {
public void testUpdateTargetWorkDuration() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertThrows(IllegalArgumentException.class, () -> {
a.updateTargetWorkDuration(-1L);
@@ -441,10 +508,12 @@ public class HintManagerServiceTest {
public void testReportActualWorkDuration() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.updateTargetWorkDuration(100L);
a.reportActualWorkDuration(DURATIONS_THREE, TIMESTAMPS_THREE);
@@ -484,10 +553,12 @@ public class HintManagerServiceTest {
public void testSendHint() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
verify(mNativeWrapperMock, times(1)).halSendHint(anyLong(),
@@ -511,10 +582,12 @@ public class HintManagerServiceTest {
public void testDoHintInBackground() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
@@ -533,10 +606,12 @@ public class HintManagerServiceTest {
public void testDoHintInForeground() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
@@ -547,10 +622,12 @@ public class HintManagerServiceTest {
public void testSetThreads() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.updateTargetWorkDuration(100L);
@@ -586,9 +663,11 @@ public class HintManagerServiceTest {
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(tids1),
eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class)))
.thenReturn(sessionPtr1);
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
AppHintSession session1 = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, tids1, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
assertNotNull(session1);
// trigger UID state change by making the process foreground->background, but because the
@@ -621,9 +700,11 @@ public class HintManagerServiceTest {
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(tids1),
eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class)))
.thenReturn(sessionPtr1);
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
AppHintSession session1 = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, tids1, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
assertNotNull(session1);
// let all session 1 threads to exit and the cleanup should force pause the session 1
@@ -729,10 +810,12 @@ public class HintManagerServiceTest {
public void testSetMode() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.setMode(0, true);
verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
@@ -741,12 +824,19 @@ public class HintManagerServiceTest {
a.setMode(0, false);
verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
eq(0), eq(false));
+ }
- assertThrows(IllegalArgumentException.class, () -> {
- a.setMode(-1, true);
- });
+ @Test
+ public void testSetModeSessionInBackGround() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+
+ AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
- reset(mNativeWrapperMock);
// Set session to background, then the duration would not be updated.
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
@@ -758,6 +848,40 @@ public class HintManagerServiceTest {
}
@Test
+ public void testSetModeInvalid() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+
+ AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ a.setMode(-1, true);
+ });
+ }
+
+ @Test
+ public void testSetModeUponSessionCreation() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+ creationConfig.modesToEnable = new int[] {0, 1};
+
+ AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
+ assertNotNull(a);
+ verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
+ eq(0), eq(true));
+ verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
+ eq(1), eq(true));
+ }
+
+ @Test
public void testGetChannel() throws Exception {
HintManagerService service = createService();
Binder token = new Binder();
@@ -945,9 +1069,12 @@ public class HintManagerServiceTest {
private void runAppHintSession(HintManagerService service, int logId,
AtomicReference<Boolean> shouldRun) throws Exception {
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
// we will start some threads and get their valid TIDs to update
int threadCount = 3;
// the list of TIDs
@@ -1012,10 +1139,12 @@ public class HintManagerServiceTest {
public void testReportActualWorkDuration2() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.updateTargetWorkDuration(100L);
a.reportActualWorkDuration2(WORK_DURATIONS_FIVE);
@@ -1096,4 +1225,157 @@ public class HintManagerServiceTest {
verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID));
assertTrue(service.hasChannel(TGID, UID));
}
+
+ @Test
+ public void testHeadroomPowerHalNotSupported() throws Exception {
+ when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
+ HintManagerService service = createService();
+ assertThrows(UnsupportedOperationException.class, () -> {
+ service.getBinderServiceInstance().getCpuHeadroom(null);
+ });
+ assertThrows(UnsupportedOperationException.class, () -> {
+ service.getBinderServiceInstance().getGpuHeadroom(null);
+ });
+ assertThrows(UnsupportedOperationException.class, () -> {
+ service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis();
+ });
+ assertThrows(UnsupportedOperationException.class, () -> {
+ service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis();
+ });
+ }
+
+ @Test
+ public void testCpuHeadroomCache() throws Exception {
+ when(mIPowerMock.getCpuHeadroomMinIntervalMillis()).thenReturn(2000L);
+ CpuHeadroomParamsInternal params1 = new CpuHeadroomParamsInternal();
+ CpuHeadroomParams halParams1 = new CpuHeadroomParams();
+ halParams1.calculationType = CpuHeadroomParams.CalculationType.MIN;
+ halParams1.selectionType = CpuHeadroomParams.SelectionType.ALL;
+ halParams1.pid = Process.myPid();
+
+ CpuHeadroomParamsInternal params2 = new CpuHeadroomParamsInternal();
+ params2.usesDeviceHeadroom = true;
+ params2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+ params2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
+ CpuHeadroomParams halParams2 = new CpuHeadroomParams();
+ halParams2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+ halParams2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
+ halParams2.pid = DEFAULT_HEADROOM_PID;
+
+ float[] headroom1 = new float[] {0.1f};
+ when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(headroom1);
+ float[] headroom2 = new float[] {0.1f, 0.5f};
+ when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(headroom2);
+
+ HintManagerService service = createService();
+ clearInvocations(mIPowerMock);
+
+ service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis();
+ verify(mIPowerMock, times(0)).getCpuHeadroomMinIntervalMillis();
+ service.getBinderServiceInstance().getCpuHeadroom(params1);
+ verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1));
+ service.getBinderServiceInstance().getCpuHeadroom(params2);
+ verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2));
+
+ // verify cache is working
+ clearInvocations(mIPowerMock);
+ assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+ 0.01f);
+ assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+
+ // after 1 more second it should be served with cache still
+ Thread.sleep(1000);
+ clearInvocations(mIPowerMock);
+ assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+ 0.01f);
+ assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+
+ // after 1.5 more second it should be served with cache still as timer reset
+ Thread.sleep(1500);
+ clearInvocations(mIPowerMock);
+ assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+ 0.01f);
+ assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+
+ // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval
+ Thread.sleep(2100);
+ clearInvocations(mIPowerMock);
+ assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+ 0.01f);
+ assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1));
+ verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2));
+ }
+
+ @Test
+ public void testGpuHeadroomCache() throws Exception {
+ when(mIPowerMock.getGpuHeadroomMinIntervalMillis()).thenReturn(2000L);
+ GpuHeadroomParamsInternal params1 = new GpuHeadroomParamsInternal();
+ GpuHeadroomParams halParams1 = new GpuHeadroomParams();
+ halParams1.calculationType = GpuHeadroomParams.CalculationType.MIN;
+
+ GpuHeadroomParamsInternal params2 = new GpuHeadroomParamsInternal();
+ GpuHeadroomParams halParams2 = new GpuHeadroomParams();
+ params2.calculationType =
+ halParams2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE;
+
+ float headroom1 = 0.1f;
+ when(mIPowerMock.getGpuHeadroom(eq(halParams1))).thenReturn(headroom1);
+ float headroom2 = 0.2f;
+ when(mIPowerMock.getGpuHeadroom(eq(halParams2))).thenReturn(headroom2);
+ HintManagerService service = createService();
+ clearInvocations(mIPowerMock);
+
+ service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis();
+ verify(mIPowerMock, times(0)).getGpuHeadroomMinIntervalMillis();
+ assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+ 0.01f);
+ assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
+ verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
+
+ // verify cache is working
+ clearInvocations(mIPowerMock);
+ assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+ 0.01f);
+ assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+
+ // after 1 more second it should be served with cache still
+ Thread.sleep(1000);
+ clearInvocations(mIPowerMock);
+ assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+ 0.01f);
+ assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+
+ // after 1.5 more second it should be served with cache still as timer reset
+ Thread.sleep(1500);
+ clearInvocations(mIPowerMock);
+ assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+ 0.01f);
+ assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+
+ // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval
+ Thread.sleep(2100);
+ clearInvocations(mIPowerMock);
+ assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+ 0.01f);
+ assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+ 0.01f);
+ verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
+ verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
+ }
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 359cf6376239..b48c2d7f5007 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -2705,12 +2705,11 @@ public class PowerManagerServiceTest {
verify(mInvalidateInteractiveCachesMock).call();
listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
- verify(mInvalidateInteractiveCachesMock, times(2)).call();
mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP,
mClock.now(), 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
- verify(mInvalidateInteractiveCachesMock, times(3)).call();
+ verify(mInvalidateInteractiveCachesMock, times(2)).call();
}
@Test
@@ -2732,12 +2731,11 @@ public class PowerManagerServiceTest {
verify(mInvalidateInteractiveCachesMock).call();
listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
- verify(mInvalidateInteractiveCachesMock, times(2)).call();
mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, mClock.now(),
0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
- verify(mInvalidateInteractiveCachesMock, times(3)).call();
+ verify(mInvalidateInteractiveCachesMock, times(2)).call();
}
@Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
index 0d5d277b00ef..ed927c6ab699 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
@@ -26,8 +26,7 @@ import android.content.Context;
import android.os.Process;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodConfig.Config;
+import android.platform.test.ravenwood.RavenwoodRule;
import com.android.internal.os.PowerStats;
import com.android.server.power.feature.flags.Flags;
@@ -39,10 +38,9 @@ import org.junit.Test;
public class WakelockPowerStatsCollectorTest {
- @Config
- public static final RavenwoodConfig sConfig =
- new RavenwoodConfig.Builder()
- .setProvideMainThread(true)
+ @Rule
+ public final RavenwoodRule mRule =
+ new RavenwoodRule.Builder()
.setSystemPropertyImmutable(
"persist.sys.com.android.server.power.feature.flags."
+ "framework_wakelock_info-override",
diff --git a/services/tests/security/forensic/OWNERS b/services/tests/security/forensic/OWNERS
deleted file mode 100644
index 80c9afb96033..000000000000
--- a/services/tests/security/forensic/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 36824
-
-file:platform/frameworks/base:main:/core/java/android/security/forensic/OWNERS
diff --git a/services/tests/security/forensic/TEST_MAPPING b/services/tests/security/forensic/TEST_MAPPING
deleted file mode 100644
index bd8b2ab7c41f..000000000000
--- a/services/tests/security/forensic/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "postsubmit": [
- {
- "name": "ForensicServiceTests"
- }
- ]
-}
diff --git a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
deleted file mode 100644
index 40e00344f87a..000000000000
--- a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (C) 2024 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.security.forensic;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.test.TestLooper;
-import android.security.forensic.ForensicEvent;
-import android.security.forensic.IForensicServiceCommandCallback;
-import android.security.forensic.IForensicServiceStateCallback;
-import android.util.ArrayMap;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.server.ServiceThread;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-public class ForensicServiceTest {
- private static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN;
- private static final int STATE_INVISIBLE = IForensicServiceStateCallback.State.INVISIBLE;
- private static final int STATE_VISIBLE = IForensicServiceStateCallback.State.VISIBLE;
- private static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED;
-
- private static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN;
- private static final int ERROR_PERMISSION_DENIED =
- IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
- private static final int ERROR_INVALID_STATE_TRANSITION =
- IForensicServiceCommandCallback.ErrorCode.INVALID_STATE_TRANSITION;
- private static final int ERROR_BACKUP_TRANSPORT_UNAVAILABLE =
- IForensicServiceCommandCallback.ErrorCode.BACKUP_TRANSPORT_UNAVAILABLE;
- private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
- IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
-
- private Context mContext;
- private BackupTransportConnection mBackupTransportConnection;
- private DataAggregator mDataAggregator;
- private ForensicService mForensicService;
- private TestLooper mTestLooper;
- private Looper mLooper;
- private TestLooper mTestLooperOfDataAggregator;
- private Looper mLooperOfDataAggregator;
-
- @SuppressLint("VisibleForTests")
- @Before
- public void setUp() {
- mContext = spy(ApplicationProvider.getApplicationContext());
-
- mTestLooper = new TestLooper();
- mLooper = mTestLooper.getLooper();
- mTestLooperOfDataAggregator = new TestLooper();
- mLooperOfDataAggregator = mTestLooperOfDataAggregator.getLooper();
- mForensicService = new ForensicService(new MockInjector(mContext));
- mForensicService.onStart();
- }
-
- @Test
- public void testMonitorState_Invisible() throws RemoteException {
- StateCallback scb = new StateCallback();
- assertEquals(STATE_UNKNOWN, scb.mState);
- mForensicService.getBinderService().monitorState(scb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb.mState);
- }
-
- @Test
- public void testMonitorState_Invisible_TwoMonitors() throws RemoteException {
- StateCallback scb1 = new StateCallback();
- assertEquals(STATE_UNKNOWN, scb1.mState);
- mForensicService.getBinderService().monitorState(scb1);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
-
- StateCallback scb2 = new StateCallback();
- assertEquals(STATE_UNKNOWN, scb2.mState);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb2.mState);
- }
-
- @Test
- public void testMakeVisible_FromInvisible() throws RemoteException {
- StateCallback scb = new StateCallback();
- assertEquals(STATE_UNKNOWN, scb.mState);
- mForensicService.getBinderService().monitorState(scb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeVisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testMakeVisible_FromInvisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_INVISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
-
- doReturn(true).when(mDataAggregator).initialize();
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeVisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testMakeVisible_FromInvisible_TwoMonitors_DataSourceUnavailable()
- throws RemoteException {
- mForensicService.setState(STATE_INVISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
-
- doReturn(false).when(mDataAggregator).initialize();
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeVisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
- assertNotNull(ccb.mErrorCode);
- assertEquals(ERROR_DATA_SOURCE_UNAVAILABLE, ccb.mErrorCode.intValue());
- }
-
- @Test
- public void testMakeVisible_FromVisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_VISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeVisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testMakeVisible_FromEnabled_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_ENABLED);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_ENABLED, scb1.mState);
- assertEquals(STATE_ENABLED, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeVisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_ENABLED, scb1.mState);
- assertEquals(STATE_ENABLED, scb2.mState);
- assertNotNull(ccb.mErrorCode);
- assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue());
- }
-
- @Test
- public void testMakeInvisible_FromInvisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_INVISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeInvisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testMakeInvisible_FromVisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_VISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeInvisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testMakeInvisible_FromEnabled_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_ENABLED);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_ENABLED, scb1.mState);
- assertEquals(STATE_ENABLED, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().makeInvisible(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
-
- @Test
- public void testEnable_FromInvisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_INVISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().enable(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
- assertNotNull(ccb.mErrorCode);
- assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue());
- }
-
- @Test
- public void testEnable_FromVisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_VISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
-
- doReturn(true).when(mBackupTransportConnection).initialize();
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().enable(ccb);
- mTestLooper.dispatchAll();
-
- verify(mDataAggregator, times(1)).enable();
- assertEquals(STATE_ENABLED, scb1.mState);
- assertEquals(STATE_ENABLED, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testEnable_FromVisible_TwoMonitors_BackupTransportUnavailable()
- throws RemoteException {
- mForensicService.setState(STATE_VISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
-
- doReturn(false).when(mBackupTransportConnection).initialize();
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().enable(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
- assertNotNull(ccb.mErrorCode);
- assertEquals(ERROR_BACKUP_TRANSPORT_UNAVAILABLE, ccb.mErrorCode.intValue());
- }
-
- @Test
- public void testEnable_FromEnabled_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_ENABLED);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_ENABLED, scb1.mState);
- assertEquals(STATE_ENABLED, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().enable(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_ENABLED, scb1.mState);
- assertEquals(STATE_ENABLED, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testDisable_FromInvisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_INVISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().disable(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_INVISIBLE, scb1.mState);
- assertEquals(STATE_INVISIBLE, scb2.mState);
- assertNotNull(ccb.mErrorCode);
- assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue());
- }
-
- @Test
- public void testDisable_FromVisible_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_VISIBLE);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().disable(ccb);
- mTestLooper.dispatchAll();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testDisable_FromEnabled_TwoMonitors() throws RemoteException {
- mForensicService.setState(STATE_ENABLED);
- StateCallback scb1 = new StateCallback();
- StateCallback scb2 = new StateCallback();
- mForensicService.getBinderService().monitorState(scb1);
- mForensicService.getBinderService().monitorState(scb2);
- mTestLooper.dispatchAll();
- assertEquals(STATE_ENABLED, scb1.mState);
- assertEquals(STATE_ENABLED, scb2.mState);
-
- doNothing().when(mBackupTransportConnection).release();
-
- ServiceThread mockThread = spy(ServiceThread.class);
- mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
-
- CommandCallback ccb = new CommandCallback();
- mForensicService.getBinderService().disable(ccb);
- mTestLooper.dispatchAll();
- mTestLooperOfDataAggregator.dispatchAll();
- // TODO: We can verify the data sources once we implement them.
- verify(mockThread, times(1)).quitSafely();
- assertEquals(STATE_VISIBLE, scb1.mState);
- assertEquals(STATE_VISIBLE, scb2.mState);
- assertNull(ccb.mErrorCode);
- }
-
- @Test
- public void testDataAggregator_AddBatchData() {
- mForensicService.setState(STATE_ENABLED);
- ServiceThread mockThread = spy(ServiceThread.class);
- mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
-
- String eventOneType = "event_one_type";
- String eventOneMapKey = "event_one_map_key";
- String eventOneMapVal = "event_one_map_val";
- Map<String, String> eventOneMap = new ArrayMap<String, String>();
- eventOneMap.put(eventOneMapKey, eventOneMapVal);
- ForensicEvent eventOne = new ForensicEvent(eventOneType, eventOneMap);
-
- String eventTwoType = "event_two_type";
- String eventTwoMapKey = "event_two_map_key";
- String eventTwoMapVal = "event_two_map_val";
- Map<String, String> eventTwoMap = new ArrayMap<String, String>();
- eventTwoMap.put(eventTwoMapKey, eventTwoMapVal);
- ForensicEvent eventTwo = new ForensicEvent(eventTwoType, eventTwoMap);
-
- List<ForensicEvent> events = new ArrayList<>();
- events.add(eventOne);
- events.add(eventTwo);
-
- doReturn(true).when(mBackupTransportConnection).addData(any());
-
- mDataAggregator.addBatchData(events);
- mTestLooperOfDataAggregator.dispatchAll();
- mTestLooper.dispatchAll();
-
- ArgumentCaptor<List<ForensicEvent>> captor = ArgumentCaptor.forClass(List.class);
- verify(mBackupTransportConnection).addData(captor.capture());
- List<ForensicEvent> receivedEvents = captor.getValue();
- assertEquals(receivedEvents.size(), 2);
-
- assertEquals(receivedEvents.getFirst().getType(), eventOneType);
- assertEquals(receivedEvents.getFirst().getKeyValuePairs().size(), 1);
- assertEquals(receivedEvents.getFirst().getKeyValuePairs().get(eventOneMapKey),
- eventOneMapVal);
-
- assertEquals(receivedEvents.getLast().getType(), eventTwoType);
- assertEquals(receivedEvents.getLast().getKeyValuePairs().size(), 1);
- assertEquals(receivedEvents.getLast().getKeyValuePairs().get(eventTwoMapKey),
- eventTwoMapVal);
-
- }
-
- private class MockInjector implements ForensicService.Injector {
- private final Context mContext;
-
- MockInjector(Context context) {
- mContext = context;
- }
-
- @Override
- public Context getContext() {
- return mContext;
- }
-
-
- @Override
- public Looper getLooper() {
- return mLooper;
- }
-
- @Override
- public BackupTransportConnection getBackupTransportConnection() {
- mBackupTransportConnection = spy(new BackupTransportConnection(mContext));
- return mBackupTransportConnection;
- }
-
- @Override
- public DataAggregator getDataAggregator(ForensicService forensicService) {
- mDataAggregator = spy(new DataAggregator(mContext, forensicService));
- return mDataAggregator;
- }
- }
-
- private static class StateCallback extends IForensicServiceStateCallback.Stub {
- int mState = STATE_UNKNOWN;
-
- @Override
- public void onStateChange(int state) throws RemoteException {
- mState = state;
- }
- }
-
- private static class CommandCallback extends IForensicServiceCommandCallback.Stub {
- Integer mErrorCode = null;
-
- public void reset() {
- mErrorCode = null;
- }
-
- @Override
- public void onSuccess() throws RemoteException {
-
- }
-
- @Override
- public void onFailure(int errorCode) throws RemoteException {
- mErrorCode = errorCode;
- }
- }
-}
diff --git a/services/tests/security/forensic/Android.bp b/services/tests/security/intrusiondetection/Android.bp
index 77a87afba6a7..00ac90807dff 100644
--- a/services/tests/security/forensic/Android.bp
+++ b/services/tests/security/intrusiondetection/Android.bp
@@ -9,7 +9,7 @@ package {
}
android_test {
- name: "ForensicServiceTests",
+ name: "IntrusionDetectionServiceTests",
srcs: [
"src/**/*.java",
],
diff --git a/services/tests/security/forensic/AndroidManifest.xml b/services/tests/security/intrusiondetection/AndroidManifest.xml
index c5b3d40ce254..f388e7ea8590 100644
--- a/services/tests/security/forensic/AndroidManifest.xml
+++ b/services/tests/security/intrusiondetection/AndroidManifest.xml
@@ -15,7 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.security.forensic.tests">
+ package="com.android.server.security.intrusiondetection.tests">
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
@@ -25,6 +25,6 @@
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.security.forensic.tests"
- android:label="Frameworks Forensic Services Tests"/>
+ android:targetPackage="com.android.server.security.intrusiondetection.tests"
+ android:label="Frameworks IntrusionDetection Services Tests"/>
</manifest>
diff --git a/services/tests/security/forensic/AndroidTest.xml b/services/tests/security/intrusiondetection/AndroidTest.xml
index bbe2e9c303ce..42cb9e3236e0 100644
--- a/services/tests/security/forensic/AndroidTest.xml
+++ b/services/tests/security/intrusiondetection/AndroidTest.xml
@@ -13,19 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Runs Frameworks Forensic Service tests.">
+<configuration description="Runs Frameworks IntrusionDetection Service tests.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="ForensicServiceTests.apk"/>
+ <option name="test-file-name" value="IntrusionDetectionServiceTests.apk"/>
<option name="install-arg" value="-t" />
</target_preparer>
- <option name="test-tag" value="ForensicServiceTests" />
+ <option name="test-tag" value="IntrusionDetectionServiceTests" />
<test class="com.android.tradefed.testtype.InstrumentationTest" >
- <option name="package" value="com.android.server.security.forensic.tests" />
+ <option name="package" value="com.android.server.security.intrusiondetection.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
diff --git a/services/tests/security/intrusiondetection/OWNERS b/services/tests/security/intrusiondetection/OWNERS
new file mode 100644
index 000000000000..2157972e06e8
--- /dev/null
+++ b/services/tests/security/intrusiondetection/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+file:platform/frameworks/base:main:/core/java/android/security/intrusiondetection/OWNERS
diff --git a/services/tests/security/intrusiondetection/TEST_MAPPING b/services/tests/security/intrusiondetection/TEST_MAPPING
new file mode 100644
index 000000000000..24d63e36e32b
--- /dev/null
+++ b/services/tests/security/intrusiondetection/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "IntrusionDetectionServiceTests"
+ }
+ ]
+}
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
new file mode 100644
index 000000000000..bc854cf6488b
--- /dev/null
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2024 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.security.intrusiondetection;
+
+import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE;
+import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.SuppressLint;
+import android.app.admin.ConnectEvent;
+import android.app.admin.DnsEvent;
+import android.app.admin.SecurityLog.SecurityEvent;
+import android.content.Context;
+import android.os.Looper;
+import android.os.PermissionEnforcer;
+import android.os.RemoteException;
+import android.os.test.FakePermissionEnforcer;
+import android.os.test.TestLooper;
+import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback;
+import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.ServiceThread;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class IntrusionDetectionServiceTest {
+ private static final int STATE_UNKNOWN =
+ IIntrusionDetectionServiceStateCallback.State.UNKNOWN;
+ private static final int STATE_DISABLED =
+ IIntrusionDetectionServiceStateCallback.State.DISABLED;
+ private static final int STATE_ENABLED =
+ IIntrusionDetectionServiceStateCallback.State.ENABLED;
+
+ private static final int ERROR_UNKNOWN =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.UNKNOWN;
+ private static final int ERROR_PERMISSION_DENIED =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
+ private static final int ERROR_TRANSPORT_UNAVAILABLE =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE;
+ private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
+ IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
+
+ private Context mContext;
+ private IntrusionDetectionEventTransportConnection mIntrusionDetectionEventTransportConnection;
+ private DataAggregator mDataAggregator;
+ private IntrusionDetectionService mIntrusionDetectionService;
+ private TestLooper mTestLooper;
+ private Looper mLooper;
+ private TestLooper mTestLooperOfDataAggregator;
+ private Looper mLooperOfDataAggregator;
+ private FakePermissionEnforcer mPermissionEnforcer;
+
+ @SuppressLint("VisibleForTests")
+ @Before
+ public void setUp() {
+ mContext = spy(ApplicationProvider.getApplicationContext());
+
+ mPermissionEnforcer = new FakePermissionEnforcer();
+ mPermissionEnforcer.grant(READ_INTRUSION_DETECTION_STATE);
+ mPermissionEnforcer.grant(MANAGE_INTRUSION_DETECTION_STATE);
+
+ mTestLooper = new TestLooper();
+ mLooper = mTestLooper.getLooper();
+ mTestLooperOfDataAggregator = new TestLooper();
+ mLooperOfDataAggregator = mTestLooperOfDataAggregator.getLooper();
+ mIntrusionDetectionService = new IntrusionDetectionService(new MockInjector(mContext));
+ mIntrusionDetectionService.onStart();
+ }
+
+ @Test
+ public void testAddStateCallback_NoPermission() {
+ mPermissionEnforcer.revoke(READ_INTRUSION_DETECTION_STATE);
+ StateCallback scb = new StateCallback();
+ assertEquals(STATE_UNKNOWN, scb.mState);
+ assertThrows(SecurityException.class,
+ () -> mIntrusionDetectionService.getBinderService().addStateCallback(scb));
+ }
+
+ @Test
+ public void testRemoveStateCallback_NoPermission() {
+ mPermissionEnforcer.revoke(READ_INTRUSION_DETECTION_STATE);
+ StateCallback scb = new StateCallback();
+ assertEquals(STATE_UNKNOWN, scb.mState);
+ assertThrows(SecurityException.class,
+ () -> mIntrusionDetectionService.getBinderService().removeStateCallback(scb));
+ }
+
+ @Test
+ public void testEnable_NoPermission() {
+ mPermissionEnforcer.revoke(MANAGE_INTRUSION_DETECTION_STATE);
+
+ CommandCallback ccb = new CommandCallback();
+ assertThrows(SecurityException.class,
+ () -> mIntrusionDetectionService.getBinderService().enable(ccb));
+ }
+
+ @Test
+ public void testDisable_NoPermission() {
+ mPermissionEnforcer.revoke(MANAGE_INTRUSION_DETECTION_STATE);
+
+ CommandCallback ccb = new CommandCallback();
+ assertThrows(SecurityException.class,
+ () -> mIntrusionDetectionService.getBinderService().disable(ccb));
+ }
+
+ @Test
+ public void testAddStateCallback_Disabled() throws RemoteException {
+ StateCallback scb = new StateCallback();
+ assertEquals(STATE_UNKNOWN, scb.mState);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb.mState);
+ }
+
+ @Test
+ public void testAddStateCallback_Disabled_TwoStateCallbacks() throws RemoteException {
+ StateCallback scb1 = new StateCallback();
+ assertEquals(STATE_UNKNOWN, scb1.mState);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb1);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb1.mState);
+
+ StateCallback scb2 = new StateCallback();
+ assertEquals(STATE_UNKNOWN, scb2.mState);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb2);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb2.mState);
+ }
+
+ @Test
+ public void testRemoveStateCallback() throws RemoteException {
+ mIntrusionDetectionService.setState(STATE_DISABLED);
+ StateCallback scb1 = new StateCallback();
+ StateCallback scb2 = new StateCallback();
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb1);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb2);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+
+ doReturn(true).when(mDataAggregator).initialize();
+ doReturn(true).when(mIntrusionDetectionEventTransportConnection).initialize();
+
+ mIntrusionDetectionService.getBinderService().removeStateCallback(scb2);
+
+ CommandCallback ccb = new CommandCallback();
+ mIntrusionDetectionService.getBinderService().enable(ccb);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_ENABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+ assertNull(ccb.mErrorCode);
+ }
+
+ @Test
+ public void testEnable_FromDisabled_TwoStateCallbacks() throws RemoteException {
+ mIntrusionDetectionService.setState(STATE_DISABLED);
+ StateCallback scb1 = new StateCallback();
+ StateCallback scb2 = new StateCallback();
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb1);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb2);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+
+ doReturn(true).when(mIntrusionDetectionEventTransportConnection).initialize();
+
+ CommandCallback ccb = new CommandCallback();
+ mIntrusionDetectionService.getBinderService().enable(ccb);
+ mTestLooper.dispatchAll();
+
+ verify(mDataAggregator, times(1)).enable();
+ assertEquals(STATE_ENABLED, scb1.mState);
+ assertEquals(STATE_ENABLED, scb2.mState);
+ assertNull(ccb.mErrorCode);
+ }
+
+ @Test
+ public void testEnable_FromEnabled_TwoStateCallbacks()
+ throws RemoteException {
+ mIntrusionDetectionService.setState(STATE_ENABLED);
+ StateCallback scb1 = new StateCallback();
+ StateCallback scb2 = new StateCallback();
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb1);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb2);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_ENABLED, scb1.mState);
+ assertEquals(STATE_ENABLED, scb2.mState);
+
+ CommandCallback ccb = new CommandCallback();
+ mIntrusionDetectionService.getBinderService().enable(ccb);
+ mTestLooper.dispatchAll();
+
+ assertEquals(STATE_ENABLED, scb1.mState);
+ assertEquals(STATE_ENABLED, scb2.mState);
+ assertNull(ccb.mErrorCode);
+ }
+
+ @Test
+ public void testDisable_FromDisabled_TwoStateCallbacks() throws RemoteException {
+ mIntrusionDetectionService.setState(STATE_DISABLED);
+ StateCallback scb1 = new StateCallback();
+ StateCallback scb2 = new StateCallback();
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb1);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb2);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+
+ CommandCallback ccb = new CommandCallback();
+ mIntrusionDetectionService.getBinderService().disable(ccb);
+ mTestLooper.dispatchAll();
+
+ assertEquals(STATE_DISABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+ assertNull(ccb.mErrorCode);
+ }
+
+ @Test
+ public void testDisable_FromEnabled_TwoStateCallbacks() throws RemoteException {
+ mIntrusionDetectionService.setState(STATE_ENABLED);
+ StateCallback scb1 = new StateCallback();
+ StateCallback scb2 = new StateCallback();
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb1);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb2);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_ENABLED, scb1.mState);
+ assertEquals(STATE_ENABLED, scb2.mState);
+
+ doNothing().when(mIntrusionDetectionEventTransportConnection).release();
+
+ ServiceThread mockThread = spy(ServiceThread.class);
+ mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
+
+ CommandCallback ccb = new CommandCallback();
+ mIntrusionDetectionService.getBinderService().disable(ccb);
+ mTestLooper.dispatchAll();
+ mTestLooperOfDataAggregator.dispatchAll();
+ // TODO: We can verify the data sources once we implement them.
+ verify(mockThread, times(1)).quitSafely();
+ assertEquals(STATE_DISABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+ assertNull(ccb.mErrorCode);
+ }
+
+ @Ignore("Enable once the IntrusionDetectionEventTransportConnection is ready")
+ @Test
+ public void testEnable_FromDisable_TwoStateCallbacks_TransportUnavailable()
+ throws RemoteException {
+ mIntrusionDetectionService.setState(STATE_DISABLED);
+ StateCallback scb1 = new StateCallback();
+ StateCallback scb2 = new StateCallback();
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb1);
+ mIntrusionDetectionService.getBinderService().addStateCallback(scb2);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+
+ doReturn(false).when(mIntrusionDetectionEventTransportConnection).initialize();
+
+ CommandCallback ccb = new CommandCallback();
+ mIntrusionDetectionService.getBinderService().enable(ccb);
+ mTestLooper.dispatchAll();
+ assertEquals(STATE_DISABLED, scb1.mState);
+ assertEquals(STATE_DISABLED, scb2.mState);
+ assertNotNull(ccb.mErrorCode);
+ assertEquals(ERROR_TRANSPORT_UNAVAILABLE, ccb.mErrorCode.intValue());
+ }
+
+ @Test
+ public void testDataAggregator_AddBatchData() {
+ mIntrusionDetectionService.setState(STATE_ENABLED);
+ ServiceThread mockThread = spy(ServiceThread.class);
+ mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
+
+ SecurityEvent securityEvent = new SecurityEvent(0, new byte[0]);
+ IntrusionDetectionEvent eventOne = new IntrusionDetectionEvent(securityEvent);
+
+ ConnectEvent connectEvent = new ConnectEvent(
+ "127.0.0.1", 80, null, 0);
+ IntrusionDetectionEvent eventTwo = new IntrusionDetectionEvent(connectEvent);
+
+ DnsEvent dnsEvent = new DnsEvent(
+ null, new String[] {"127.0.0.1"}, 1, null, 0);
+ IntrusionDetectionEvent eventThree = new IntrusionDetectionEvent(dnsEvent);
+
+ List<IntrusionDetectionEvent> events = new ArrayList<>();
+ events.add(eventOne);
+ events.add(eventTwo);
+ events.add(eventThree);
+
+ doReturn(true).when(mIntrusionDetectionEventTransportConnection).addData(any());
+
+ mDataAggregator.addBatchData(events);
+ mTestLooperOfDataAggregator.dispatchAll();
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<List<IntrusionDetectionEvent>> captor = ArgumentCaptor.forClass(List.class);
+ verify(mIntrusionDetectionEventTransportConnection).addData(captor.capture());
+ List<IntrusionDetectionEvent> receivedEvents = captor.getValue();
+ assertEquals(receivedEvents.size(), 3);
+
+ assertEquals(receivedEvents.get(0).getType(), IntrusionDetectionEvent.SECURITY_EVENT);
+ assertNotNull(receivedEvents.get(0).getSecurityEvent());
+
+ assertEquals(receivedEvents.get(1).getType(),
+ IntrusionDetectionEvent.NETWORK_EVENT_CONNECT);
+ assertNotNull(receivedEvents.get(1).getConnectEvent());
+
+ assertEquals(receivedEvents.get(2).getType(), IntrusionDetectionEvent.NETWORK_EVENT_DNS);
+ assertNotNull(receivedEvents.get(2).getDnsEvent());
+ }
+
+ private class MockInjector implements IntrusionDetectionService.Injector {
+ private final Context mContext;
+
+ MockInjector(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ public PermissionEnforcer getPermissionEnforcer() {
+ return mPermissionEnforcer;
+ }
+
+ @Override
+ public Looper getLooper() {
+ return mLooper;
+ }
+
+ @Override
+ public IntrusionDetectionEventTransportConnection
+ getIntrusionDetectionEventransportConnection() {
+ mIntrusionDetectionEventTransportConnection =
+ spy(new IntrusionDetectionEventTransportConnection(mContext));
+ return mIntrusionDetectionEventTransportConnection;
+ }
+
+ @Override
+ public DataAggregator getDataAggregator(
+ IntrusionDetectionService intrusionDetectionService) {
+ mDataAggregator = spy(new DataAggregator(mContext, intrusionDetectionService));
+ return mDataAggregator;
+ }
+ }
+
+ private static class StateCallback extends IIntrusionDetectionServiceStateCallback.Stub {
+ int mState = STATE_UNKNOWN;
+
+ @Override
+ public void onStateChange(int state) throws RemoteException {
+ mState = state;
+ }
+ }
+
+ private static class CommandCallback extends IIntrusionDetectionServiceCommandCallback.Stub {
+ Integer mErrorCode = null;
+
+ public void reset() {
+ mErrorCode = null;
+ }
+
+ @Override
+ public void onSuccess() throws RemoteException {
+
+ }
+
+ @Override
+ public void onFailure(int errorCode) throws RemoteException {
+ mErrorCode = errorCode;
+ }
+ }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index f1656678d3bd..0c058df35195 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -97,7 +97,7 @@ android_test {
"com_android_server_accessibility_flags_lib",
"locksettings_flags_lib",
] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
- "true": ["service-crashrecovery.impl"],
+ "true": ["service-crashrecovery-pre-jarjar"],
default: [],
}),
diff --git a/services/tests/servicestests/jni/Android.bp b/services/tests/servicestests/jni/Android.bp
index 0a3103722796..e738c19cc545 100644
--- a/services/tests/servicestests/jni/Android.bp
+++ b/services/tests/servicestests/jni/Android.bp
@@ -22,9 +22,9 @@ cc_library_shared {
srcs: [
":lib_cachedAppOptimizer_native",
":lib_freezer_native",
- ":lib_gameManagerService_native",
":lib_oomConnection_native",
":lib_anrTimer_native",
+ ":lib_lazilyRegisteredServices_native",
"onload.cpp",
],
@@ -55,6 +55,8 @@ cc_library_shared {
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@4.0",
+ "android.hardware.ir@1.0",
+ "android.hardware.vr@1.0",
"android.hidl.token@1.0-utils",
],
}
diff --git a/services/tests/servicestests/jni/onload.cpp b/services/tests/servicestests/jni/onload.cpp
index 25487c5aabbe..ad979c62f40e 100644
--- a/services/tests/servicestests/jni/onload.cpp
+++ b/services/tests/servicestests/jni/onload.cpp
@@ -25,9 +25,9 @@
namespace android {
int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
int register_android_server_am_OomConnection(JNIEnv* env);
int register_android_server_utils_AnrTimer(JNIEnv *env);
+int register_android_server_utils_LazyJniRegistrar(JNIEnv* env);
};
using namespace android;
@@ -43,8 +43,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
}
ALOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_am_CachedAppOptimizer(env);
- register_android_server_app_GameManagerService(env);
register_android_server_am_OomConnection(env);
register_android_server_utils_AnrTimer(env);
+ register_android_server_utils_LazyJniRegistrar(env);
return JNI_VERSION_1_4;
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index d5b930769e43..492838e9b4fb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -1136,7 +1136,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_HARDWARE_SHORTCUT_DISABLES_WARNING)
public void enableHardwareShortcutsForTargets_shortcutDialogSetting_isShown() {
// TODO(b/111889696): Remove the user 0 assumption once we support multi-user
assumeTrue("The test is setup to run as a user 0",
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 403930d96a12..2ae31ad618d6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -18,20 +18,24 @@ package com.android.server.accessibility;
import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.EventWindowIdMatcher.eventWindowId;
import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges;
-import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.windowId;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.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;
@@ -42,14 +46,13 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.Nullable;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.SparseArray;
import android.view.Display;
import android.view.IWindow;
@@ -63,6 +66,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
@@ -70,7 +74,6 @@ import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -81,17 +84,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-// This test verifies deprecated codepath. Probably changing this file means
-// AccessibilityWindowManagerWithAccessibilityWindowTest also needs to be updated.
-// LINT.IfChange
-
/**
- * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2
- * enabled.
- * TODO(b/322444245): Merge with AccessibilityWindowManagerWithAccessibilityWindowTest
- * after completing the flag migration.
+ * Tests for the AccessibilityWindowManager.
*/
-@RequiresFlagsDisabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2)
public class AccessibilityWindowManagerTest {
private static final String PACKAGE_NAME = "com.android.server.accessibility";
private static final boolean FORCE_SEND = true;
@@ -122,9 +117,8 @@ public class AccessibilityWindowManagerTest {
// List of window token, mapping from windowId -> window token.
private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
- // List of window info lists, mapping from displayId -> window info lists.
- private final SparseArray<ArrayList<WindowInfo>> mWindowInfos =
- new SparseArray<>();
+ // List of window info lists, mapping from displayId -> a11y window lists.
+ private final SparseArray<ArrayList<AccessibilityWindow>> mWindows = new SparseArray<>();
// List of callback, mapping from displayId -> callback.
private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
new SparseArray<>();
@@ -134,6 +128,13 @@ public class AccessibilityWindowManagerTest {
private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
+ // This maps displayId -> next region offset.
+ // Touchable region must have un-occluded area so that it's exposed to a11y services.
+ // This offset can be used as left and top of new region so that top-left of each region are
+ // kept visible.
+ // It's expected to be incremented by some amount everytime the value is used.
+ private final SparseArray<Integer> mNextRegionOffsets = new SparseArray<>();
+
@Mock private WindowManagerInternal mMockWindowManagerInternal;
@Mock private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
@Mock private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
@@ -144,9 +145,6 @@ public class AccessibilityWindowManagerTest {
@Mock private IBinder mMockEmbeddedToken;
@Mock private IBinder mMockInvalidToken;
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
@@ -159,7 +157,7 @@ public class AccessibilityWindowManagerTest {
anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
doAnswer((invocation) -> {
- onWindowsForAccessibilityChanged(invocation.getArgument(0), false);
+ onAccessibilityWindowsChanged(invocation.getArgument(0), false);
return null;
}).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
@@ -173,7 +171,7 @@ public class AccessibilityWindowManagerTest {
// as top focused display before each testing starts.
startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
- // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
+ // AccessibilityEventSender is invoked during onAccessibilityWindowsChanged.
// Resets it for mockito verify of further test case.
Mockito.reset(mMockA11yEventSender);
@@ -237,19 +235,18 @@ public class AccessibilityWindowManagerTest {
@Test
public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- WindowInfo focusedWindowInfo =
- mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+ final WindowInfo focusedWindowInfo =
+ mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, focusedWindowInfo.token));
focusedWindowInfo.focused = false;
- focusedWindowInfo =
- mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
- focusedWindowInfo.focused = true;
+ mWindows.get(Display.DEFAULT_DISPLAY).get(
+ DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().focused = true;
mA11yWindowManager.onTouchInteractionStart();
setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
}
@@ -273,7 +270,7 @@ public class AccessibilityWindowManagerTest {
changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
- onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+ onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
// The active window should not be changed.
assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
// The top focused window should not be changed.
@@ -301,8 +298,8 @@ public class AccessibilityWindowManagerTest {
changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
- onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
// The active window should be changed.
assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
// The top focused window should be changed.
@@ -312,53 +309,181 @@ public class AccessibilityWindowManagerTest {
@Test
public void onWindowsChanged_shouldReportCorrectLayer() {
- // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+ // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
for (int i = 0; i < a11yWindows.size(); i++) {
final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
- final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
- assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1,
+ assertThat(mWindows.get(Display.DEFAULT_DISPLAY).size() - i - 1,
is(a11yWindow.getLayer()));
}
}
@Test
public void onWindowsChanged_shouldReportCorrectOrder() {
- // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+ // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
for (int i = 0; i < a11yWindows.size(); i++) {
final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
final IBinder windowToken = mA11yWindowManager
.getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
- final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+ final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY)
+ .get(i).getWindowInfo();
assertThat(windowToken, is(windowInfo.token));
}
}
@Test
- public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
- final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
- final int correctLayer =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
- windowInfo.layer += 1;
+ public void onWindowsChanged_shouldNotReportNonTouchableWindow() {
+ final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ when(window.isTouchable()).thenReturn(false);
+ final int windowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, window.getWindowInfo().token);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, not(hasItem(windowId(windowId))));
+ }
+
+ @Test
+ public void onWindowsChanged_shouldReportFocusedNonTouchableWindow() {
+ final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
+ DEFAULT_FOCUSED_INDEX);
+ when(window.isTouchable()).thenReturn(false);
+ final int windowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, window.getWindowInfo().token);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasItem(windowId(windowId)));
+ }
+
+ @Test
+ public void onWindowsChanged_trustedFocusedNonTouchableWindow_shouldNotHideWindowsBelow() {
+ // Make the focused trusted un-touchable window fullscreen.
+ final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
+ DEFAULT_FOCUSED_INDEX);
+ setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+ when(window.isTouchable()).thenReturn(false);
+ when(window.isTrustedOverlay()).thenReturn(true);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
+ }
+
+ @Test
+ public void onWindowsChanged_accessibilityOverlay_shouldNotHideWindowsBelow() {
+ // Make the a11y overlay window fullscreen.
+ final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+ when(window.getType()).thenReturn(WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
+ }
+
+ @Test
+ public void onWindowsChanged_shouldReportFocusedWindowEvenIfOccluded() {
+ // Make the front window fullscreen.
+ final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(frontWindow,
+ new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+ final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
+
+ final AccessibilityWindow focusedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(
+ DEFAULT_FOCUSED_INDEX);
+ final int focusedWindowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, focusedWindow.getWindowInfo().token);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasSize(2));
+ assertThat(a11yWindows.get(0), windowId(frontWindowId));
+ assertThat(a11yWindows.get(1), windowId(focusedWindowId));
+ }
+
+ @Test
+ public void onWindowsChanged_embeddedWindows_shouldOnlyReportHost() throws RemoteException {
+ final Rect embeddingBounds = new Rect(0, 0, 200, 100);
+
+ // The embedded window comes front of the host window.
+ final IBinder embeddedWindowLeashToken = Mockito.mock(IBinder.class);
+ final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+ false, embeddedWindowLeashToken, USER_SYSTEM_ID);
+ final AccessibilityWindow embeddedWindow = createMockAccessibilityWindow(
+ mA11yWindowTokens.get(embeddedWindowId), Display.DEFAULT_DISPLAY);
+ setRegionForMockAccessibilityWindow(embeddedWindow, new Region(embeddingBounds));
+ mWindows.get(Display.DEFAULT_DISPLAY).set(0, embeddedWindow);
+
+ final IBinder hostWindowLeashToken = Mockito.mock(IBinder.class);
+ final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+ false, hostWindowLeashToken, USER_SYSTEM_ID);
+ final AccessibilityWindow hostWindow = createMockAccessibilityWindow(
+ mA11yWindowTokens.get(hostWindowId), Display.DEFAULT_DISPLAY);
+ setRegionForMockAccessibilityWindow(hostWindow, new Region(embeddingBounds));
+ mWindows.get(Display.DEFAULT_DISPLAY).set(1, hostWindow);
+
+ mA11yWindowManager.associateEmbeddedHierarchyLocked(
+ hostWindowLeashToken, embeddedWindowLeashToken);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, not(hasItem(windowId(embeddedWindowId))));
+ assertThat(a11yWindows.get(0), windowId(hostWindowId));
+ final Rect bounds = new Rect();
+ a11yWindows.get(0).getBoundsInScreen(bounds);
+ assertEquals(bounds, embeddingBounds);
+ }
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
- assertNotEquals(correctLayer,
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+ @Test
+ public void onWindowsChanged_shouldNotReportfullyOccludedWindow() {
+ final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(frontWindow, new Region(100, 100, 300, 300));
+ final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
+
+ // index 1 is focused. Let's use the next one for this test.
+ final AccessibilityWindow occludedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(2);
+ setRegionForMockAccessibilityWindow(occludedWindow, new Region(150, 150, 250, 250));
+ final int occludedWindowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, occludedWindow.getWindowInfo().token);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasItem(windowId(frontWindowId)));
+ assertThat(a11yWindows, not(hasItem(windowId(occludedWindowId))));
}
@Test
- public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
- final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
- final int correctLayer =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
- windowInfo.layer += 1;
+ public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+ assertNotEquals("new title",
+ toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
+ .get(0).getTitle()));
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
- assertEquals(correctLayer,
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+ mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().title = "new title";
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+ assertEquals("new title",
+ toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
+ .get(0).getTitle()));
}
@Test
@@ -368,14 +493,10 @@ public class AccessibilityWindowManagerTest {
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
true, USER_SYSTEM_ID);
- final WindowInfo windowInfo = WindowInfo.obtain();
- windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
- windowInfo.token = token.asBinder();
- windowInfo.layer = 0;
- windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
+ mWindows.get(Display.DEFAULT_DISPLAY).set(0,
+ createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertNotEquals(oldWindow,
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
}
@@ -383,12 +504,12 @@ public class AccessibilityWindowManagerTest {
@Test
public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
final WindowInfo focusedWindowInfo =
- mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
- final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+ mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
+ final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo();
focusedWindowInfo.focused = false;
windowInfo.focused = true;
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
.isFocused());
}
@@ -497,15 +618,18 @@ public class AccessibilityWindowManagerTest {
@Test
public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
// Updates top 2 z-order WindowInfo are whole visible.
- WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
- windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
- windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1);
- windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2,
- SCREEN_WIDTH, SCREEN_HEIGHT);
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(firstWindow,
+ new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
+ final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+ setRegionForMockAccessibilityWindow(secondWindow,
+ new Region(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasSize(2));
final Region outBounds = new Region();
int windowId = a11yWindows.get(0).getId();
@@ -523,12 +647,17 @@ public class AccessibilityWindowManagerTest {
@Test
public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
// Updates z-order #1 WindowInfo is half visible.
- WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
- windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
-
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(firstWindow,
+ new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
+ final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+ setRegionForMockAccessibilityWindow(secondWindow,
+ new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasSize(2));
final Region outBounds = new Region();
int windowId = a11yWindows.get(1).getId();
@@ -539,9 +668,17 @@ public class AccessibilityWindowManagerTest {
@Test
public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
- // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+ // z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+ final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(firstWindow,
+ new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ // Note that the second window is also exposed even if region is empty because it's focused.
+ assertThat(a11yWindows, hasSize(2));
final Region outBounds = new Region();
int windowId = a11yWindows.get(1).getId();
@@ -552,16 +689,21 @@ public class AccessibilityWindowManagerTest {
@Test
public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
// Updates z-order #0 WindowInfo to have two interact-able areas.
- Region region = new Region(0, 0, SCREEN_WIDTH, 200);
+ final Region region = new Region(0, 0, SCREEN_WIDTH, 200);
region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
- WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
- windowInfo.regionInScreen.set(region);
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(firstWindow, region);
+ final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+ setRegionForMockAccessibilityWindow(secondWindow,
+ new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasSize(2));
final Region outBounds = new Region();
- int windowId = a11yWindows.get(1).getId();
+ final int windowId = a11yWindows.get(1).getId();
mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
assertFalse(outBounds.getBounds().isEmpty());
@@ -572,7 +714,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
final IBinder eventWindowToken =
- mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token;
+ mWindows.get(Display.DEFAULT_DISPLAY)
+ .get(DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().token;
final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, eventWindowToken);
when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
@@ -611,11 +754,11 @@ public class AccessibilityWindowManagerTest {
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(currentActiveWindowId),
+ eventWindowId(currentActiveWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
assertThat(captor.getAllValues().get(1),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(eventWindowId),
+ eventWindowId(eventWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
}
@@ -641,7 +784,7 @@ public class AccessibilityWindowManagerTest {
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(eventWindowId),
+ eventWindowId(eventWindowId),
a11yWindowChanges(
AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
}
@@ -690,12 +833,12 @@ public class AccessibilityWindowManagerTest {
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
allOf(displayId(initialDisplayId),
- a11yWindowId(initialWindowId),
+ eventWindowId(initialWindowId),
a11yWindowChanges(
AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
assertThat(captor.getAllValues().get(1),
allOf(displayId(eventDisplayId),
- a11yWindowId(eventWindowId),
+ eventWindowId(eventWindowId),
a11yWindowChanges(
AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
}
@@ -722,7 +865,7 @@ public class AccessibilityWindowManagerTest {
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
noUse);
assertThat(mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
+ AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
}
@@ -751,11 +894,11 @@ public class AccessibilityWindowManagerTest {
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(eventWindowId),
+ eventWindowId(eventWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
assertThat(captor.getAllValues().get(1),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(currentActiveWindowId),
+ eventWindowId(currentActiveWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
}
@@ -763,7 +906,8 @@ public class AccessibilityWindowManagerTest {
public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
throws RemoteException {
final IBinder defaultFocusWinToken =
- mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
+ mWindows.get(Display.DEFAULT_DISPLAY).get(
+ DEFAULT_FOCUSED_INDEX).getWindowInfo().token;
final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, defaultFocusWinToken);
when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
@@ -808,8 +952,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void getPictureInPictureWindow_shouldNotNull() {
assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
- mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ mWindows.get(Display.DEFAULT_DISPLAY).get(1).getWindowInfo().inPictureInPicture = true;
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
}
@@ -823,8 +967,9 @@ public class AccessibilityWindowManagerTest {
final IAccessibilityInteractionConnection mockRemoteConnection =
mA11yWindowManager.getConnectionLocked(
USER_SYSTEM_ID, outsideWindowId).getRemote();
- mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+ mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().hasFlagWatchOutsideTouch =
+ true;
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
verify(mockRemoteConnection).notifyOutsideTouch();
@@ -942,18 +1087,14 @@ public class AccessibilityWindowManagerTest {
@Test
public void sendAccessibilityEventOnWindowRemoval() {
- final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+ final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
// Removing index 0 because it's not focused, and avoids unnecessary layer change.
final int windowId =
getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
- infos.remove(0);
- for (WindowInfo info : infos) {
- // Adjust layer number because it should start from 0.
- info.layer--;
- }
+ windows.remove(0);
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
final ArgumentCaptor<AccessibilityEvent> captor =
ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -961,27 +1102,21 @@ public class AccessibilityWindowManagerTest {
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(windowId),
+ eventWindowId(windowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
}
@Test
public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
- final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
-
- for (WindowInfo info : infos) {
- // Adjust layer number because new window will have 0 so that layer number in
- // A11yWindowInfo in window won't be changed.
- info.layer++;
- }
+ final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
false, USER_SYSTEM_ID);
- addWindowInfo(infos, token, 0);
- final int windowId =
- getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1);
+ // Adding window to the front so that other windows' layer won't change.
+ windows.add(0, createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
+ final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
final ArgumentCaptor<AccessibilityEvent> captor =
ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -989,17 +1124,17 @@ public class AccessibilityWindowManagerTest {
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(windowId),
+ eventWindowId(windowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
}
@Test
public void sendAccessibilityEventOnWindowChange() {
- final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
- infos.get(0).title = "new title";
+ final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
+ windows.get(0).getWindowInfo().title = "new title";
final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
- onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
final ArgumentCaptor<AccessibilityEvent> captor =
ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -1007,7 +1142,7 @@ public class AccessibilityWindowManagerTest {
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
allOf(displayId(Display.DEFAULT_DISPLAY),
- a11yWindowId(windowId),
+ eventWindowId(windowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
}
@@ -1017,48 +1152,47 @@ public class AccessibilityWindowManagerTest {
}
private void startTrackingPerDisplay(int displayId) throws RemoteException {
- ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
+ ArrayList<AccessibilityWindow> windowsForDisplay = new ArrayList<>();
// Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
// mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
// for the test.
- int layer = 0;
for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
final IWindow token = addAccessibilityInteractionConnection(displayId,
true, USER_SYSTEM_ID);
- addWindowInfo(windowInfosForDisplay, token, layer++);
+ windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
}
for (int i = 0; i < NUM_APP_WINDOWS; i++) {
final IWindow token = addAccessibilityInteractionConnection(displayId,
false, USER_SYSTEM_ID);
- addWindowInfo(windowInfosForDisplay, token, layer++);
+ windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
}
// Sets up current focused window of display.
// Each display has its own current focused window if config_perDisplayFocusEnabled is true.
// Otherwise only default display needs to current focused window.
if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
- windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
+ windowsForDisplay.get(DEFAULT_FOCUSED_INDEX).getWindowInfo().focused = true;
}
// Turns on windows tracking, and update window info.
mA11yWindowManager.startTrackingWindows(displayId, false);
// Puts window lists into array.
- mWindowInfos.put(displayId, windowInfosForDisplay);
+ mWindows.put(displayId, windowsForDisplay);
// Sets the default display is the top focused display and
// its current focused window is the top focused window.
if (displayId == Display.DEFAULT_DISPLAY) {
setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
}
// Invokes callback for sending window lists to A11y framework.
- onWindowsForAccessibilityChanged(displayId, FORCE_SEND);
+ onAccessibilityWindowsChanged(displayId, FORCE_SEND);
assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
- windowInfosForDisplay.size());
+ windowsForDisplay.size());
}
private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
ArgumentCaptor.forClass(
- WindowManagerInternal.WindowsForAccessibilityCallback.class);
+ WindowsForAccessibilityCallback.class);
verify(mMockWindowManagerInternal)
.setWindowsForAccessibilityCallback(eq(displayId),
windowsForAccessibilityCallbacksCaptor.capture());
@@ -1106,36 +1240,28 @@ public class AccessibilityWindowManagerTest {
return windowId;
}
- private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) {
- final WindowInfo windowInfo = WindowInfo.obtain();
- windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
- windowInfo.token = windowToken.asBinder();
- windowInfo.layer = layer;
- windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- windowInfos.add(windowInfo);
- }
-
private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
- final IBinder windowToken = mWindowInfos.get(displayId).get(index).token;
+ final IBinder windowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
return mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, windowToken);
}
private void setTopFocusedWindowAndDisplay(int displayId, int index) {
// Sets the top focus window.
- mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token;
+ mTopFocusedWindowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
// Sets the top focused display.
mTopFocusedDisplayId = displayId;
}
- private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) {
+ private void onAccessibilityWindowsChanged(int displayId, boolean forceSend) {
WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
if (callbacks == null) {
callbacks = getWindowsForAccessibilityCallbacks(displayId);
mCallbackOfWindows.put(displayId, callbacks);
}
- callbacks.onWindowsForAccessibilityChanged(forceSend, mTopFocusedDisplayId,
- mTopFocusedWindowToken, mWindowInfos.get(displayId));
+ callbacks.onAccessibilityWindowsChanged(forceSend, mTopFocusedDisplayId,
+ mTopFocusedWindowToken, new Point(SCREEN_WIDTH, SCREEN_HEIGHT),
+ mWindows.get(displayId));
}
private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
@@ -1144,23 +1270,23 @@ public class AccessibilityWindowManagerTest {
if (mSupportPerDisplayFocus) {
// Gets the old focused window of display which wants to change focused window.
WindowInfo focusedWindowInfo =
- mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex);
+ mWindows.get(changeFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
// Resets the focus of old focused window.
focusedWindowInfo.focused = false;
// Gets the new window of display which wants to change focused window.
focusedWindowInfo =
- mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+ mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
// Sets the focus of new focused window.
focusedWindowInfo.focused = true;
} else {
// Gets the window of display which wants to change focused window.
WindowInfo focusedWindowInfo =
- mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+ mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
// Sets the focus of new focused window.
focusedWindowInfo.focused = true;
// Gets the old focused window of old top focused display.
focusedWindowInfo =
- mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex);
+ mWindows.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
// Resets the focus of old focused window.
focusedWindowInfo.focused = false;
// Changes the top focused display and window.
@@ -1168,6 +1294,39 @@ public class AccessibilityWindowManagerTest {
}
}
+ private AccessibilityWindow createMockAccessibilityWindow(IWindow windowToken, int displayId) {
+ final WindowInfo windowInfo = WindowInfo.obtain();
+ windowInfo.type = WindowManager.LayoutParams.TYPE_APPLICATION;
+ windowInfo.token = windowToken.asBinder();
+
+ final AccessibilityWindow window = Mockito.mock(AccessibilityWindow.class);
+ when(window.getWindowInfo()).thenReturn(windowInfo);
+ when(window.isFocused()).thenAnswer(invocation -> windowInfo.focused);
+ when(window.isTouchable()).thenReturn(true);
+ when(window.getType()).thenReturn(windowInfo.type);
+
+ setRegionForMockAccessibilityWindow(window, nextToucableRegion(displayId));
+ return window;
+ }
+
+ private void setRegionForMockAccessibilityWindow(AccessibilityWindow window, Region region) {
+ doAnswer(invocation -> {
+ ((Region) invocation.getArgument(0)).set(region);
+ return null;
+ }).when(window).getTouchableRegionInScreen(any(Region.class));
+ doAnswer(invocation -> {
+ ((Region) invocation.getArgument(0)).set(region);
+ return null;
+ }).when(window).getTouchableRegionInWindow(any(Region.class));
+ }
+
+ private Region nextToucableRegion(int displayId) {
+ final int topLeft = mNextRegionOffsets.get(displayId, 0);
+ final int bottomRight = topLeft + 100;
+ mNextRegionOffsets.put(displayId, topLeft + 10);
+ return new Region(topLeft, topLeft, bottomRight, bottomRight);
+ }
+
@Nullable
private static String toString(@Nullable CharSequence cs) {
return cs == null ? null : cs.toString();
@@ -1196,16 +1355,16 @@ public class AccessibilityWindowManagerTest {
}
}
- static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+ static class EventWindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
private int mWindowId;
- WindowIdMatcher(int windowId) {
+ EventWindowIdMatcher(int windowId) {
super();
mWindowId = windowId;
}
- static WindowIdMatcher a11yWindowId(int windowId) {
- return new WindowIdMatcher(windowId);
+ static EventWindowIdMatcher eventWindowId(int windowId) {
+ return new EventWindowIdMatcher(windowId);
}
@Override
@@ -1241,5 +1400,27 @@ public class AccessibilityWindowManagerTest {
description.appendText("Matching to window changes " + mWindowChanges);
}
}
+
+ static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityWindowInfo> {
+ private final int mWindowId;
+
+ WindowIdMatcher(int windowId) {
+ super();
+ mWindowId = windowId;
+ }
+
+ static WindowIdMatcher windowId(int windowId) {
+ return new WindowIdMatcher(windowId);
+ }
+
+ @Override
+ protected boolean matchesSafely(AccessibilityWindowInfo window) {
+ return window.getId() == mWindowId;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Matching to windowId " + mWindowId);
+ }
+ }
}
-// LINT.ThenChange(/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
deleted file mode 100644
index 19041451c8eb..000000000000
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
+++ /dev/null
@@ -1,1444 +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.server.accessibility;
-
-import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.DisplayIdMatcher.displayId;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.WindowIdMatcher.windowId;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.WindowChangesMatcher.a11yWindowChanges;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.EventWindowIdMatcher.eventWindowId;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-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.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.Nullable;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.IBinder;
-import android.os.LocaleList;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.IWindow;
-import android.view.WindowInfo;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityWindowAttributes;
-import android.view.accessibility.AccessibilityWindowInfo;
-import android.view.accessibility.IAccessibilityInteractionConnection;
-
-import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
-import com.android.server.accessibility.test.MessageCapturingHandler;
-import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
-import com.android.server.wm.WindowManagerInternal;
-import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
-
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2
- * TODO(b/322444245): Merge with AccessibilityWindowManagerTest
- * after completing the flag migration.
- */
-@RequiresFlagsEnabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2)
-public class AccessibilityWindowManagerWithAccessibilityWindowTest {
- private static final String PACKAGE_NAME = "com.android.server.accessibility";
- private static final boolean FORCE_SEND = true;
- private static final boolean SEND_ON_WINDOW_CHANGES = false;
- private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
- private static final int USER_PROFILE = 11;
- private static final int USER_PROFILE_PARENT = 1;
- private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1;
- private static final int NUM_GLOBAL_WINDOWS = 4;
- private static final int NUM_APP_WINDOWS = 4;
- private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS);
- private static final int DEFAULT_FOCUSED_INDEX = 1;
- private static final int SCREEN_WIDTH = 1080;
- private static final int SCREEN_HEIGHT = 1920;
- private static final int INVALID_ID = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
- private static final int HOST_WINDOW_ID = 10;
- private static final int EMBEDDED_WINDOW_ID = 11;
- private static final int OTHER_WINDOW_ID = 12;
-
- private AccessibilityWindowManager mA11yWindowManager;
- // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true,
- // i.e., each display would have its current focused window, and one of all focused windows
- // would be top focused window. Otherwise, window manager only supports one focused window
- // at all displays, and that focused window would be top focused window.
- private boolean mSupportPerDisplayFocus = false;
- private int mTopFocusedDisplayId = Display.INVALID_DISPLAY;
- private IBinder mTopFocusedWindowToken = null;
-
- // List of window token, mapping from windowId -> window token.
- private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
- // List of window info lists, mapping from displayId -> a11y window lists.
- private final SparseArray<ArrayList<AccessibilityWindow>> mWindows = new SparseArray<>();
- // List of callback, mapping from displayId -> callback.
- private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
- new SparseArray<>();
- // List of display ID.
- private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList(
- Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID));
-
- private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
-
- // This maps displayId -> next region offset.
- // Touchable region must have un-occluded area so that it's exposed to a11y services.
- // This offset can be used as left and top of new region so that top-left of each region are
- // kept visible.
- // It's expected to be incremented by some amount everytime the value is used.
- private final SparseArray<Integer> mNextRegionOffsets = new SparseArray<>();
-
- @Mock
- private WindowManagerInternal mMockWindowManagerInternal;
- @Mock
- private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
- @Mock
- private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
- @Mock
- private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
- @Mock
- private AccessibilityTraceManager mMockA11yTraceManager;
-
- @Mock
- private IBinder mMockHostToken;
- @Mock
- private IBinder mMockEmbeddedToken;
- @Mock
- private IBinder mMockInvalidToken;
-
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
- @Before
- public void setUp() throws RemoteException {
- MockitoAnnotations.initMocks(this);
- when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID);
- when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
- USER_PROFILE)).thenReturn(USER_PROFILE_PARENT);
- when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
- USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
- when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
- anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
-
- doAnswer((invocation) -> {
- onAccessibilityWindowsChanged(invocation.getArgument(0), false);
- return null;
- }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
-
- mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler,
- mMockWindowManagerInternal,
- mMockA11yEventSender,
- mMockA11ySecurityPolicy,
- mMockA11yUserManager,
- mMockA11yTraceManager);
- // Starts tracking window of default display and sets the default display
- // as top focused display before each testing starts.
- startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
-
- // AccessibilityEventSender is invoked during onAccessibilityWindowsChanged.
- // Resets it for mockito verify of further test case.
- Mockito.reset(mMockA11yEventSender);
-
- registerLeashedTokenAndWindowId();
- }
-
- @After
- public void tearDown() {
- mHandler.removeAllMessages();
- }
-
- @Test
- public void startTrackingWindows_shouldEnableWindowManagerCallback() {
- // AccessibilityWindowManager#startTrackingWindows already invoked in setup.
- assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
- final WindowsForAccessibilityCallback callbacks =
- mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
- verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
- eq(Display.DEFAULT_DISPLAY), eq(callbacks));
- }
-
- @Test
- public void stopTrackingWindows_shouldDisableWindowManagerCallback() {
- assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
- Mockito.reset(mMockWindowManagerInternal);
-
- mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
- assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
- verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
- eq(Display.DEFAULT_DISPLAY), isNull());
-
- }
-
- @Test
- public void stopTrackingWindows_shouldClearWindows() {
- assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
- final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-
- mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
- assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY));
- assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
- AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
- assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID),
- activeWindowId);
- }
-
- @Test
- public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow()
- throws RemoteException {
- // At setup, the default display sets be the top focused display and
- // its current focused window sets be the top focused window.
- // Starts tracking window of second display.
- startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
- assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
- // Stops tracking windows of second display.
- mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID);
- assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
- AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
- }
-
- @Test
- public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
- final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- final WindowInfo focusedWindowInfo =
- mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
- assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, focusedWindowInfo.token));
-
- focusedWindowInfo.focused = false;
- mWindows.get(Display.DEFAULT_DISPLAY).get(
- DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().focused = true;
-
- mA11yWindowManager.onTouchInteractionStart();
- setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
- }
-
- @Test
- public void
- onWindowsChanged_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow()
- throws RemoteException {
- // At setup, the default display sets be the top focused display and
- // its current focused window sets be the top focused window.
- // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true.
- mSupportPerDisplayFocus = true;
- // Starts tracking window of second display.
- startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
- // Gets the active window.
- final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- // Gets the top focused window.
- final int topFocusedWindowId =
- mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
- // Changes the current focused window at second display.
- changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
- DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
-
- onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
- // The active window should not be changed.
- assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
- // The top focused window should not be changed.
- assertEquals(topFocusedWindowId,
- mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
- }
-
- @Test
- public void
- onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow()
- throws RemoteException {
- // At setup, the default display sets be the top focused display and
- // its current focused window sets be the top focused window.
- // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is
- // false.
- mSupportPerDisplayFocus = false;
- // Starts tracking window of second display.
- startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
- // Gets the active window.
- final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- // Gets the top focused window.
- final int topFocusedWindowId =
- mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
- // Changes the current focused window from default display to second display.
- changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
- DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
- onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
- // The active window should be changed.
- assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
- // The top focused window should be changed.
- assertNotEquals(topFocusedWindowId,
- mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
- }
-
- @Test
- public void onWindowsChanged_shouldReportCorrectLayer() {
- // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
- List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- for (int i = 0; i < a11yWindows.size(); i++) {
- final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
- assertThat(mWindows.get(Display.DEFAULT_DISPLAY).size() - i - 1,
- is(a11yWindow.getLayer()));
- }
- }
-
- @Test
- public void onWindowsChanged_shouldReportCorrectOrder() {
- // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
- List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- for (int i = 0; i < a11yWindows.size(); i++) {
- final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
- final IBinder windowToken = mA11yWindowManager
- .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
- final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY)
- .get(i).getWindowInfo();
- assertThat(windowToken, is(windowInfo.token));
- }
- }
-
- @Test
- public void onWindowsChanged_shouldNotReportNonTouchableWindow() {
- final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- when(window.isTouchable()).thenReturn(false);
- final int windowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, window.getWindowInfo().token);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, not(hasItem(windowId(windowId))));
- }
-
- @Test
- public void onWindowsChanged_shouldReportFocusedNonTouchableWindow() {
- final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
- DEFAULT_FOCUSED_INDEX);
- when(window.isTouchable()).thenReturn(false);
- final int windowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, window.getWindowInfo().token);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasItem(windowId(windowId)));
- }
-
- @Test
- public void onWindowsChanged_trustedFocusedNonTouchableWindow_shouldNotHideWindowsBelow() {
- // Make the focused trusted un-touchable window fullscreen.
- final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
- DEFAULT_FOCUSED_INDEX);
- setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
- when(window.isTouchable()).thenReturn(false);
- when(window.isTrustedOverlay()).thenReturn(true);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
- }
-
- @Test
- public void onWindowsChanged_accessibilityOverlay_shouldNotHideWindowsBelow() {
- // Make the a11y overlay window fullscreen.
- final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
- when(window.getType()).thenReturn(WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
- }
-
- @Test
- public void onWindowsChanged_shouldReportFocusedWindowEvenIfOccluded() {
- // Make the front window fullscreen.
- final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- setRegionForMockAccessibilityWindow(frontWindow,
- new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
- final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
-
- final AccessibilityWindow focusedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(
- DEFAULT_FOCUSED_INDEX);
- final int focusedWindowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, focusedWindow.getWindowInfo().token);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasSize(2));
- assertThat(a11yWindows.get(0), windowId(frontWindowId));
- assertThat(a11yWindows.get(1), windowId(focusedWindowId));
- }
-
- @Test
- public void onWindowsChanged_embeddedWindows_shouldOnlyReportHost() throws RemoteException {
- final Rect embeddingBounds = new Rect(0, 0, 200, 100);
-
- // The embedded window comes front of the host window.
- final IBinder embeddedWindowLeashToken = Mockito.mock(IBinder.class);
- final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, embeddedWindowLeashToken, USER_SYSTEM_ID);
- final AccessibilityWindow embeddedWindow = createMockAccessibilityWindow(
- mA11yWindowTokens.get(embeddedWindowId), Display.DEFAULT_DISPLAY);
- setRegionForMockAccessibilityWindow(embeddedWindow, new Region(embeddingBounds));
- mWindows.get(Display.DEFAULT_DISPLAY).set(0, embeddedWindow);
-
- final IBinder hostWindowLeashToken = Mockito.mock(IBinder.class);
- final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, hostWindowLeashToken, USER_SYSTEM_ID);
- final AccessibilityWindow hostWindow = createMockAccessibilityWindow(
- mA11yWindowTokens.get(hostWindowId), Display.DEFAULT_DISPLAY);
- setRegionForMockAccessibilityWindow(hostWindow, new Region(embeddingBounds));
- mWindows.get(Display.DEFAULT_DISPLAY).set(1, hostWindow);
-
- mA11yWindowManager.associateEmbeddedHierarchyLocked(
- hostWindowLeashToken, embeddedWindowLeashToken);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, not(hasItem(windowId(embeddedWindowId))));
- assertThat(a11yWindows.get(0), windowId(hostWindowId));
- final Rect bounds = new Rect();
- a11yWindows.get(0).getBoundsInScreen(bounds);
- assertEquals(bounds, embeddingBounds);
- }
-
- @Test
- public void onWindowsChanged_shouldNotReportfullyOccludedWindow() {
- final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- setRegionForMockAccessibilityWindow(frontWindow, new Region(100, 100, 300, 300));
- final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
-
- // index 1 is focused. Let's use the next one for this test.
- final AccessibilityWindow occludedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(2);
- setRegionForMockAccessibilityWindow(occludedWindow, new Region(150, 150, 250, 250));
- final int occludedWindowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, occludedWindow.getWindowInfo().token);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasItem(windowId(frontWindowId)));
- assertThat(a11yWindows, not(hasItem(windowId(occludedWindowId))));
- }
-
- @Test
- public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
- assertNotEquals("new title",
- toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
- .get(0).getTitle()));
-
- mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().title = "new title";
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
- assertEquals("new title",
- toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
- .get(0).getTitle()));
- }
-
- @Test
- public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
- throws RemoteException {
- final AccessibilityWindowInfo oldWindow =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
- final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- true, USER_SYSTEM_ID);
- mWindows.get(Display.DEFAULT_DISPLAY).set(0,
- createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
- assertNotEquals(oldWindow,
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
- }
-
- @Test
- public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
- final WindowInfo focusedWindowInfo =
- mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
- final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo();
- focusedWindowInfo.focused = false;
- windowInfo.focused = true;
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
- assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
- .isFocused());
- }
-
- @Test
- public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
- for (int i = 0; i < NUM_OF_WINDOWS; i++) {
- final int windowId = mA11yWindowTokens.keyAt(i);
- final IWindow windowToken = mA11yWindowTokens.valueAt(i);
- assertNotNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
-
- mA11yWindowManager.removeAccessibilityInteractionConnection(windowToken);
- assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
- }
- }
-
- @Test
- public void remoteAccessibilityConnection_binderDied_shouldRemoveConnection() {
- for (int i = 0; i < NUM_OF_WINDOWS; i++) {
- final int windowId = mA11yWindowTokens.keyAt(i);
- final RemoteAccessibilityConnection remoteA11yConnection =
- mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId);
- assertNotNull(remoteA11yConnection);
-
- remoteA11yConnection.binderDied();
- assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
- }
- }
-
- @Test
- public void getWindowTokenForUserAndWindowId_shouldNotNull() {
- final List<AccessibilityWindowInfo> windows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- for (int i = 0; i < windows.size(); i++) {
- final int windowId = windows.get(i).getId();
-
- assertNotNull(mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
- USER_SYSTEM_ID, windowId));
- }
- }
-
- @Test
- public void findWindowId() {
- final List<AccessibilityWindowInfo> windows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- for (int i = 0; i < windows.size(); i++) {
- final int windowId = windows.get(i).getId();
- final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
- USER_SYSTEM_ID, windowId);
-
- assertEquals(mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, windowToken), windowId);
- }
- }
-
- @Test
- public void resolveParentWindowId_windowIsNotEmbedded_shouldReturnGivenId()
- throws RemoteException {
- final int windowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, false,
- Mockito.mock(IBinder.class), USER_SYSTEM_ID);
- assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
- }
-
- @Test
- public void resolveParentWindowId_windowIsNotRegistered_shouldReturnGivenId() {
- final int windowId = -1;
- assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
- }
-
- @Test
- public void resolveParentWindowId_windowIsAssociated_shouldReturnParentWindowId()
- throws RemoteException {
- final IBinder mockHostToken = Mockito.mock(IBinder.class);
- final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
- final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, mockHostToken, USER_SYSTEM_ID);
- final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, mockEmbeddedToken, USER_SYSTEM_ID);
-
- mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
-
- final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
- embeddedWindowId);
- assertEquals(hostWindowId, resolvedWindowId);
- }
-
- @Test
- public void resolveParentWindowId_windowIsDisassociated_shouldReturnGivenId()
- throws RemoteException {
- final IBinder mockHostToken = Mockito.mock(IBinder.class);
- final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
- final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, mockHostToken, USER_SYSTEM_ID);
- final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, mockEmbeddedToken, USER_SYSTEM_ID);
-
- mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
- mA11yWindowManager.disassociateEmbeddedHierarchyLocked(mockEmbeddedToken);
-
- final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
- embeddedWindowId);
- assertNotEquals(hostWindowId, resolvedWindowId);
- assertEquals(embeddedWindowId, resolvedWindowId);
- }
-
- @Test
- public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
- // Updates top 2 z-order WindowInfo are whole visible.
- final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- setRegionForMockAccessibilityWindow(firstWindow,
- new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
- final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
- setRegionForMockAccessibilityWindow(secondWindow,
- new Region(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT));
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasSize(2));
- final Region outBounds = new Region();
- int windowId = a11yWindows.get(0).getId();
-
- mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
- assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
- assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
-
- windowId = a11yWindows.get(1).getId();
-
- mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
- assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
- assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
- }
-
- @Test
- public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
- // Updates z-order #1 WindowInfo is half visible.
- final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- setRegionForMockAccessibilityWindow(firstWindow,
- new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
- final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
- setRegionForMockAccessibilityWindow(secondWindow,
- new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasSize(2));
- final Region outBounds = new Region();
- int windowId = a11yWindows.get(1).getId();
-
- mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
- assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
- assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
- }
-
- @Test
- public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
- // z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
- final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- setRegionForMockAccessibilityWindow(firstWindow,
- new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- // Note that the second window is also exposed even if region is empty because it's focused.
- assertThat(a11yWindows, hasSize(2));
- final Region outBounds = new Region();
- int windowId = a11yWindows.get(1).getId();
-
- mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
- assertTrue(outBounds.getBounds().isEmpty());
- }
-
- @Test
- public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
- // Updates z-order #0 WindowInfo to have two interact-able areas.
- final Region region = new Region(0, 0, SCREEN_WIDTH, 200);
- region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
- final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
- setRegionForMockAccessibilityWindow(firstWindow, region);
- final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
- setRegionForMockAccessibilityWindow(secondWindow,
- new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- final List<AccessibilityWindowInfo> a11yWindows =
- mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
- assertThat(a11yWindows, hasSize(2));
- final Region outBounds = new Region();
- final int windowId = a11yWindows.get(1).getId();
-
- mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
- assertFalse(outBounds.getBounds().isEmpty());
- assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
- assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400));
- }
-
- @Test
- public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
- final IBinder eventWindowToken =
- mWindows.get(Display.DEFAULT_DISPLAY)
- .get(DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().token;
- final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, eventWindowToken);
- when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
- .thenReturn(eventWindowToken);
-
- final int noUse = 0;
- mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- eventWindowId,
- noUse,
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
- noUse);
- assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
- assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
- is(eventWindowId));
- }
-
- @Test
- public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
- final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
- DEFAULT_FOCUSED_INDEX + 1);
- final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- assertThat(currentActiveWindowId, is(not(eventWindowId)));
-
- final int noUse = 0;
- mA11yWindowManager.onTouchInteractionStart();
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- eventWindowId,
- noUse,
- AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
- noUse);
- assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
- final ArgumentCaptor<AccessibilityEvent> captor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
- verify(mMockA11yEventSender, times(2))
- .sendAccessibilityEventForCurrentUserLocked(captor.capture());
- assertThat(captor.getAllValues().get(0),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(currentActiveWindowId),
- a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
- assertThat(captor.getAllValues().get(1),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(eventWindowId),
- a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
- }
-
- @Test
- public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
- final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
- DEFAULT_FOCUSED_INDEX);
- final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
- assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
-
- final int noUse = 0;
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- eventWindowId,
- AccessibilityNodeInfo.ROOT_NODE_ID,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
- noUse);
- assertThat(mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
- final ArgumentCaptor<AccessibilityEvent> captor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
- verify(mMockA11yEventSender, times(1))
- .sendAccessibilityEventForCurrentUserLocked(captor.capture());
- assertThat(captor.getAllValues().get(0),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(eventWindowId),
- a11yWindowChanges(
- AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
- }
-
- @Test
- public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary()
- throws RemoteException {
- runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
- Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID);
- }
-
- @Test
- public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault()
- throws RemoteException {
- runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
- SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY);
- }
-
- private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
- int initialDisplayId, int eventDisplayId) throws RemoteException {
- startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
- final int initialWindowId = getWindowIdFromWindowInfosForDisplay(
- initialDisplayId, DEFAULT_FOCUSED_INDEX);
- final int noUse = 0;
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- initialWindowId,
- AccessibilityNodeInfo.ROOT_NODE_ID,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
- noUse);
- assertThat(mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId));
- Mockito.reset(mMockA11yEventSender);
-
- final int eventWindowId = getWindowIdFromWindowInfosForDisplay(
- eventDisplayId, DEFAULT_FOCUSED_INDEX);
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- eventWindowId,
- AccessibilityNodeInfo.ROOT_NODE_ID,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
- noUse);
- assertThat(mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
- final ArgumentCaptor<AccessibilityEvent> captor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
- verify(mMockA11yEventSender, times(2))
- .sendAccessibilityEventForCurrentUserLocked(captor.capture());
- assertThat(captor.getAllValues().get(0),
- allOf(displayId(initialDisplayId),
- eventWindowId(initialWindowId),
- a11yWindowChanges(
- AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
- assertThat(captor.getAllValues().get(1),
- allOf(displayId(eventDisplayId),
- eventWindowId(eventWindowId),
- a11yWindowChanges(
- AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
- }
-
- @Test
- public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
- final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
- DEFAULT_FOCUSED_INDEX);
- final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
- assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
-
- final int noUse = 0;
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- eventWindowId,
- AccessibilityNodeInfo.ROOT_NODE_ID,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
- noUse);
- assertThat(mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- eventWindowId,
- AccessibilityNodeInfo.ROOT_NODE_ID,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
- noUse);
- assertThat(mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
- is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
- }
-
- @Test
- public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
- final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
- DEFAULT_FOCUSED_INDEX + 1);
- final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- assertThat(currentActiveWindowId, is(not(eventWindowId)));
-
- final int noUse = 0;
- mA11yWindowManager.onTouchInteractionStart();
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- eventWindowId,
- noUse,
- AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
- noUse);
- assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
- // AccessibilityEventSender is invoked after active window changed. Reset it.
- Mockito.reset(mMockA11yEventSender);
-
- mA11yWindowManager.onTouchInteractionEnd();
- final ArgumentCaptor<AccessibilityEvent> captor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
- verify(mMockA11yEventSender, times(2))
- .sendAccessibilityEventForCurrentUserLocked(captor.capture());
- assertThat(captor.getAllValues().get(0),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(eventWindowId),
- a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
- assertThat(captor.getAllValues().get(1),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(currentActiveWindowId),
- a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
- }
-
- @Test
- public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
- throws RemoteException {
- final IBinder defaultFocusWinToken =
- mWindows.get(Display.DEFAULT_DISPLAY).get(
- DEFAULT_FOCUSED_INDEX).getWindowInfo().token;
- final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, defaultFocusWinToken);
- when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
- .thenReturn(defaultFocusWinToken);
- final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
- DEFAULT_FOCUSED_INDEX + 1);
- final IAccessibilityInteractionConnection mockNewFocusConnection =
- mA11yWindowManager.getConnectionLocked(
- USER_SYSTEM_ID, newFocusWindowId).getRemote();
-
- mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
- final int noUse = 0;
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- defaultFocusWindowId,
- noUse,
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
- noUse);
- assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(defaultFocusWindowId));
- assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
- is(defaultFocusWindowId));
-
- mA11yWindowManager.onTouchInteractionStart();
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- newFocusWindowId,
- noUse,
- AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
- noUse);
- mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
- newFocusWindowId,
- AccessibilityNodeInfo.ROOT_NODE_ID,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
- noUse);
- assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(newFocusWindowId));
- assertThat(mA11yWindowManager.getFocusedWindowId(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(newFocusWindowId));
-
- mA11yWindowManager.onTouchInteractionEnd();
- mHandler.sendLastMessage();
- verify(mockNewFocusConnection).clearAccessibilityFocus();
- }
-
- @Test
- public void getPictureInPictureWindow_shouldNotNull() {
- assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
- mWindows.get(Display.DEFAULT_DISPLAY).get(1).getWindowInfo().inPictureInPicture = true;
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
- }
-
- @Test
- public void notifyOutsideTouch() throws RemoteException {
- final int targetWindowId =
- getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1);
- final int outsideWindowId =
- getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
- final IAccessibilityInteractionConnection mockRemoteConnection =
- mA11yWindowManager.getConnectionLocked(
- USER_SYSTEM_ID, outsideWindowId).getRemote();
- mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().hasFlagWatchOutsideTouch =
- true;
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
- mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
- verify(mockRemoteConnection).notifyOutsideTouch();
- }
-
- @Test
- public void addAccessibilityInteractionConnection_profileUser_findInParentUser()
- throws RemoteException {
- final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, USER_PROFILE);
- final int windowId = mA11yWindowManager.findWindowIdLocked(
- USER_PROFILE_PARENT, token.asBinder());
- assertTrue(windowId >= 0);
- }
-
- @Test
- public void getDisplayList() throws RemoteException {
- // Starts tracking window of second display.
- startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-
- final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
- DISPLAY_TYPE_DEFAULT);
- assertTrue(displayList.equals(mExpectedDisplayList));
- }
-
- @Test
- public void setAccessibilityWindowIdToSurfaceMetadata()
- throws RemoteException {
- final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- true, USER_SYSTEM_ID);
- int windowId = -1;
- for (int i = 0; i < mA11yWindowTokens.size(); i++) {
- if (mA11yWindowTokens.valueAt(i).equals(token)) {
- windowId = mA11yWindowTokens.keyAt(i);
- }
- }
- assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
- verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
- token.asBinder(), windowId);
-
- mA11yWindowManager.removeAccessibilityInteractionConnection(token);
- verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
- token.asBinder(), -1);
- }
-
- @Test
- public void getHostTokenLocked_hierarchiesAreAssociated_shouldReturnHostToken() {
- mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
- final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
- assertEquals(hostToken, mMockHostToken);
- }
-
- @Test
- public void getHostTokenLocked_hierarchiesAreNotAssociated_shouldReturnNull() {
- final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
- assertNull(hostToken);
- }
-
- @Test
- public void getHostTokenLocked_embeddedHierarchiesAreDisassociated_shouldReturnNull() {
- mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
- mA11yWindowManager.disassociateLocked(mMockEmbeddedToken);
- final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
- assertNull(hostToken);
- }
-
- @Test
- public void getHostTokenLocked_hostHierarchiesAreDisassociated_shouldReturnNull() {
- mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
- mA11yWindowManager.disassociateLocked(mMockHostToken);
- final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockHostToken);
- assertNull(hostToken);
- }
-
- @Test
- public void getWindowIdLocked_windowIsRegistered_shouldReturnWindowId() {
- final int windowId = mA11yWindowManager.getWindowIdLocked(mMockHostToken);
- assertEquals(windowId, HOST_WINDOW_ID);
- }
-
- @Test
- public void getWindowIdLocked_windowIsNotRegistered_shouldReturnInvalidWindowId() {
- final int windowId = mA11yWindowManager.getWindowIdLocked(mMockInvalidToken);
- assertEquals(windowId, INVALID_ID);
- }
-
- @Test
- public void getTokenLocked_windowIsRegistered_shouldReturnToken() {
- final IBinder token = mA11yWindowManager.getLeashTokenLocked(HOST_WINDOW_ID);
- assertEquals(token, mMockHostToken);
- }
-
- @Test
- public void getTokenLocked_windowIsNotRegistered_shouldReturnNull() {
- final IBinder token = mA11yWindowManager.getLeashTokenLocked(OTHER_WINDOW_ID);
- assertNull(token);
- }
-
- @Test
- public void setAccessibilityWindowAttributes_windowIsNotRegistered_titleIsChanged() {
- final int windowId =
- getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
- final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
- layoutParams.accessibilityTitle = "accessibility window title";
- final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
- layoutParams, new LocaleList());
-
- mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId,
- USER_SYSTEM_ID, attributes);
-
- final AccessibilityWindowInfo a11yWindow = mA11yWindowManager.findA11yWindowInfoByIdLocked(
- windowId);
- assertEquals(toString(layoutParams.accessibilityTitle), toString(a11yWindow.getTitle()));
- }
-
- @Test
- public void sendAccessibilityEventOnWindowRemoval() {
- final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-
- // Removing index 0 because it's not focused, and avoids unnecessary layer change.
- final int windowId =
- getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
- windows.remove(0);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
- final ArgumentCaptor<AccessibilityEvent> captor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
- verify(mMockA11yEventSender, times(1))
- .sendAccessibilityEventForCurrentUserLocked(captor.capture());
- assertThat(captor.getAllValues().get(0),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(windowId),
- a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
- }
-
- @Test
- public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
- final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-
- final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
- false, USER_SYSTEM_ID);
- // Adding window to the front so that other windows' layer won't change.
- windows.add(0, createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
- final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
- final ArgumentCaptor<AccessibilityEvent> captor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
- verify(mMockA11yEventSender, times(1))
- .sendAccessibilityEventForCurrentUserLocked(captor.capture());
- assertThat(captor.getAllValues().get(0),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(windowId),
- a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
- }
-
- @Test
- public void sendAccessibilityEventOnWindowChange() {
- final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
- windows.get(0).getWindowInfo().title = "new title";
- final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-
- onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
- final ArgumentCaptor<AccessibilityEvent> captor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
- verify(mMockA11yEventSender, times(1))
- .sendAccessibilityEventForCurrentUserLocked(captor.capture());
- assertThat(captor.getAllValues().get(0),
- allOf(displayId(Display.DEFAULT_DISPLAY),
- eventWindowId(windowId),
- a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
- }
-
- private void registerLeashedTokenAndWindowId() {
- mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
- mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
- }
-
- private void startTrackingPerDisplay(int displayId) throws RemoteException {
- ArrayList<AccessibilityWindow> windowsForDisplay = new ArrayList<>();
- // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
- // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
- // for the test.
- for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
- final IWindow token = addAccessibilityInteractionConnection(displayId,
- true, USER_SYSTEM_ID);
- windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
-
- }
- for (int i = 0; i < NUM_APP_WINDOWS; i++) {
- final IWindow token = addAccessibilityInteractionConnection(displayId,
- false, USER_SYSTEM_ID);
- windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
- }
- // Sets up current focused window of display.
- // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
- // Otherwise only default display needs to current focused window.
- if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
- windowsForDisplay.get(DEFAULT_FOCUSED_INDEX).getWindowInfo().focused = true;
- }
- // Turns on windows tracking, and update window info.
- mA11yWindowManager.startTrackingWindows(displayId, false);
- // Puts window lists into array.
- mWindows.put(displayId, windowsForDisplay);
- // Sets the default display is the top focused display and
- // its current focused window is the top focused window.
- if (displayId == Display.DEFAULT_DISPLAY) {
- setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
- }
- // Invokes callback for sending window lists to A11y framework.
- onAccessibilityWindowsChanged(displayId, FORCE_SEND);
-
- assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
- windowsForDisplay.size());
- }
-
- private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
- ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
- ArgumentCaptor.forClass(
- WindowsForAccessibilityCallback.class);
- verify(mMockWindowManagerInternal)
- .setWindowsForAccessibilityCallback(eq(displayId),
- windowsForAccessibilityCallbacksCaptor.capture());
- return windowsForAccessibilityCallbacksCaptor.getValue();
- }
-
- private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
- int userId) throws RemoteException {
- final IWindow mockWindowToken = Mockito.mock(IWindow.class);
- final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
- IAccessibilityInteractionConnection.class);
- final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
- final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
- final IBinder mockLeashToken = Mockito.mock(IBinder.class);
- when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
- when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
- when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
- .thenReturn(bGlobal);
- when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
- .thenReturn(displayId);
-
- int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
- mockWindowToken, mockLeashToken, mockA11yConnection, PACKAGE_NAME, userId);
- mA11yWindowTokens.put(windowId, mockWindowToken);
- return mockWindowToken;
- }
-
- private int addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
- IBinder leashToken, int userId) throws RemoteException {
- final IWindow mockWindowToken = Mockito.mock(IWindow.class);
- final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
- IAccessibilityInteractionConnection.class);
- final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
- final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
- when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
- when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
- when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
- .thenReturn(bGlobal);
- when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
- .thenReturn(displayId);
-
- int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
- mockWindowToken, leashToken, mockA11yConnection, PACKAGE_NAME, userId);
- mA11yWindowTokens.put(windowId, mockWindowToken);
- return windowId;
- }
-
- private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
- final IBinder windowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
- return mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, windowToken);
- }
-
- private void setTopFocusedWindowAndDisplay(int displayId, int index) {
- // Sets the top focus window.
- mTopFocusedWindowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
- // Sets the top focused display.
- mTopFocusedDisplayId = displayId;
- }
-
- private void onAccessibilityWindowsChanged(int displayId, boolean forceSend) {
- WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
- if (callbacks == null) {
- callbacks = getWindowsForAccessibilityCallbacks(displayId);
- mCallbackOfWindows.put(displayId, callbacks);
- }
- callbacks.onAccessibilityWindowsChanged(forceSend, mTopFocusedDisplayId,
- mTopFocusedWindowToken, new Point(SCREEN_WIDTH, SCREEN_HEIGHT),
- mWindows.get(displayId));
- }
-
- private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
- int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId,
- int oldFocusedWindowIndex) {
- if (mSupportPerDisplayFocus) {
- // Gets the old focused window of display which wants to change focused window.
- WindowInfo focusedWindowInfo =
- mWindows.get(changeFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
- // Resets the focus of old focused window.
- focusedWindowInfo.focused = false;
- // Gets the new window of display which wants to change focused window.
- focusedWindowInfo =
- mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
- // Sets the focus of new focused window.
- focusedWindowInfo.focused = true;
- } else {
- // Gets the window of display which wants to change focused window.
- WindowInfo focusedWindowInfo =
- mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
- // Sets the focus of new focused window.
- focusedWindowInfo.focused = true;
- // Gets the old focused window of old top focused display.
- focusedWindowInfo =
- mWindows.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
- // Resets the focus of old focused window.
- focusedWindowInfo.focused = false;
- // Changes the top focused display and window.
- setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex);
- }
- }
-
- private AccessibilityWindow createMockAccessibilityWindow(IWindow windowToken, int displayId) {
- final WindowInfo windowInfo = WindowInfo.obtain();
- windowInfo.type = WindowManager.LayoutParams.TYPE_APPLICATION;
- windowInfo.token = windowToken.asBinder();
-
- final AccessibilityWindow window = Mockito.mock(AccessibilityWindow.class);
- when(window.getWindowInfo()).thenReturn(windowInfo);
- when(window.isFocused()).thenAnswer(invocation -> windowInfo.focused);
- when(window.isTouchable()).thenReturn(true);
- when(window.getType()).thenReturn(windowInfo.type);
-
- setRegionForMockAccessibilityWindow(window, nextToucableRegion(displayId));
- return window;
- }
-
- private void setRegionForMockAccessibilityWindow(AccessibilityWindow window, Region region) {
- doAnswer(invocation -> {
- ((Region) invocation.getArgument(0)).set(region);
- return null;
- }).when(window).getTouchableRegionInScreen(any(Region.class));
- doAnswer(invocation -> {
- ((Region) invocation.getArgument(0)).set(region);
- return null;
- }).when(window).getTouchableRegionInWindow(any(Region.class));
- }
-
- private Region nextToucableRegion(int displayId) {
- final int topLeft = mNextRegionOffsets.get(displayId, 0);
- final int bottomRight = topLeft + 100;
- mNextRegionOffsets.put(displayId, topLeft + 10);
- return new Region(topLeft, topLeft, bottomRight, bottomRight);
- }
-
- @Nullable
- private static String toString(@Nullable CharSequence cs) {
- return cs == null ? null : cs.toString();
- }
-
- static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
- private final int mDisplayId;
-
- DisplayIdMatcher(int displayId) {
- super();
- mDisplayId = displayId;
- }
-
- static DisplayIdMatcher displayId(int displayId) {
- return new DisplayIdMatcher(displayId);
- }
-
- @Override
- protected boolean matchesSafely(AccessibilityEvent event) {
- return event.getDisplayId() == mDisplayId;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("Matching to displayId " + mDisplayId);
- }
- }
-
- static class EventWindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
- private int mWindowId;
-
- EventWindowIdMatcher(int windowId) {
- super();
- mWindowId = windowId;
- }
-
- static EventWindowIdMatcher eventWindowId(int windowId) {
- return new EventWindowIdMatcher(windowId);
- }
-
- @Override
- protected boolean matchesSafely(AccessibilityEvent event) {
- return event.getWindowId() == mWindowId;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("Matching to windowId " + mWindowId);
- }
- }
-
- static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
- private int mWindowChanges;
-
- WindowChangesMatcher(int windowChanges) {
- super();
- mWindowChanges = windowChanges;
- }
-
- static WindowChangesMatcher a11yWindowChanges(int windowChanges) {
- return new WindowChangesMatcher(windowChanges);
- }
-
- @Override
- protected boolean matchesSafely(AccessibilityEvent event) {
- return event.getWindowChanges() == mWindowChanges;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("Matching to window changes " + mWindowChanges);
- }
- }
-
- static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityWindowInfo> {
- private final int mWindowId;
-
- WindowIdMatcher(int windowId) {
- super();
- mWindowId = windowId;
- }
-
- static WindowIdMatcher windowId(int windowId) {
- return new WindowIdMatcher(windowId);
- }
-
- @Override
- protected boolean matchesSafely(AccessibilityWindowInfo window) {
- return window.getId() == mWindowId;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("Matching to windowId " + mWindowId);
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
index 0988eeab5913..a55346caeeb1 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
@@ -430,7 +430,7 @@ public class FlashNotificationsControllerTest {
AudioPlaybackConfiguration config = new AudioPlaybackConfiguration(
mock(PlayerBase.PlayerIdCard.class), 0, 0, 0);
config.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_STARTED,
- AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+ AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID);
AudioAttributes.Builder builder = new AudioAttributes.Builder();
builder.setUsage(AudioAttributes.USAGE_ALARM);
diff --git a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
index 84c0ab38ca48..0d44021bae09 100644
--- a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
@@ -314,12 +314,13 @@ public class LoudnessCodecHelperTest {
AudioDeviceInfo[] devicesStatic = AudioManager.getDevicesStatic(GET_DEVICES_OUTPUTS);
assumeTrue(devIdx < devicesStatic.length);
Log.d(TAG, "Out devices number " + devicesStatic.length + ". Picking index " + devIdx);
- int deviceId = devicesStatic[devIdx].getId();
+ int[] deviceIds = new int[1];
+ deviceIds[0] = devicesStatic[devIdx].getId();
PlayerBase.PlayerIdCard idCard = Mockito.mock(PlayerBase.PlayerIdCard.class);
AudioPlaybackConfiguration apc =
new AudioPlaybackConfiguration(idCard, piid, /*uid=*/1, /*pid=*/myPid());
- apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceId);
+ apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceIds);
apc.handleSessionIdEvent(sessionId);
apc.handleAudioAttributesEvent(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
index b81bf3c6e712..f6f831f41f83 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
@@ -21,6 +21,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS;
+import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
import static com.android.server.biometrics.sensors.LockoutTracker.LOCKOUT_NONE;
@@ -354,6 +355,21 @@ public class PreAuthInfoTest {
assertThat(preAuthInfo.getIsMandatoryBiometricsAuthentication()).isTrue();
}
+ @Test
+ public void prioritizeStrengthErrorBeforeCameraUnavailableError() throws Exception {
+ final BiometricSensor sensor = getFaceSensorWithStrength(
+ BiometricManager.Authenticators.BIOMETRIC_WEAK);
+ final PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ promptInfo.setNegativeButtonText(TEST_PACKAGE_NAME);
+ final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(sensor), USER_ID , promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
+ mUserManager);
+
+ assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE);
+ }
+
private BiometricSensor getFingerprintSensor() {
BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT,
TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG,
@@ -372,9 +388,10 @@ public class PreAuthInfoTest {
return sensor;
}
- private BiometricSensor getFaceSensor() {
+ private BiometricSensor getFaceSensorWithStrength(
+ @BiometricManager.Authenticators.Types int sensorStrength) {
BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE,
- BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) {
+ sensorStrength, mFaceAuthenticator) {
@Override
boolean confirmationAlwaysRequired(int userId) {
return false;
@@ -388,4 +405,8 @@ public class PreAuthInfoTest {
return sensor;
}
+
+ private BiometricSensor getFaceSensor() {
+ return getFaceSensorWithStrength(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 51c2ad1d1134..687a1ab4c7aa 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -200,7 +200,9 @@ public class VirtualAudioControllerTest {
AudioPlaybackConfiguration audioPlaybackConfiguration =
new AudioPlaybackConfiguration(
playerIdCard, /* piid= */ 1000, appUid, /* pid= */ 1000);
- audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, /* deviceId= */1);
+ int[] deviceIds = new int[1];
+ deviceIds[0] = 1;
+ audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, deviceIds);
configs.add(audioPlaybackConfiguration);
}
return configs;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 698bda335f83..4c381eb4429e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -24,6 +24,7 @@ import android.app.PendingIntent;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerLiteInternal;
import android.app.backup.IBackupManager;
+import android.app.supervision.SupervisionManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.Intent;
@@ -488,6 +489,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
public Context createContextAsUser(UserHandle user) {
return context;
}
+
+ @Override
+ SupervisionManagerInternal getSupervisionManager() {
+ return services.supervisionManagerInternal;
+ }
}
static class TransferOwnershipMetadataManagerMockInjector extends
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 cb4269a205e4..a7bf3e194dd9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -109,6 +109,7 @@ import android.app.admin.PasswordMetrics;
import android.app.admin.PreferentialNetworkServiceConfig;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.WifiSsidPolicy;
+import android.app.admin.flags.Flags;
import android.app.role.RoleManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -134,6 +135,10 @@ import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.security.KeyChain;
@@ -165,6 +170,7 @@ import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.util.collections.Sets;
@@ -207,6 +213,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public static final String INVALID_CALLING_IDENTITY_MSG = "Calling identity is not authorized";
public static final String ONGOING_CALL_MSG = "ongoing call on the device";
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
// TODO replace all instances of this with explicit {@link #mServiceContext}.
@Deprecated
private DpmMockContext mContext;
@@ -4395,6 +4404,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeEnabledModifiesSetting() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4406,6 +4416,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setupProfileOwnerOnUser0();
@@ -4425,6 +4436,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -4902,6 +4914,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
public void testSecondaryLockscreen_profileOwner() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -4930,6 +4943,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
public void testSecondaryLockscreen_deviceOwner() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
@@ -4948,6 +4962,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
public void testSecondaryLockscreen_nonOwner() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -4964,6 +4979,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
public void testSecondaryLockscreen_nonSupervisionApp() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -4996,6 +5012,51 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
+ public void testIsSecondaryLockscreenEnabled() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ verifyIsSecondaryLockscreenEnabled(false);
+ verifyIsSecondaryLockscreenEnabled(true);
+ }
+
+ private void verifyIsSecondaryLockscreenEnabled(boolean expected) throws Exception {
+ reset(getServices().supervisionManagerInternal);
+
+ doReturn(expected).when(getServices().supervisionManagerInternal)
+ .isSupervisionLockscreenEnabledForUser(anyInt());
+
+ final boolean enabled = dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE));
+ verify(getServices().supervisionManagerInternal)
+ .isSupervisionLockscreenEnabledForUser(CALLER_USER_HANDLE);
+
+ assertThat(enabled).isEqualTo(expected);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
+ public void testSetSecondaryLockscreenEnabled() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ verifySetSecondaryLockscreenEnabled(false);
+ verifySetSecondaryLockscreenEnabled(true);
+ }
+
+ private void verifySetSecondaryLockscreenEnabled(boolean enabled) throws Exception {
+ reset(getServices().supervisionManagerInternal);
+
+ dpm.setSecondaryLockscreenEnabled(admin1, enabled);
+ verify(getServices().supervisionManagerInternal).setSupervisionLockscreenEnabledForUser(
+ CALLER_USER_HANDLE, enabled, null);
+
+ reset(getServices().supervisionManagerInternal);
+
+ dpm.setSecondaryLockscreenEnabled(enabled, new PersistableBundle());
+ verify(getServices().supervisionManagerInternal).setSupervisionLockscreenEnabledForUser(
+ eq(CALLER_USER_HANDLE), eq(enabled), any(PersistableBundle.class));
+ }
+
+ @Test
public void testIsDeviceManaged() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 2e200a9268f5..3e4448c1dafa 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -35,6 +35,7 @@ import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.backup.IBackupManager;
import android.app.role.RoleManager;
+import android.app.supervision.SupervisionManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -77,8 +78,8 @@ import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockSettingsInternal;
import com.android.server.AlarmManagerInternal;
-import com.android.server.pdb.PersistentDataBlockManagerInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.pdb.PersistentDataBlockManagerInternal;
import com.android.server.pm.PackageManagerLocal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.pkg.PackageState;
@@ -149,6 +150,7 @@ public class MockSystemServices {
public final BuildMock buildMock = new BuildMock();
public final File dataDir;
public final PolicyPathProvider pathProvider;
+ public final SupervisionManagerInternal supervisionManagerInternal;
private final Map<String, PackageState> mTestPackageStates = new ArrayMap<>();
@@ -203,6 +205,7 @@ public class MockSystemServices {
roleManager = realContext.getSystemService(RoleManager.class);
roleManagerForMock = mock(RoleManagerForMock.class);
subscriptionManager = mock(SubscriptionManager.class);
+ supervisionManagerInternal = mock(SupervisionManagerInternal.class);
// Package manager is huge, so we use a partial mock instead.
packageManager = spy(realContext.getPackageManager());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 51276a4db883..0816e7b61165 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -28,7 +28,7 @@ import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE;
import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
-import static com.android.server.hdmi.RequestActiveSourceAction.TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS;
+import static com.android.server.hdmi.RequestActiveSourceAction.TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS;
import static com.android.server.hdmi.RoutingControlAction.TIMEOUT_ROUTING_INFORMATION_MS;
import static com.android.server.hdmi.RequestSadAction.RETRY_COUNTER_MAX;
@@ -1877,7 +1877,7 @@ public class HdmiCecLocalDeviceTvTest {
mTestLooper.dispatchAll();
// Skip the LauncherX API timeout.
- mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS);
+ mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1910,7 +1910,7 @@ public class HdmiCecLocalDeviceTvTest {
mTestLooper.dispatchAll();
// Skip the LauncherX API timeout.
- mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS);
+ mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1946,7 +1946,7 @@ public class HdmiCecLocalDeviceTvTest {
mTestLooper.dispatchAll();
// Skip the LauncherX API timeout.
- mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS);
+ mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1989,7 +1989,7 @@ public class HdmiCecLocalDeviceTvTest {
mTestLooper.dispatchAll();
// Skip the LauncherX API timeout.
- mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS);
+ mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -2026,7 +2026,7 @@ public class HdmiCecLocalDeviceTvTest {
mHdmiControlService.sendCecCommand(setStreamPathFromTv);
// Skip the LauncherX API timeout.
- mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS);
+ mTestLooper.moveTimeForward(TIMEOUT_WAIT_FOR_TV_ASSERT_ACTIVE_SOURCE_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestActiveSource);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 93aa10b9112f..fd221185bacf 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -68,7 +68,6 @@ import androidx.test.InstrumentationRegistry;
import com.android.internal.R;
import com.android.server.compat.PlatformCompat;
-import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.testutils.TestUtils;
import org.junit.After;
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java
deleted file mode 100644
index d31ed689a7da..000000000000
--- a/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.model;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.Rule;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-@RunWith(JUnit4.class)
-public class IntegrityCheckResultTest {
-
- @Test
- public void createAllowResult() {
- IntegrityCheckResult allowResult = IntegrityCheckResult.allow();
-
- assertThat(allowResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.ALLOW);
- assertThat(allowResult.getMatchedRules()).isEmpty();
- }
-
- @Test
- public void createAllowResultWithRule() {
- String packageName = "com.test.deny";
- Rule forceAllowRule =
- new Rule(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- packageName),
- Rule.FORCE_ALLOW);
-
- IntegrityCheckResult allowResult =
- IntegrityCheckResult.allow(Collections.singletonList(forceAllowRule));
-
- assertThat(allowResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.ALLOW);
- assertThat(allowResult.getMatchedRules()).containsExactly(forceAllowRule);
- }
-
- @Test
- public void createDenyResultWithRule() {
- String packageName = "com.test.deny";
- Rule failedRule =
- new Rule(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- packageName),
- Rule.DENY);
-
- IntegrityCheckResult denyResult =
- IntegrityCheckResult.deny(Collections.singletonList(failedRule));
-
- assertThat(denyResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.DENY);
- assertThat(denyResult.getMatchedRules()).containsExactly(failedRule);
- }
-
- @Test
- public void isDenyCausedByAppCertificate() {
- String packageName = "com.test.deny";
- String appCert = "app-cert";
- Rule failedRule =
- new Rule(
- new CompoundFormula(
- CompoundFormula.AND,
- Arrays.asList(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.PACKAGE_NAME, packageName),
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE, appCert))),
- Rule.DENY);
- Rule otherFailedRule =
- new Rule(
- new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE,
- AtomicFormula.EQ, 12),
- Rule.DENY);
-
- IntegrityCheckResult denyResult =
- IntegrityCheckResult.deny(Arrays.asList(failedRule, otherFailedRule));
-
- assertThat(denyResult.isCausedByAppCertRule()).isTrue();
- assertThat(denyResult.isCausedByInstallerRule()).isFalse();
- }
-
- @Test
- public void isDenyCausedByInstaller() {
- String packageName = "com.test.deny";
- String appCert = "app-cert";
- Rule failedRule =
- new Rule(
- new CompoundFormula(
- CompoundFormula.AND,
- Arrays.asList(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.PACKAGE_NAME, packageName),
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.INSTALLER_CERTIFICATE, appCert))),
- Rule.DENY);
- Rule otherFailedRule =
- new Rule(
- new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE,
- AtomicFormula.EQ, 12),
- Rule.DENY);
-
- IntegrityCheckResult denyResult =
- IntegrityCheckResult.deny(Arrays.asList(failedRule, otherFailedRule));
-
- assertThat(denyResult.isCausedByAppCertRule()).isFalse();
- assertThat(denyResult.isCausedByInstallerRule()).isTrue();
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 73aec6375a03..3ced56a04138 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -67,10 +67,12 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Rect;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
@@ -532,6 +534,8 @@ public class MediaProjectionManagerServiceTest {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
projection.start(mIMediaProjectionCallback);
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, projection.packageName);
doReturn(true).when(mKeyguardManager).isKeyguardLocked();
MediaProjectionManagerService.BinderService mediaProjectionBinderService =
mService.new BinderService(mContext);
@@ -540,50 +544,6 @@ public class MediaProjectionManagerServiceTest {
verify(mContext, never()).startActivityAsUser(any(), any());
}
- @EnableFlags(android.companion.virtualdevice.flags
- .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
- @Test
- public void testKeyguardLocked_stopsActiveProjection() throws Exception {
- MediaProjectionManagerService service =
- new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
- MediaProjectionManagerService.MediaProjection projection =
- startProjectionPreconditions(service);
- projection.start(mIMediaProjectionCallback);
- projection.notifyVirtualDisplayCreated(10);
-
- assertThat(service.getActiveProjectionInfo()).isNotNull();
-
- doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager)
- .checkPermission(RECORD_SENSITIVE_CONTENT, projection.packageName);
- service.onKeyguardLockedStateChanged(true);
-
- verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN);
- assertThat(service.getActiveProjectionInfo()).isNull();
- assertThat(mIMediaProjectionCallback.mLatch.await(5, TimeUnit.SECONDS)).isTrue();
- }
-
- @EnableFlags(android.companion.virtualdevice.flags
- .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
- @Test
- public void testKeyguardLocked_packageAllowlisted_doesNotStopActiveProjection()
- throws NameNotFoundException {
- MediaProjectionManagerService service =
- new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
- MediaProjectionManagerService.MediaProjection projection =
- startProjectionPreconditions(service);
- projection.start(mIMediaProjectionCallback);
- projection.notifyVirtualDisplayCreated(10);
-
- assertThat(service.getActiveProjectionInfo()).isNotNull();
-
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
- RECORD_SENSITIVE_CONTENT, projection.packageName);
- service.onKeyguardLockedStateChanged(true);
-
- verifyZeroInteractions(mMediaProjectionMetricsLogger);
- assertThat(service.getActiveProjectionInfo()).isNotNull();
- }
-
@Test
public void stop_noActiveProjections_doesNotLog() throws Exception {
MediaProjectionManagerService service =
@@ -591,7 +551,7 @@ public class MediaProjectionManagerServiceTest {
MediaProjectionManagerService.MediaProjection projection =
startProjectionPreconditions(service);
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
verifyZeroInteractions(mMediaProjectionMetricsLogger);
}
@@ -604,10 +564,10 @@ public class MediaProjectionManagerServiceTest {
startProjectionPreconditions(service);
projection.start(mIMediaProjectionCallback);
- projection.stop();
+ final @StopReason int stopReason = StopReason.STOP_UNKNOWN;
+ projection.stop(stopReason);
- verify(mMediaProjectionMetricsLogger)
- .logStopped(UID, TARGET_UID_UNKNOWN);
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN, stopReason);
}
@Test
@@ -622,15 +582,16 @@ public class MediaProjectionManagerServiceTest {
.setContentRecordingSession(any(ContentRecordingSession.class));
service.setContentRecordingSession(DISPLAY_SESSION);
- projection.stop();
+ final @StopReason int stopReason = StopReason.STOP_UNKNOWN;
+ projection.stop(stopReason);
- verify(mMediaProjectionMetricsLogger)
- .logStopped(UID, TARGET_UID_FULL_SCREEN);
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_FULL_SCREEN, stopReason);
}
@Test
public void stop_taskSession_logsHostUidAndTargetUid() throws Exception {
int targetUid = 1234;
+ int stopReason = StopReason.STOP_UNKNOWN;
MediaProjectionManagerService service =
new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
MediaProjectionManagerService.MediaProjection projection =
@@ -643,9 +604,9 @@ public class MediaProjectionManagerServiceTest {
taskSession.setTargetUid(targetUid);
service.setContentRecordingSession(taskSession);
- projection.stop();
+ projection.stop(stopReason);
- verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid);
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid, stopReason);
}
@Test
@@ -680,7 +641,7 @@ public class MediaProjectionManagerServiceTest {
projection.start(mIMediaProjectionCallback);
assertThat(projection.isValid()).isTrue();
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
@@ -706,7 +667,7 @@ public class MediaProjectionManagerServiceTest {
mClockInjector);
MediaProjectionManagerService.MediaProjection projection = createProjectionPreconditions(
service);
- mClock.fastForward(projection.mDefaultTimeoutMs + 10);
+ mClock.fastForward(projection.mDefaultTimeoutMillis + 10);
// Immediate timeout - so no longer valid.
assertThat(projection.isValid()).isFalse();
@@ -734,7 +695,7 @@ public class MediaProjectionManagerServiceTest {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
service);
projection.start(mIMediaProjectionCallback);
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
@@ -750,7 +711,7 @@ public class MediaProjectionManagerServiceTest {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
service);
projection.start(mIMediaProjectionCallback);
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
@@ -989,6 +950,26 @@ public class MediaProjectionManagerServiceTest {
projection.uid, targetUid, WINDOWING_MODE_MULTI_WINDOW);
}
+ @Test
+ public void notifyCaptureBoundsChanged_forwardsToLoggerAndResizeCallbacks() throws Exception {
+ int targetUid = 123;
+ mService =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+
+ ContentRecordingSession taskSession = createTaskSession(mock(IBinder.class));
+ taskSession.setTargetUid(targetUid);
+ mService.setContentRecordingSession(taskSession);
+
+ MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+ projection.start(mIMediaProjectionCallback);
+
+ Rect newBounds = new Rect(0, 0, 1000, 2000);
+ mService.notifyCaptureBoundsChanged(RECORD_CONTENT_TASK, targetUid, newBounds);
+
+ verify(mMediaProjectionMetricsLogger)
+ .logChangedCaptureBounds(RECORD_CONTENT_TASK, projection.uid, targetUid, newBounds);
+ }
+
/**
* Executes and validates scenario where the consent result indicates the projection ends.
*/
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
index 72ce9fe9a23f..c727bb6bbf7d 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
@@ -32,6 +32,17 @@ import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN;
@@ -46,6 +57,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.media.projection.StopReason;
import android.platform.test.annotations.Presubmit;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -81,6 +93,7 @@ public class MediaProjectionMetricsLoggerTest {
private static final int TEST_WINDOWING_MODE = 987;
private static final int TEST_CONTENT_TO_RECORD = 654;
+ private static final int TEST_STOP_SOURCE = 321;
@Mock private FrameworkStatsLogWrapper mFrameworkStatsLogWrapper;
@Mock private MediaProjectionSessionIdGenerator mSessionIdGenerator;
@@ -136,6 +149,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logInitiated_logsUnknownStopSource() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logInitiated_noPreviousSession_logsUnknownTimeSinceLastActive() {
when(mTimestampStore.timeSinceLastActiveSession()).thenReturn(null);
@@ -177,7 +198,7 @@ public class MediaProjectionMetricsLoggerTest {
@Test
public void logStopped_logsStateChangedAtomId() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStateChangedAtomIdLogged();
}
@@ -187,42 +208,49 @@ public class MediaProjectionMetricsLoggerTest {
int currentSessionId = 987;
when(mSessionIdGenerator.getCurrentSessionId()).thenReturn(currentSessionId);
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifySessionIdLogged(currentSessionId);
}
@Test
public void logStopped_logsStateStopped() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
}
@Test
public void logStopped_logsHostUid() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStateChangedHostUidLogged(TEST_HOST_UID);
}
@Test
public void logStopped_logsTargetUid() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStageChangedTargetUidLogged(TEST_TARGET_UID);
}
@Test
+ public void logStopped_logsStopSource() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, StopReason.STOP_UNKNOWN);
+
+ verifyStopSourceLogged(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logStopped_logsUnknownTimeSinceLastActive() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyTimeSinceLastActiveSessionLogged(-1);
}
@Test
public void logStopped_logsUnknownSessionCreationSource() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyCreationSourceLogged(
MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
@@ -230,7 +258,7 @@ public class MediaProjectionMetricsLoggerTest {
@Test
public void logStopped_logsPreviousState() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN);
@@ -238,7 +266,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
}
@@ -247,14 +275,14 @@ public class MediaProjectionMetricsLoggerTest {
public void logStopped_capturingWasInProgress_registersActiveSessionEnded() {
mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID);
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verify(mTimestampStore).registerActiveSessionEnded();
}
@Test
public void logStopped_capturingWasNotInProgress_doesNotRegistersActiveSessionEnded() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verify(mTimestampStore, never()).registerActiveSessionEnded();
}
@@ -314,6 +342,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logInProgress_logsUnknownSessionStopSource() {
+ mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logInProgress_logsPreviousState() {
mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
verifyPreviousStateLogged(
@@ -323,7 +359,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS);
@@ -387,6 +423,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logPermissionRequestDisplayed_logsUnknownSessionStopSource() {
+ mLogger.logPermissionRequestDisplayed(TEST_HOST_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logPermissionRequestDisplayed_logsPreviousState() {
mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
verifyPreviousStateLogged(
@@ -396,7 +440,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED);
@@ -460,6 +504,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logAppSelectorDisplayed_logsUnknownSessionStopSource() {
+ mLogger.logAppSelectorDisplayed(TEST_HOST_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logAppSelectorDisplayed_logsPreviousState() {
mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
verifyPreviousStateLogged(
@@ -469,7 +521,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED);
@@ -536,6 +588,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logProjectionPermissionRequestCancelled_logsUnknownStopSource() {
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logWindowingModeChanged_logsTargetChangedAtomId() {
mLogger.logChangedWindowingMode(
TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE);
@@ -614,6 +674,42 @@ public class MediaProjectionMetricsLoggerTest {
.isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN);
}
+ @Test
+ public void testStopReasonToSessionStopSource() {
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_HOST_APP))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_TARGET_REMOVED))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_DEVICE_LOCKED))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_PRIVACY_CHIP))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_QS_TILE))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_USER_SWITCH))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_FOREGROUND_SERVICE_CHANGE))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_PROJECTION))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_MEDIA_ROUTE))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_ERROR))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_UNKNOWN))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
private void verifyStateChangedAtomIdLogged() {
verify(mFrameworkStatsLogWrapper)
.writeStateChanged(
@@ -624,7 +720,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyStateLogged(int state) {
@@ -637,7 +734,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyStateChangedHostUidLogged(int hostUid) {
@@ -650,7 +748,8 @@ public class MediaProjectionMetricsLoggerTest {
eq(hostUid),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyCreationSourceLogged(int creationSource) {
@@ -663,7 +762,22 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- eq(creationSource));
+ eq(creationSource),
+ /* stopSource= */ anyInt());
+ }
+
+ private void verifyStopSourceLogged(int stopSource) {
+ verify(mFrameworkStatsLogWrapper)
+ .writeStateChanged(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* stopSource= */ anyInt(),
+ eq(stopSource));
}
private void verifyStageChangedTargetUidLogged(int targetUid) {
@@ -676,7 +790,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
eq(targetUid),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyTimeSinceLastActiveSessionLogged(int timeSinceLastActiveSession) {
@@ -689,7 +804,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ eq(timeSinceLastActiveSession),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifySessionIdLogged(int newSessionId) {
@@ -702,7 +818,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyPreviousStateLogged(int previousState) {
@@ -715,7 +832,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyTargetChangedAtomIdLogged() {
@@ -726,7 +844,12 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyTargetTypeLogged(int targetType) {
@@ -737,7 +860,12 @@ public class MediaProjectionMetricsLoggerTest {
eq(targetType),
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyTargetChangedHostUidLogged(int hostUid) {
@@ -748,7 +876,12 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
eq(hostUid),
/* targetUid= */ anyInt(),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyTargetChangedTargetUidLogged(int targetUid) {
@@ -759,7 +892,12 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
/* hostUid= */ anyInt(),
eq(targetUid),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyWindowingModeLogged(int targetWindowingMode) {
@@ -770,6 +908,11 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
- eq(targetWindowingMode));
+ eq(targetWindowingMode),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java
new file mode 100644
index 000000000000..affcfc14034e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2024 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.media.projection;
+
+
+import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
+import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+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.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.app.Instrumentation;
+import android.app.KeyguardManager;
+import android.app.role.RoleManager;
+import android.companion.AssociationRequest;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.media.projection.MediaProjectionManager;
+import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+import android.testing.TestableContext;
+import android.util.ArraySet;
+
+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.SystemConfig;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Tests for the {@link MediaProjectionStopController} class.
+ * <p>
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:MediaProjectionStopControllerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+@SuppressLint({"UseCheckPermission", "VisibleForTests", "MissingPermission"})
+public class MediaProjectionStopControllerTest {
+ private static final int UID = 10;
+ private static final String PACKAGE_NAME = "test.package";
+ private final ApplicationInfo mAppInfo = new ApplicationInfo();
+ @Rule
+ public final TestableContext mContext = spy(
+ new TestableContext(InstrumentationRegistry.getInstrumentation().getContext()));
+
+ private final MediaProjectionManagerService.Injector mMediaProjectionMetricsLoggerInjector =
+ new MediaProjectionManagerService.Injector() {
+ @Override
+ MediaProjectionMetricsLogger mediaProjectionMetricsLogger(Context context) {
+ return mMediaProjectionMetricsLogger;
+ }
+ };
+
+ private MediaProjectionManagerService mService;
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Mock
+ private ActivityManagerInternal mAmInternal;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private KeyguardManager mKeyguardManager;
+ @Mock
+ private TelecomManager mTelecomManager;
+
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
+ @Mock
+ private Consumer<Integer> mStopConsumer;
+
+ private MediaProjectionStopController mStopController;
+
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, mAmInternal);
+
+ mAppOpsManager = mockAppOpsManager();
+ mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager);
+ mContext.addMockSystemService(KeyguardManager.class, mKeyguardManager);
+ mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
+ mContext.setMockPackageManager(mPackageManager);
+
+ mStopController = new MediaProjectionStopController(mContext, mStopConsumer);
+ mService = new MediaProjectionManagerService(mContext,
+ mMediaProjectionMetricsLoggerInjector);
+
+ mAppInfo.targetSdkVersion = 35;
+ }
+
+ private static AppOpsManager mockAppOpsManager() {
+ return mock(AppOpsManager.class, invocationOnMock -> {
+ if (invocationOnMock.getMethod().getName().startsWith("noteOp")) {
+ // Mockito will return 0 for non-stubbed method which corresponds to MODE_ALLOWED
+ // and is not what we want.
+ return AppOpsManager.MODE_IGNORED;
+ }
+ return Answers.RETURNS_DEFAULTS.answer(invocationOnMock);
+ });
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ }
+
+ @Test
+ @EnableFlags(
+ android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ public void testMediaProjectionNotRestricted() throws Exception {
+ when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
+
+ assertThat(mStopController.isStartForbidden(
+ createMediaProjection(PACKAGE_NAME))).isFalse();
+ }
+
+ @Test
+ @EnableFlags(
+ android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ public void testMediaProjectionRestricted() throws Exception {
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+ mediaProjection.notifyVirtualDisplayCreated(1);
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+
+ assertThat(mStopController.isStartForbidden(mediaProjection)).isTrue();
+ }
+
+ @Test
+ public void testExemptFromStoppingNullProjection() throws Exception {
+ assertThat(mStopController.isExemptFromStopping(null,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ }
+
+ @Test
+ public void testExemptFromStoppingInvalidProjection() throws Exception {
+ assertThat(mStopController.isExemptFromStopping(createMediaProjection(null),
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ }
+
+ @Test
+ public void testExemptFromStoppingDisableScreenshareProtections() throws Exception {
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ int value = Settings.Global.getInt(mContext.getContentResolver(),
+ DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0);
+ try {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1);
+
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ } finally {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, value);
+ }
+ }
+
+ @Test
+ public void testExemptFromStoppingHasOpProjectMedia() throws Exception {
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager)
+ .noteOpNoThrow(eq(AppOpsManager.OP_PROJECT_MEDIA),
+ eq(mediaProjection.uid), eq(mediaProjection.packageName),
+ nullable(String.class),
+ nullable(String.class));
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ }
+
+ @Test
+ public void testExemptFromStoppingHasAppStreamingRole() throws Exception {
+ runWithRole(
+ AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
+ () -> {
+ try {
+ MediaProjectionManagerService.MediaProjection mediaProjection =
+ createMediaProjection();
+ doReturn(PackageManager.PERMISSION_DENIED).when(
+ mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ @Test
+ public void testExemptFromStoppingIsBugreportAllowlisted() throws Exception {
+ ArraySet<String> packages = SystemConfig.getInstance().getBugreportWhitelistedPackages();
+ if (packages.isEmpty()) {
+ return;
+ }
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(
+ packages.valueAt(0));
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ }
+
+ @Test
+ public void testExemptFromStoppingHasNoDisplay() throws Exception {
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(
+ PACKAGE_NAME);
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ }
+
+ @Test
+ public void testExemptFromStoppingHasRecordSensitiveContentPermission() throws Exception {
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+ }
+
+ @Test
+ public void testExemptFromStoppingIsFalse() throws Exception {
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+ mediaProjection.notifyVirtualDisplayCreated(1);
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_UNKNOWN)).isFalse();
+ }
+
+ @Test
+ @EnableFlags(
+ android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ public void testKeyguardLockedStateChanged_unlocked() {
+ mStopController.onKeyguardLockedStateChanged(false);
+
+ verify(mStopConsumer, never()).accept(anyInt());
+ }
+
+ @Test
+ @EnableFlags(
+ android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ public void testKeyguardLockedStateChanged_locked() {
+ mStopController.onKeyguardLockedStateChanged(true);
+
+ verify(mStopConsumer).accept(MediaProjectionStopController.STOP_REASON_KEYGUARD);
+ }
+
+ @Test
+ @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+ public void testCallStateChanged_callStarts() {
+ // Setup call state to false
+ when(mTelecomManager.isInCall()).thenReturn(false);
+ mStopController.callStateChanged();
+
+ clearInvocations(mStopConsumer);
+
+ when(mTelecomManager.isInCall()).thenReturn(true);
+ mStopController.callStateChanged();
+
+ verify(mStopConsumer, never()).accept(anyInt());
+ }
+
+ @Test
+ @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+ public void testCallStateChanged_remainsInCall() {
+ // Setup call state to false
+ when(mTelecomManager.isInCall()).thenReturn(true);
+ mStopController.callStateChanged();
+
+ clearInvocations(mStopConsumer);
+
+ when(mTelecomManager.isInCall()).thenReturn(true);
+ mStopController.callStateChanged();
+
+ verify(mStopConsumer, never()).accept(anyInt());
+ }
+
+ @Test
+ @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+ public void testCallStateChanged_remainsNoCall() {
+ // Setup call state to false
+ when(mTelecomManager.isInCall()).thenReturn(false);
+ mStopController.callStateChanged();
+
+ clearInvocations(mStopConsumer);
+
+ when(mTelecomManager.isInCall()).thenReturn(false);
+ mStopController.callStateChanged();
+
+ verify(mStopConsumer, never()).accept(anyInt());
+ }
+
+ @Test
+ @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+ public void testCallStateChanged_callEnds() {
+ // Setup call state to false
+ when(mTelecomManager.isInCall()).thenReturn(true);
+ mStopController.callStateChanged();
+
+ clearInvocations(mStopConsumer);
+
+ when(mTelecomManager.isInCall()).thenReturn(false);
+ mStopController.callStateChanged();
+
+ verify(mStopConsumer).accept(MediaProjectionStopController.STOP_REASON_CALL_END);
+ }
+
+ @Test
+ @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+ public void testExemptFromStopping_callEnd_callBeforeMediaProjection() throws Exception {
+ when(mTelecomManager.isInCall()).thenReturn(true);
+ mStopController.callStateChanged();
+
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+ mediaProjection.notifyVirtualDisplayCreated(1);
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_CALL_END)).isFalse();
+ }
+
+ @Test
+ @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+ public void testExemptFromStopping_callEnd_callAfterMediaProjection() throws Exception {
+ MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+ mediaProjection.notifyVirtualDisplayCreated(1);
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+
+ when(mTelecomManager.isInCall()).thenReturn(true);
+ mStopController.callStateChanged();
+
+ assertThat(mStopController.isExemptFromStopping(mediaProjection,
+ MediaProjectionStopController.STOP_REASON_CALL_END)).isTrue();
+ }
+
+ private MediaProjectionManagerService.MediaProjection createMediaProjection()
+ throws NameNotFoundException {
+ return createMediaProjection(PACKAGE_NAME);
+ }
+
+ private MediaProjectionManagerService.MediaProjection createMediaProjection(String packageName)
+ throws NameNotFoundException {
+ doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(anyString(),
+ any(ApplicationInfoFlags.class), any(UserHandle.class));
+ doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(Mockito.isNull(),
+ any(ApplicationInfoFlags.class), any(UserHandle.class));
+ return mService.createProjectionInternal(UID, packageName,
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false, mContext.getUser(),
+ INVALID_DISPLAY);
+ }
+
+ /**
+ * Run the provided block giving the current context's package the provided role.
+ */
+ @SuppressWarnings("SameParameterValue")
+ private void runWithRole(String role, Runnable block) {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ String packageName = mContext.getPackageName();
+ UserHandle user = instrumentation.getTargetContext().getUser();
+ RoleManager roleManager = Objects.requireNonNull(
+ mContext.getSystemService(RoleManager.class));
+ try {
+ CountDownLatch latch = new CountDownLatch(1);
+ instrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.MANAGE_ROLE_HOLDERS,
+ Manifest.permission.BYPASS_ROLE_QUALIFICATION);
+
+ roleManager.setBypassingRoleQualification(true);
+ roleManager.addRoleHolderAsUser(role, packageName,
+ /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
+ mContext.getMainExecutor(), success -> {
+ if (success) {
+ latch.countDown();
+ } else {
+ Assert.fail("Couldn't set role for test (failure) " + role);
+ }
+ });
+ assertWithMessage("Couldn't set role for test (timeout) : " + role)
+ .that(latch.await(1, TimeUnit.SECONDS)).isTrue();
+ block.run();
+
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ roleManager.removeRoleHolderAsUser(role, packageName,
+ /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
+ mContext.getMainExecutor(), (aBool) -> {
+ });
+ roleManager.setBypassingRoleQualification(false);
+ instrumentation.getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 3e748ffb37e9..2c1e37beda26 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -52,6 +52,7 @@ import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
@@ -273,6 +274,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
public String getPackageName() {
return SYSTEM_PACKAGE_NAME;
}
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
}
/** ShortcutService with injection override methods. */
@@ -665,6 +671,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected ServiceContext mServiceContext;
protected ClientContext mClientContext;
+ protected ContentResolver mContentResolver;
protected ShortcutServiceTestable mService;
protected ShortcutManagerTestable mManager;
@@ -861,6 +868,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
mServiceContext = spy(new ServiceContext());
mClientContext = new ClientContext();
+ mContentResolver = mock(ContentResolver.class);
mMockPackageManager = mock(PackageManager.class);
mMockPackageManagerInternal = mock(PackageManagerInternal.class);
@@ -982,6 +990,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
return userProperties;
});
+ when(mMockUserManagerInternal.getUserInfos()).thenReturn(
+ mUserInfos.values().toArray(new UserInfo[0]));
// User 0 and P0 are always running
mRunningUsers.put(USER_0, true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java
new file mode 100644
index 000000000000..d69e47684f8b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2011 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.ActivityManager;
+import android.app.LocaleManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.multiuser.Flags;
+import android.os.LocaleList;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.util.ArraySet;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Test {@link UserManager Cache} functionality.
+ *
+ * atest com.android.server.pm.UserManagerCacheTest
+ */
+@Postsubmit
+@RunWith(AndroidJUnit4.class)
+public final class UserManagerCacheTest {
+
+ private static final LocaleList TEST_LOCALE_LIST = LocaleList.forLanguageTags("pl-PL");
+ private static final long SLEEP_TIMEOUT = 5_000;
+ private static final int REMOVE_USER_TIMEOUT_SECONDS = 180; // 180 seconds
+ private static final String TAG = UserManagerCacheTest.class.getSimpleName();
+
+ private final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ private UserManager mUserManager = null;
+ private PackageManager mPackageManager;
+ private LocaleManager mLocaleManager;
+ private ArraySet<Integer> mUsersToRemove;
+ private UserRemovalWaiter mUserRemovalWaiter;
+ private int mOriginalCurrentUserId;
+ private LocaleList mSystemLocales;
+
+ @Before
+ public void setUp() throws Exception {
+ mOriginalCurrentUserId = ActivityManager.getCurrentUser();
+ mUserManager = UserManager.get(mContext);
+ mPackageManager = mContext.getPackageManager();
+ mLocaleManager = mContext.getSystemService(LocaleManager.class);
+ mSystemLocales = mLocaleManager.getSystemLocales();
+ mUserRemovalWaiter = new UserRemovalWaiter(mContext, TAG, REMOVE_USER_TIMEOUT_SECONDS);
+ mUsersToRemove = new ArraySet<>();
+ removeExistingUsers();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Making a copy of mUsersToRemove to avoid ConcurrentModificationException
+ mUsersToRemove.stream().toList().forEach(this::removeUser);
+ mUserRemovalWaiter.close();
+ mUserManager.setUserRestriction(UserManager.DISALLOW_GRANT_ADMIN, false,
+ mContext.getUser());
+ mLocaleManager.setSystemLocales(mSystemLocales);
+ }
+
+ private void removeExistingUsers() {
+ int currentUser = ActivityManager.getCurrentUser();
+
+ UserHandle communalProfile = mUserManager.getCommunalProfile();
+ int communalProfileId = communalProfile != null
+ ? communalProfile.getIdentifier() : UserHandle.USER_NULL;
+
+ List<UserInfo> list = mUserManager.getUsers();
+ for (UserInfo user : list) {
+ // Keep system and current user
+ if (user.id != UserHandle.USER_SYSTEM
+ && user.id != currentUser
+ && user.id != communalProfileId
+ && !user.isMain()) {
+ removeUser(user.id);
+ }
+ }
+ }
+
+ @MediumTest
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+ public void testUserInfoAfterLocaleChange() throws Exception {
+ UserInfo userInfo = mUserManager.createGuest(mContext);
+ mUsersToRemove.add(userInfo.id);
+ assertThat(userInfo).isNotNull();
+
+ UserInfo guestUserInfo = mUserManager.getUserInfo(userInfo.id);
+ assertThat(guestUserInfo).isNotNull();
+ assertThat(guestUserInfo.name).isNotEqualTo("Gość");
+
+ UserInfo ownerUserInfo = mUserManager.getUserInfo(mOriginalCurrentUserId);
+ assertThat(ownerUserInfo).isNotNull();
+ assertThat(ownerUserInfo.name).isNotEqualTo("Właściciel");
+
+ mLocaleManager.setSystemLocales(TEST_LOCALE_LIST);
+ SystemClock.sleep(SLEEP_TIMEOUT);
+ UserInfo guestUserInfoPl = mUserManager.getUserInfo(userInfo.id);
+ UserInfo ownerUserInfoPl = mUserManager.getUserInfo(mOriginalCurrentUserId);
+
+ assertThat(guestUserInfoPl).isNotNull();
+ assertThat(guestUserInfoPl.name).isEqualTo("Gość");
+
+ assertThat(ownerUserInfoPl).isNotNull();
+ assertThat(ownerUserInfoPl.name).isEqualTo("Właściciel");
+ }
+
+
+ @MediumTest
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+ public void testGetUserInfo10kSpam() throws Exception {
+ UserInfo cachedUserInfo = mUserManager.getUserInfo(mOriginalCurrentUserId);
+ for (int i = 0; i < 10000; i++) {
+ // Control how often cache is calling the API
+ UserInfo ownerUserInfo = mUserManager.getUserInfo(mOriginalCurrentUserId);
+ assertThat(ownerUserInfo).isNotNull();
+ // If indeed it was chached then objects should stay the same. We use == to compare
+ // object addresses to make sure UserInfo is not new copy of the same UserInfo.
+ assertThat(cachedUserInfo.toFullString()).isEqualTo(ownerUserInfo.toFullString());
+ }
+ }
+
+
+ @MediumTest
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+ public void testSetUserAdmin() throws Exception {
+ UserInfo userInfo = mUserManager.createUser("SecondaryUser",
+ UserManager.USER_TYPE_FULL_SECONDARY, /*flags=*/ 0);
+ mUsersToRemove.add(userInfo.id);
+ // cache user
+ UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+
+ assertThat(userInfo.isAdmin()).isFalse();
+ assertThat(cachedUserInfo.isAdmin()).isFalse();
+
+ // invalidate cache
+ mUserManager.setUserAdmin(userInfo.id);
+
+ // updated UserInfo should be returned
+ cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+ assertThat(cachedUserInfo.isAdmin()).isTrue();
+ }
+
+
+ @MediumTest
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+ public void testRevokeUserAdmin() throws Exception {
+ UserInfo userInfo = mUserManager.createUser("Admin",
+ UserManager.USER_TYPE_FULL_SECONDARY, /*flags=*/ UserInfo.FLAG_ADMIN);
+ mUsersToRemove.add(userInfo.id);
+ // cache user
+ UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+ assertThat(userInfo.isAdmin()).isTrue();
+ assertThat(cachedUserInfo.isAdmin()).isTrue();
+
+ // invalidate cache
+ mUserManager.revokeUserAdmin(userInfo.id);
+
+ // updated UserInfo should be returned
+ cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+ assertThat(cachedUserInfo.isAdmin()).isFalse();
+ }
+
+ @MediumTest
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+ public void testRevokeUserAdminFromNonAdmin() throws Exception {
+ UserInfo userInfo = mUserManager.createUser("NonAdmin",
+ UserManager.USER_TYPE_FULL_SECONDARY, /*flags=*/ 0);
+ mUsersToRemove.add(userInfo.id);
+ // cache user
+ UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+ assertThat(userInfo.isAdmin()).isFalse();
+ assertThat(cachedUserInfo.isAdmin()).isFalse();
+
+ // invalidate cache
+ mUserManager.revokeUserAdmin(userInfo.id);
+
+ // updated UserInfo should be returned
+ cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+ assertThat(cachedUserInfo.isAdmin()).isFalse();
+ }
+
+
+ @MediumTest
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+ public void testSetUserName_withContextUserId() throws Exception {
+ assumeManagedUsersSupported();
+ final String newName = "Managed_user 1";
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
+
+ // cache main user
+ UserInfo mainUserInfo = mUserManager.getUserInfo(mainUserId);
+
+ assertThat(mainUserInfo).isNotNull();
+
+ // invalidate cache
+ UserInfo userInfo = mUserManager.createProfileForUser("Managed 1",
+ UserManager.USER_TYPE_PROFILE_MANAGED, 0, mainUserId, null);
+ mUsersToRemove.add(userInfo.id);
+ // cache user
+ UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+ // updated cache for main user
+ mainUserInfo = mUserManager.getUserInfo(mainUserId);
+
+ assertThat(userInfo).isNotNull();
+ assertThat(cachedUserInfo).isNotNull();
+ assertThat(mainUserInfo).isNotNull();
+ // profileGroupId are the same after adding profile to user.
+ assertThat(mainUserInfo.profileGroupId).isEqualTo(cachedUserInfo.profileGroupId);
+
+ UserManager um = (UserManager) mContext.createPackageContextAsUser(
+ "android", 0, userInfo.getUserHandle())
+ .getSystemService(Context.USER_SERVICE);
+ // invalidate cache
+ um.setUserName(newName);
+
+ // updated UserInfo should be returned
+ cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+ assertThat(cachedUserInfo.name).isEqualTo(newName);
+
+ // get user name from getUserName using context.getUserId
+ assertThat(um.getUserName()).isEqualTo(newName);
+ }
+
+ private void assumeManagedUsersSupported() {
+ // In Automotive, if headless system user is enabled, a managed user cannot be created
+ // under a primary user.
+ assumeTrue("device doesn't support managed users",
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)
+ && (!isAutomotive() || !UserManager.isHeadlessSystemUserMode()));
+ }
+
+ private void removeUser(int userId) {
+ mUserManager.removeUser(userId);
+ mUserRemovalWaiter.waitFor(userId);
+ mUsersToRemove.remove(userId);
+ }
+
+ private boolean isAutomotive() {
+ return mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS b/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS
deleted file mode 100644
index bc8efa92c16f..000000000000
--- a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/core/java/com/android/server/security/adaptiveauthentication/OWNERS \ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
index 24bf6ca507e6..b1df0f1e9cce 100644
--- a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
@@ -60,7 +60,7 @@ public class AdvancedProtectionServiceTest {
public void setup() throws Settings.SettingNotFoundException {
mContext = mock(Context.class);
mPermissionEnforcer = new FakePermissionEnforcer();
- mPermissionEnforcer.grant(Manifest.permission.SET_ADVANCED_PROTECTION_MODE);
+ mPermissionEnforcer.grant(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE);
mPermissionEnforcer.grant(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
mStore = new AdvancedProtectionService.AdvancedProtectionStore(mContext) {
@@ -299,7 +299,7 @@ public class AdvancedProtectionServiceTest {
@Test
public void testSetProtection_withoutPermission() {
- mPermissionEnforcer.revoke(Manifest.permission.SET_ADVANCED_PROTECTION_MODE);
+ mPermissionEnforcer.revoke(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE);
assertThrows(SecurityException.class, () -> mService.setAdvancedProtectionEnabled(true));
}
diff --git a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
index 154494a13072..ee8eb9b35088 100644
--- a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package com.android.server.security.adaptiveauthentication;
+package com.android.server.security.authenticationpolicy;
import static android.adaptiveauth.Flags.FLAG_ENABLE_ADAPTIVE_AUTH;
import static android.adaptiveauth.Flags.FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS;
import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS;
+import static android.security.authenticationpolicy.AuthenticationPolicyManager.ERROR_UNSUPPORTED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
-import static com.android.server.security.adaptiveauthentication.AdaptiveAuthenticationService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS;
+import static com.android.server.security.authenticationpolicy.AuthenticationPolicyService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -66,12 +68,12 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * atest FrameworksServicesTests:AdaptiveAuthenticationServiceTest
+ * atest FrameworksServicesTests:AuthenticationPolicyServiceTest
*/
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class AdaptiveAuthenticationServiceTest {
+public class AuthenticationPolicyServiceTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -81,7 +83,7 @@ public class AdaptiveAuthenticationServiceTest {
private static final int REASON_UNKNOWN = 0; // BiometricRequestConstants.RequestReason
private Context mContext;
- private AdaptiveAuthenticationService mAdaptiveAuthenticationService;
+ private AuthenticationPolicyService mAuthenticationPolicyService;
@Mock
LockPatternUtils mLockPatternUtils;
@@ -95,6 +97,8 @@ public class AdaptiveAuthenticationServiceTest {
private WindowManagerInternal mWindowManager;
@Mock
private UserManagerInternal mUserManager;
+ @Mock
+ private SecureLockDeviceServiceInternal mSecureLockDeviceService;
@Captor
ArgumentCaptor<LockSettingsStateListener> mLockSettingsStateListenerCaptor;
@@ -123,10 +127,15 @@ public class AdaptiveAuthenticationServiceTest {
LocalServices.addService(WindowManagerInternal.class, mWindowManager);
LocalServices.removeServiceForTest(UserManagerInternal.class);
LocalServices.addService(UserManagerInternal.class, mUserManager);
+ if (android.security.Flags.secureLockdown()) {
+ LocalServices.removeServiceForTest(SecureLockDeviceServiceInternal.class);
+ LocalServices.addService(SecureLockDeviceServiceInternal.class,
+ mSecureLockDeviceService);
+ }
- mAdaptiveAuthenticationService = new AdaptiveAuthenticationService(
+ mAuthenticationPolicyService = new AuthenticationPolicyService(
mContext, mLockPatternUtils);
- mAdaptiveAuthenticationService.init();
+ mAuthenticationPolicyService.init();
verify(mLockSettings).registerLockSettingsStateListener(
mLockSettingsStateListenerCaptor.capture());
@@ -136,6 +145,12 @@ public class AdaptiveAuthenticationServiceTest {
// Set PRIMARY_USER_ID as the parent of MANAGED_PROFILE_USER_ID
when(mUserManager.getProfileParentId(eq(MANAGED_PROFILE_USER_ID)))
.thenReturn(PRIMARY_USER_ID);
+ if (android.security.Flags.secureLockdown()) {
+ when(mSecureLockDeviceService.enableSecureLockDevice(any()))
+ .thenReturn(ERROR_UNSUPPORTED);
+ when(mSecureLockDeviceService.disableSecureLockDevice(any()))
+ .thenReturn(ERROR_UNSUPPORTED);
+ }
}
@After
@@ -143,6 +158,9 @@ public class AdaptiveAuthenticationServiceTest {
LocalServices.removeServiceForTest(LockSettingsInternal.class);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.removeServiceForTest(UserManagerInternal.class);
+ if (android.security.Flags.secureLockdown()) {
+ LocalServices.removeServiceForTest(SecureLockDeviceServiceInternal.class);
+ }
}
@Test
@@ -318,13 +336,13 @@ public class AdaptiveAuthenticationServiceTest {
private void verifyNotLockDevice(int expectedCntFailedAttempts, int userId) {
assertEquals(expectedCntFailedAttempts,
- mAdaptiveAuthenticationService.mFailedAttemptsForUser.get(userId));
+ mAuthenticationPolicyService.mFailedAttemptsForUser.get(userId));
verify(mWindowManager, never()).lockNow();
}
private void verifyLockDevice(int userId) {
assertEquals(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS,
- mAdaptiveAuthenticationService.mFailedAttemptsForUser.get(userId));
+ mAuthenticationPolicyService.mFailedAttemptsForUser.get(userId));
verify(mLockPatternUtils).requireStrongAuth(
eq(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST), eq(userId));
// If userId is MANAGED_PROFILE_USER_ID, the StrongAuthFlag of its parent (PRIMARY_USER_ID)
diff --git a/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS
new file mode 100644
index 000000000000..4310d1a3a9db
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS \ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
index 79b0623640f6..8290e1cfb9db 100644
--- a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
@@ -20,7 +20,7 @@ import android.app.admin.DevicePolicyManagerInternal
import android.content.ComponentName
import android.content.Context
import android.content.pm.UserInfo
-import android.os.Bundle
+import android.os.PersistableBundle
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -139,7 +139,7 @@ class SupervisionServiceTest {
assertThat(userData.supervisionLockScreenEnabled).isFalse()
assertThat(userData.supervisionLockScreenOptions).isNull()
- service.mInternal.setSupervisionLockscreenEnabledForUser(USER_ID, true, Bundle())
+ service.mInternal.setSupervisionLockscreenEnabledForUser(USER_ID, true, PersistableBundle())
userData = service.getUserDataLocked(USER_ID)
assertThat(userData.supervisionLockScreenEnabled).isTrue()
assertThat(userData.supervisionLockScreenOptions).isNotNull()
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 3bc089fb3f5d..842c441e09f2 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -691,6 +691,40 @@ public class SystemConfigTest {
assertThat(actual).isEqualTo(expected);
}
+ /**
+ * Tests that readPermissions works correctly for the tags:
+ * disabled-in-sku, enabled-in-sku-override.
+ * I.e. that disabled-in-sku add package to block list and
+ * enabled-in-sku-override removes package from the list.
+ */
+ @Test
+ public void testDisablePackageInSku() throws Exception {
+ final String disable_in_sku =
+ "<config>\n"
+ + " <disabled-in-sku package=\"com.sony.product1.app\"/>\n"
+ + " <disabled-in-sku package=\"com.sony.product2.app\"/>\n"
+ + "</config>\n";
+
+ final String enable_in_sku_override =
+ "<config>\n"
+ + " <enabled-in-sku-override package=\"com.sony.product2.app\"/>\n"
+ + "</config>\n";
+
+ final File folder1 = createTempSubfolder("folder1");
+ createTempFile(folder1, "permissionFile1.xml", disable_in_sku);
+
+ final File folder2 = createTempSubfolder("folder2");
+ createTempFile(folder2, "permissionFile2.xml", enable_in_sku_override);
+
+ readPermissions(folder1, /* Grant all permission flags */ ~0);
+ readPermissions(folder2, /* Grant all permission flags */ ~0);
+
+ final ArraySet<String> blocklist = mSysConfig.getDisabledUntilUsedPreinstalledCarrierApps();
+
+ assertThat(blocklist).contains("com.sony.product1.app");
+ assertThat(blocklist).doesNotContain("com.sony.product2.app");
+ }
+
private void parseSharedLibraries(String contents) throws IOException {
File folder = createTempSubfolder("permissions_folder");
createTempFile(folder, "permissions.xml", contents);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index cc0286508cdc..dd278fccad14 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -84,7 +84,9 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.GroupHelper.CachedSummary;
+import com.android.server.notification.GroupHelper.FullyQualifiedGroupKey;
import com.android.server.notification.GroupHelper.NotificationAttributes;
+import com.android.server.notification.GroupHelper.NotificationSectioner;
import org.junit.Before;
import org.junit.Rule;
@@ -2168,6 +2170,174 @@ public class GroupHelperTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
+ public void testRemoveChildNotification_summaryForceGrouped() {
+ // Check that removing all child notifications from a group will trigger empty summary
+ // force grouping re-evaluation
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+ // Post summaries without children, below the force grouping limit
+ for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+ NotificationRecord summary = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+ UserHandle.SYSTEM, "testGrp " + i, true);
+ notificationList.add(summary);
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+ }
+ // Post a valid (full) group
+ final int summaryId = 4242;
+ final int numChildren = 3;
+ final ArrayList<NotificationRecord> childrenToRemove = new ArrayList<>();
+ NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+ String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp " + summaryId, true);
+ notificationList.add(summary);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ for (int i = 0; i < numChildren; i++) {
+ NotificationRecord child = getNotificationRecord(pkg, summaryId + 42,
+ String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + summaryId, false);
+ notificationList.add(child);
+ // schedule all children for removal
+ childrenToRemove.add(child);
+ }
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+ verifyZeroInteractions(mCallback);
+
+ // Remove all child notifications from the valid group => summary without children
+ Mockito.reset(mCallback);
+ for (NotificationRecord r: childrenToRemove) {
+ notificationList.remove(r);
+ mGroupHelper.onNotificationRemoved(r, notificationList);
+ }
+ // Only call onGroupedNotificationRemovedWithDelay with the summary notification
+ mGroupHelper.onGroupedNotificationRemovedWithDelay(summary, notificationList,
+ summaryByGroup);
+
+ // Check that the summaries were force grouped
+ final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(expectedGroupKey), anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+ eq(expectedGroupKey), eq(true));
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
+ public void testRemoveChildNotification_groupBecomesSingleton() {
+ // Check that removing child notifications from a group will trigger singleton force
+ // grouping re-evaluation
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+ // Post singleton groups, under forced group limit
+ for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT - 1; i++) {
+ NotificationRecord summary = getNotificationRecord(pkg, i,
+ String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true);
+ notificationList.add(summary);
+ NotificationRecord child = getNotificationRecord(pkg, i + 42,
+ String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + i, false);
+ notificationList.add(child);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+ }
+ // Post a valid (full) group
+ final int summaryId = 4242;
+ final int numChildren = 3;
+ final ArrayList<NotificationRecord> childrenToRemove = new ArrayList<>();
+ NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+ String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp " + summaryId, true);
+ notificationList.add(summary);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ for (int i = 0; i < numChildren; i++) {
+ NotificationRecord child = getNotificationRecord(pkg, summaryId + 42,
+ String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + summaryId, false);
+ notificationList.add(child);
+
+ // schedule all children except one for removal
+ if (i < numChildren - 1) {
+ childrenToRemove.add(child);
+ }
+ }
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+ verifyZeroInteractions(mCallback);
+
+ // Remove some child notifications from the valid group, transform into a singleton group
+ Mockito.reset(mCallback);
+ for (NotificationRecord r: childrenToRemove) {
+ notificationList.remove(r);
+ mGroupHelper.onNotificationRemoved(r, notificationList);
+ }
+ // Only call onGroupedNotificationRemovedWithDelay with the summary notification
+ mGroupHelper.onGroupedNotificationRemovedWithDelay(summary, notificationList,
+ summaryByGroup);
+
+ // Check that the singleton groups were force grouped
+ final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(expectedGroupKey), anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
+ verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
+ eq(expectedGroupKey), eq(true));
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
+ verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).removeAppProvidedSummary(
+ anyString());
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
+ public void testRemoveAllGroupNotifications_noForceGrouping() {
+ // Check that removing all notifications from a group will not trigger any force grouping
+ // re-evaluation
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+ // Post summaries without children, below the force grouping limit
+ for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+ NotificationRecord summary = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+ UserHandle.SYSTEM, "testGrp " + i, true);
+ notificationList.add(summary);
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+ }
+ // Post a valid (full) group
+ final int summaryId = 4242;
+ final int numChildren = 3;
+ final String groupToRemove = "testRemoveGrp";
+ NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+ String.valueOf(summaryId), UserHandle.SYSTEM, groupToRemove + summaryId, true);
+ notificationList.add(summary);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ for (int i = 0; i < numChildren; i++) {
+ NotificationRecord child = getNotificationRecord(pkg, summaryId + 42,
+ String.valueOf(i + 42), UserHandle.SYSTEM, groupToRemove + summaryId, false);
+ notificationList.add(child);
+ }
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+ verifyZeroInteractions(mCallback);
+
+ // Remove all child notifications from the valid group => summary without children
+ Mockito.reset(mCallback);
+ for (NotificationRecord r: notificationList) {
+ if (r.getGroupKey().contains(groupToRemove)) {
+ r.isCanceled = true;
+ mGroupHelper.onNotificationRemoved(r, notificationList);
+ }
+ }
+ // Only call onGroupedNotificationRemovedWithDelay with the summary notification
+ mGroupHelper.onGroupedNotificationRemovedWithDelay(summary, notificationList,
+ summaryByGroup);
+ // Check that nothing was force grouped
+ verifyZeroInteractions(mCallback);
+ }
+
+ @Test
@EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
public void testMoveAggregateGroups_updateChannel() {
final String pkg = "package";
@@ -2298,6 +2468,7 @@ public class GroupHelperTest extends UiServiceTestCase {
final String pkg = "package";
final String expectedGroupKey_alerting = GroupHelper.getFullAggregateGroupKey(pkg,
AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ final int numNotifications = 2 * AUTOGROUP_AT_COUNT;
int numNotificationChannel1 = 0;
final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1",
"TEST_CHANNEL_ID1", IMPORTANCE_DEFAULT);
@@ -2307,7 +2478,7 @@ public class GroupHelperTest extends UiServiceTestCase {
final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
// Post notifications with different channels that autogroup within the same section
NotificationRecord r;
- for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ for (int i = 0; i < numNotifications; i++) {
if (i % 2 == 0) {
r = getNotificationRecord(pkg, i, String.valueOf(i),
UserHandle.SYSTEM, "testGrp " + i, false, channel1);
@@ -2324,12 +2495,12 @@ public class GroupHelperTest extends UiServiceTestCase {
"TEST_CHANNEL_ID1");
verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
eq(expectedGroupKey_alerting), anyInt(), eq(expectedSummaryAttr));
- verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+ verify(mCallback, times(numNotifications)).addAutoGroup(anyString(),
eq(expectedGroupKey_alerting), eq(true));
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
- any());
+ verify(mCallback, times(numNotifications - AUTOGROUP_AT_COUNT)).updateAutogroupSummary(
+ anyInt(), anyString(), anyString(), any());
Mockito.reset(mCallback);
// Update channel1's importance
@@ -2375,7 +2546,7 @@ public class GroupHelperTest extends UiServiceTestCase {
final List<NotificationRecord> notificationList = new ArrayList<>();
final String pkg = "package";
final int summaryId = 0;
- final int numChildNotif = 4;
+ final int numChildNotif = 2 * AUTOGROUP_AT_COUNT;
// Create an app-provided group: summary + child notifications
final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1",
@@ -2435,8 +2606,8 @@ public class GroupHelperTest extends UiServiceTestCase {
eq(expectedGroupKey_social), eq(true));
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
- verify(mCallback, times(numChildNotif / 2)).updateAutogroupSummary(anyInt(), anyString(),
- anyString(), any());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
verify(mCallback, times(numChildNotif)).removeAppProvidedSummaryOnClassification(
anyString(), eq(originalAppGroupKey));
}
@@ -2513,9 +2684,10 @@ public class GroupHelperTest extends UiServiceTestCase {
final List<NotificationRecord> notificationList = new ArrayList<>();
final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
final String pkg = "package";
+ final int numChildNotifications = AUTOGROUP_AT_COUNT;
// Post singleton groups, above forced group limit
- for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT; i++) {
+ for (int i = 0; i < numChildNotifications; i++) {
NotificationRecord summary = getNotificationRecord(pkg, i,
String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true);
notificationList.add(summary);
@@ -2545,13 +2717,13 @@ public class GroupHelperTest extends UiServiceTestCase {
// Check that notifications are forced grouped and app-provided summaries are canceled
verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social));
- verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
+ verify(mCallback, times(numChildNotifications)).addAutoGroup(anyString(),
eq(expectedGroupKey_social), eq(true));
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
- verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
any());
- verify(mCallback, times(2)).removeAppProvidedSummaryOnClassification(
+ verify(mCallback, times(numChildNotifications)).removeAppProvidedSummaryOnClassification(
anyString(), anyString());
// Adjust group key and cancel summaries
@@ -2593,14 +2765,16 @@ public class GroupHelperTest extends UiServiceTestCase {
AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
String expectedTriggeringKey = null;
// Post singleton groups, above forced group limit
- for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT; i++) {
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
NotificationRecord summary = getNotificationRecord(pkg, i,
String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true);
notificationList.add(summary);
NotificationRecord child = getNotificationRecord(pkg, i + 42,
String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + i, false);
notificationList.add(child);
- expectedTriggeringKey = child.getKey();
+ if (i == AUTOGROUP_SINGLETONS_AT_COUNT - 1) {
+ expectedTriggeringKey = child.getKey();
+ }
summaryByGroup.put(summary.getGroupKey(), summary);
mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
summary.isCanceled = true; // simulate removing the app summary
@@ -2611,14 +2785,8 @@ public class GroupHelperTest extends UiServiceTestCase {
verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg),
eq(expectedTriggeringKey), eq(expectedGroupKey_alerting), anyInt(),
eq(getNotificationAttributes(BASE_FLAGS)));
- verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
- eq(expectedGroupKey_alerting), eq(true));
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
- any());
- verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).removeAppProvidedSummary(
- anyString());
assertThat(mGroupHelper.findCanceledSummary(pkg, String.valueOf(0), 0,
UserHandle.SYSTEM.getIdentifier())).isNotNull();
assertThat(mGroupHelper.findCanceledSummary(pkg, String.valueOf(1), 1,
@@ -2645,12 +2813,12 @@ public class GroupHelperTest extends UiServiceTestCase {
// Check that all notifications are moved to the social section group
verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social));
- verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
eq(expectedGroupKey_social), eq(true));
// Check that the alerting section group is removed
verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg),
eq(expectedGroupKey_alerting));
- verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).updateAutogroupSummary(anyInt(),
+ verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).updateAutogroupSummary(anyInt(),
anyString(), anyString(), any());
}
@@ -2666,7 +2834,7 @@ public class GroupHelperTest extends UiServiceTestCase {
final String pkg = "package";
final int summaryId = 0;
- final int numChildren = 3;
+ final int numChildren = AUTOGROUP_AT_COUNT;
// Post a regular/valid group: summary + notifications
NotificationRecord summary = getNotificationRecord(pkg, summaryId,
String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true);
@@ -2706,13 +2874,211 @@ public class GroupHelperTest extends UiServiceTestCase {
eq(true));
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
- verify(mCallback, times(numChildren - 1)).updateAutogroupSummary(anyInt(), anyString(),
- anyString(), any());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification(anyString(),
anyString());
}
@Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
+ FLAG_NOTIFICATION_CLASSIFICATION})
+ public void testUnbundleNotification_originalSummaryMissing_autogroupInNewSection() {
+ // Check that unbundled notifications are moved to the original section and aggregated
+ // with existing autogrouped notifications
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+
+ final int summaryId = 0;
+ final int numChildren = AUTOGROUP_AT_COUNT - 1;
+ // Post a regular/valid group: summary + notifications (one less than autogroup limit)
+ NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+ String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true);
+ notificationList.add(summary);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ final String originalAppGroupKey = summary.getGroupKey();
+ final NotificationChannel originalChannel = summary.getChannel();
+ for (int i = 0; i < numChildren; i++) {
+ NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+ UserHandle.SYSTEM, "testGrp", false);
+ notificationList.add(child);
+ mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
+ }
+
+ // Classify/bundle all child notifications: original group & summary is removed
+ final NotificationChannel socialChannel = new NotificationChannel(
+ NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID,
+ IMPORTANCE_DEFAULT);
+ for (NotificationRecord record: notificationList) {
+ if (record.getOriginalGroupKey().contains("testGrp")
+ && record.getNotification().isGroupChild()) {
+ record.updateNotificationChannel(socialChannel);
+ mGroupHelper.onChannelUpdated(record);
+ }
+ }
+
+ // Check that no autogroup summaries were created for the social section
+ verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(),
+ anyString(), anyInt(), any());
+ verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean());
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
+ verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification(
+ anyString(), eq(originalAppGroupKey));
+
+ // Cancel summary
+ summary.isCanceled = true;
+ summaryByGroup.clear();
+ notificationList.remove(summary);
+
+ // Add 1 ungrouped notification in the original section
+ NotificationRecord ungroupedNotification = getNotificationRecord(pkg, 4242,
+ String.valueOf(4242), UserHandle.SYSTEM);
+ notificationList.add(ungroupedNotification);
+ mGroupHelper.onNotificationPosted(ungroupedNotification, false);
+
+ // Unbundle the bundled notifications => notifications are moved back to the original group
+ // and an aggregate group is created because autogroup limit is reached
+ reset(mCallback);
+ for (NotificationRecord record: notificationList) {
+ if (record.getNotification().isGroupChild()
+ && record.getOriginalGroupKey().contains("testGrp")
+ && NotificationChannel.SYSTEM_RESERVED_IDS.contains(
+ record.getChannel().getId())) {
+ record.updateNotificationChannel(originalChannel);
+ mGroupHelper.onNotificationUnbundled(record, false);
+ }
+ }
+
+ // Check that a new aggregate group is created
+ final String expectedGroupKey_alerting = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(expectedGroupKey_alerting), anyInt(), any());
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+ eq(expectedGroupKey_alerting), eq(true));
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, times(numChildren)).removeAutoGroupSummary(anyInt(), anyString(),
+ anyString());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
+ FLAG_NOTIFICATION_CLASSIFICATION})
+ public void testUnbundleNotification_originalSummaryExists() {
+ // Check that unbundled notifications are moved to the original section and original group
+ // when the original summary is still present
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+
+ final int summaryId = 0;
+ final int numChildren = AUTOGROUP_AT_COUNT + 1;
+ // Post a regular/valid group: summary + notifications
+ NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+ String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true);
+ notificationList.add(summary);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ final String originalAppGroupKey = summary.getGroupKey();
+ final NotificationChannel originalChannel = summary.getChannel();
+ for (int i = 0; i < numChildren; i++) {
+ NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+ UserHandle.SYSTEM, "testGrp", false);
+ notificationList.add(child);
+ mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
+ }
+
+ // Classify/bundle child notifications: all except one, to keep the original group
+ final NotificationChannel socialChannel = new NotificationChannel(
+ NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID,
+ IMPORTANCE_DEFAULT);
+ final String expectedGroupKey_social = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "SocialSection", UserHandle.SYSTEM.getIdentifier());
+ final NotificationAttributes expectedSummaryAttr_social = new NotificationAttributes(
+ BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT,
+ NotificationChannel.SOCIAL_MEDIA_ID);
+ int numChildrenBundled = 0;
+ for (NotificationRecord record: notificationList) {
+ if (record.getOriginalGroupKey().contains("testGrp")
+ && record.getNotification().isGroupChild()) {
+ record.updateNotificationChannel(socialChannel);
+ mGroupHelper.onChannelUpdated(record);
+ numChildrenBundled++;
+ if (numChildrenBundled == AUTOGROUP_AT_COUNT) {
+ break;
+ }
+ }
+ }
+
+ // Check that 1 autogroup summaries were created for the social section
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+ eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social));
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+ eq(expectedGroupKey_social), eq(true));
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).removeAppProvidedSummaryOnClassification(
+ anyString(), eq(originalAppGroupKey));
+
+ // Adjust group key and cancel summaries
+ for (NotificationRecord record: notificationList) {
+ if (record.getNotification().isGroupSummary()) {
+ record.isCanceled = true;
+ } else if (record.getOriginalGroupKey().contains("testGrp")
+ && NotificationChannel.SYSTEM_RESERVED_IDS.contains(
+ record.getChannel().getId())) {
+ record.setOverrideGroupKey(expectedGroupKey_social);
+ }
+ }
+
+ // Add 1 ungrouped notification in the original section
+ NotificationRecord ungroupedNotification = getNotificationRecord(pkg, 4242,
+ String.valueOf(4242), UserHandle.SYSTEM);
+ notificationList.add(ungroupedNotification);
+ mGroupHelper.onNotificationPosted(ungroupedNotification, false);
+
+ // Unbundle the bundled notifications => social section summary is destroyed
+ // and notifications are moved back to the original group
+ reset(mCallback);
+ for (NotificationRecord record: notificationList) {
+ if (record.getNotification().isGroupChild()
+ && record.getOriginalGroupKey().contains("testGrp")
+ && NotificationChannel.SYSTEM_RESERVED_IDS.contains(
+ record.getChannel().getId())) {
+ record.updateNotificationChannel(originalChannel);
+ mGroupHelper.onNotificationUnbundled(record, true);
+ }
+ }
+
+ // Check that the autogroup summary for the social section was removed
+ // and that no new autogroup summaries were created
+ verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(),
+ anyString(), anyInt(), any());
+ verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean());
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg),
+ eq(expectedGroupKey_social));
+ verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).updateAutogroupSummary(anyInt(), eq(pkg),
+ eq(expectedGroupKey_social), any());
+
+ for (NotificationRecord record: notificationList) {
+ if (record.getNotification().isGroupChild()
+ && record.getOriginalGroupKey().contains("testGrp")) {
+ assertThat(record.getSbn().getOverrideGroupKey()).isNull();
+ }
+ }
+ }
+
+ @Test
@EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
public void testMoveAggregateGroups_updateChannel_groupsUngrouped() {
final String pkg = "package";
@@ -3059,6 +3425,120 @@ public class GroupHelperTest extends UiServiceTestCase {
@Test
@EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
@DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS)
+ public void testNonGroupableChildren_singletonGroups_disableConversations() {
+ // Check that singleton groups with children that are not groupable, is not grouped
+ // Even though the group summary is a regular (alerting) notification, the children are
+ // conversations => the group should not be forced grouped.
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+
+ // Trigger notification, ungrouped
+ final int triggerId = 1;
+ NotificationRecord triggerNotification = getNotificationRecord(pkg, triggerId,
+ String.valueOf(triggerId), UserHandle.SYSTEM);
+ notificationList.add(triggerNotification);
+ final NotificationSectioner triggerSection = GroupHelper.getSection(triggerNotification);
+ final FullyQualifiedGroupKey triggerFullAggregateGroupKey = new FullyQualifiedGroupKey(
+ triggerNotification.getUserId(), triggerNotification.getSbn().getPackageName(),
+ triggerSection);
+
+ // Add singleton group with alerting child
+ final String groupName_valid = "testGrp_valid";
+ final int summaryId_valid = 0;
+ NotificationRecord summary = getNotificationRecord(pkg, summaryId_valid,
+ String.valueOf(summaryId_valid), UserHandle.SYSTEM, groupName_valid, true);
+ notificationList.add(summary);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ final String groupKey_valid = summary.getGroupKey();
+ NotificationRecord child = getNotificationRecord(pkg, summaryId_valid + 42,
+ String.valueOf(summaryId_valid + 42), UserHandle.SYSTEM, groupName_valid, false);
+ notificationList.add(child);
+
+ // Add singleton group with conversation child
+ final String groupName_invalid = "testGrp_invalid";
+ final int summaryId_invalid = 100;
+ summary = getNotificationRecord(pkg, summaryId_invalid,
+ String.valueOf(summaryId_invalid), UserHandle.SYSTEM, groupName_invalid, true);
+ notificationList.add(summary);
+ final String groupKey_invalid = summary.getGroupKey();
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ child = getNotificationRecord(pkg, summaryId_invalid + 42,
+ String.valueOf(summaryId_invalid + 42), UserHandle.SYSTEM, groupName_invalid,
+ false);
+ child = spy(child);
+ when(child.isConversation()).thenReturn(true);
+ notificationList.add(child);
+
+ // Check that the invalid group will not be force grouped
+ final ArrayMap<String, NotificationRecord> sparseGroups = mGroupHelper.getSparseGroups(
+ triggerFullAggregateGroupKey, notificationList, summaryByGroup, triggerSection);
+ assertThat(sparseGroups).containsKey(groupKey_valid);
+ assertThat(sparseGroups).doesNotContainKey(groupKey_invalid);
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS})
+ public void testNonGroupableChildren_singletonGroups_enableConversations() {
+ // Check that singleton groups with children that are not groupable, is not grouped
+ // Conversations are groupable (FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS is enabled)
+ // The invalid group is the alerting notifications: because the triggering notifications'
+ // section is Conversations, so the alerting group should be skipped.
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+
+ // Trigger notification, ungrouped conversation
+ final int triggerId = 1;
+ NotificationRecord triggerNotification = getNotificationRecord(pkg, triggerId,
+ String.valueOf(triggerId), UserHandle.SYSTEM);
+ triggerNotification = spy(triggerNotification);
+ when(triggerNotification.isConversation()).thenReturn(true);
+ notificationList.add(triggerNotification);
+ final NotificationSectioner triggerSection = GroupHelper.getSection(triggerNotification);
+ final FullyQualifiedGroupKey triggerFullAggregateGroupKey = new FullyQualifiedGroupKey(
+ triggerNotification.getUserId(), triggerNotification.getSbn().getPackageName(),
+ triggerSection);
+
+ // Add singleton group with conversation child
+ final String groupName_valid = "testGrp_valid";
+ final int summaryId_valid = 0;
+ NotificationRecord summary = getNotificationRecord(pkg, summaryId_valid,
+ String.valueOf(summaryId_valid), UserHandle.SYSTEM, groupName_valid, true);
+ summary = spy(summary);
+ when(summary.isConversation()).thenReturn(true);
+ notificationList.add(summary);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ final String groupKey_valid = summary.getGroupKey();
+ NotificationRecord child = getNotificationRecord(pkg, summaryId_valid + 42,
+ String.valueOf(summaryId_valid + 42), UserHandle.SYSTEM, groupName_valid, false);
+ child = spy(child);
+ when(child.isConversation()).thenReturn(true);
+ notificationList.add(child);
+
+ // Add singleton group with non-conversation child
+ final String groupName_invalid = "testGrp_invalid";
+ final int summaryId_invalid = 100;
+ summary = getNotificationRecord(pkg, summaryId_invalid,
+ String.valueOf(summaryId_invalid), UserHandle.SYSTEM, groupName_invalid, true);
+ notificationList.add(summary);
+ final String groupKey_invalid = summary.getGroupKey();
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ child = getNotificationRecord(pkg, summaryId_invalid + 42,
+ String.valueOf(summaryId_invalid + 42), UserHandle.SYSTEM, groupName_invalid,
+ false);
+ notificationList.add(child);
+
+ // Check that the invalid group will not be force grouped
+ final ArrayMap<String, NotificationRecord> sparseGroups = mGroupHelper.getSparseGroups(
+ triggerFullAggregateGroupKey, notificationList, summaryByGroup, triggerSection);
+ assertThat(sparseGroups).containsKey(groupKey_valid);
+ assertThat(sparseGroups).doesNotContainKey(groupKey_invalid);
+ }
+
+ @Test
+ @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
+ @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS)
public void testNonGroupableNotifications() {
// Check that there is no valid section for: conversations, calls, foreground services
NotificationRecord notification_conversation = mock(NotificationRecord.class);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 6eb2f718a0e9..decbaacdcef9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -60,8 +60,6 @@ import android.testing.TestableContext;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
-import android.util.Log;
-import android.util.Slog;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -720,6 +718,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
public void testDefaultAllowedKeyAdjustments_readWriteXml() throws Exception {
mAssistants.loadDefaultsFromConfig(true);
@@ -728,4 +727,79 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
.containsExactly(TYPE_PROMOTION);
}
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testSetAssistantAdjustmentKeyTypeStateForPackage_allowsAndDenies() {
+ // Given that a package is allowed to have its type adjusted,
+ String allowedPackage = "allowed.package";
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+ mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
+
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+ assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+
+ // Set type adjustment disallowed for this package
+ mAssistants.setTypeAdjustmentForPackageState(allowedPackage, false);
+
+ // Then the package is marked as denied
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactly(allowedPackage);
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+
+ // Set type adjustment allowed again
+ mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
+
+ // Then the package is marked as allowed again
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+ assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testSetAssistantAdjustmentKeyTypeStateForPackage_deniesMultiple() {
+ // Given packages not allowed to have their type adjusted,
+ String deniedPkg1 = "denied.Pkg1";
+ String deniedPkg2 = "denied.Pkg2";
+ String deniedPkg3 = "denied.Pkg3";
+ // Set type adjustment disallowed for these packages
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, false);
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+
+ // Then the packages are marked as denied
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg2, deniedPkg3));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+
+ // And when we re-allow one of them,
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, true);
+
+ // Then the rest of the original packages are still marked as denied.
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
+ assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
+ assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ public void testSetAssistantAdjustmentKeyTypeStateForPackage_readWriteXml() throws Exception {
+ mAssistants.loadDefaultsFromConfig(true);
+ String deniedPkg1 = "denied.Pkg1";
+ String allowedPkg2 = "allowed.Pkg2";
+ String deniedPkg3 = "denied.Pkg3";
+ // Set type adjustment disallowed or allowed for these packages
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
+ mAssistants.setTypeAdjustmentForPackageState(allowedPkg2, true);
+ mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+
+ writeXmlAndReload(USER_ALL);
+
+ assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+ .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
+ }
} \ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index b34b1fb39a7f..bf3333349b82 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -907,10 +907,18 @@ public class NotificationListenersTest extends UiServiceTestCase {
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
verify(mNm.mHandler, times(1)).post(runnableCaptor.capture());
runnableCaptor.getValue().run();
- ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
- ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
- verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
- StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+ StatusBarNotification sbnResult = null;
+ if (android.app.Flags.noSbnholder()) {
+ ArgumentCaptor<StatusBarNotification> sbnCaptor =
+ ArgumentCaptor.forClass(StatusBarNotification.class);
+ verify(sysuiListener, times(1)).onNotificationPostedFull(sbnCaptor.capture(), any());
+ sbnResult = sbnCaptor.getValue();
+ } else {
+ ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+ ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+ verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+ sbnResult = sbnCaptor.getValue().get();
+ }
assertThat(sbnResult.getNotification()
.extras.getCharSequence(Notification.EXTRA_TITLE).toString())
.isEqualTo("new title");
@@ -920,7 +928,7 @@ public class NotificationListenersTest extends UiServiceTestCase {
}
@Test
- public void testListenerPostLifeimteExtension_postsToAppropriateListeners() throws Exception {
+ public void testListenerPostLifetimeExtension_postsToAppropriateListeners() throws Exception {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
// Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY.
@@ -998,16 +1006,29 @@ public class NotificationListenersTest extends UiServiceTestCase {
r.run();
}
- ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
- ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
- verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
- StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+ StatusBarNotification sbnResult = null;
+ if (android.app.Flags.noSbnholder()) {
+ ArgumentCaptor<StatusBarNotification> sbnCaptor =
+ ArgumentCaptor.forClass(StatusBarNotification.class);
+ verify(sysuiListener, times(1)).onNotificationPostedFull(sbnCaptor.capture(), any());
+ sbnResult = sbnCaptor.getValue();
+ } else {
+ ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+ ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+ verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+ sbnResult = sbnCaptor.getValue().get();
+ }
assertThat(sbnResult.getNotification()
.extras.getCharSequence(Notification.EXTRA_TITLE).toString())
.isEqualTo("new title");
- verify(otherListener1, times(1)).onNotificationPosted(any(), any());
- verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+ if (android.app.Flags.noSbnholder()) {
+ verify(otherListener1, times(1)).onNotificationPostedFull(any(), any());
+ verify(otherListener2, times(1)).onNotificationPostedFull(any(), any());
+ } else {
+ verify(otherListener1, times(1)).onNotificationPosted(any(), any());
+ verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+ }
}
@Test
@@ -1083,16 +1104,29 @@ public class NotificationListenersTest extends UiServiceTestCase {
r.run();
}
- ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
- ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
- verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
- StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+ StatusBarNotification sbnResult = null;
+ if (android.app.Flags.noSbnholder()) {
+ ArgumentCaptor<StatusBarNotification> sbnCaptor =
+ ArgumentCaptor.forClass(StatusBarNotification.class);
+ verify(sysuiListener, times(1)).onNotificationPostedFull(sbnCaptor.capture(), any());
+ sbnResult = sbnCaptor.getValue();
+ } else {
+ ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+ ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+ verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+ sbnResult = sbnCaptor.getValue().get();
+ }
assertThat(sbnResult.getNotification()
.extras.getCharSequence(Notification.EXTRA_TITLE).toString())
.isEqualTo("new title");
- verify(otherListener1, times(1)).onNotificationPosted(any(), any());
- verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+ if (android.app.Flags.noSbnholder()) {
+ verify(otherListener1, times(1)).onNotificationPostedFull(any(), any());
+ verify(otherListener2, times(1)).onNotificationPostedFull(any(), any());
+ } else {
+ verify(otherListener1, times(1)).onNotificationPosted(any(), any());
+ verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+ }
}
/**
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index eae587bc0187..863f42f3d1c1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -210,6 +210,7 @@ import android.app.Person;
import android.app.RemoteInput;
import android.app.RemoteInputHistoryItem;
import android.app.StatsManager;
+import android.app.ZenBypassingApp;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.backup.BackupRestoreEventLogger;
import android.app.job.JobScheduler;
@@ -231,7 +232,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.ModuleInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
@@ -336,12 +336,12 @@ import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
-import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
-import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
import com.google.android.collect.Lists;
import com.google.common.collect.ImmutableList;
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -489,7 +489,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private final NotificationChannel mParentChannel =
new NotificationChannel(PARENT_CHANNEL_ID, "parentName", IMPORTANCE_DEFAULT);
private final NotificationChannel mConversationChannel =
- new NotificationChannel(CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT);
+ new NotificationChannel(
+ CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT);
private static final String PARENT_CHANNEL_ID = "parentChannelId";
private static final String CONVERSATION_CHANNEL_ID = "conversationChannelId";
@@ -3092,6 +3093,92 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
+ public void testScheduleGroupHelperWithDelay_onChildNotificationCanceled() throws Exception {
+ // Post summary + 2 child notification
+ final String originalGroupName = "originalGroup";
+ final int summaryId = 0;
+ final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
+ summaryId + 1, originalGroupName, false);
+ mService.addNotification(r1);
+ final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
+ summaryId + 2, originalGroupName, false);
+ mService.addNotification(r2);
+ final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
+ summaryId, originalGroupName, true);
+ mService.addNotification(summary);
+ final String originalGroupKey = summary.getGroupKey();
+ assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
+
+ // Cancel the child notifications
+ mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
+ r1.getSbn().getPackageName(), r1.getSbn().getTag(),
+ r1.getSbn().getId(), r1.getSbn().getUserId());
+ waitForIdle();
+
+ mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
+ r2.getSbn().getPackageName(), r2.getSbn().getTag(),
+ r2.getSbn().getId(), r2.getSbn().getUserId());
+ waitForIdle();
+
+ mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
+ waitForIdle();
+
+ // Check that onGroupedNotificationRemovedWithDelay was called only once
+ verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any());
+ verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any());
+ verify(mGroupHelper, times(1)).onGroupedNotificationRemovedWithDelay(eq(summary), any(),
+ any());
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
+ public void testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()
+ throws Exception {
+ // Post summary + 2 child notification
+ final String originalGroupName = "originalGroup";
+ final int summaryId = 0;
+ final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
+ summaryId + 1, originalGroupName, false);
+ mService.addNotification(r1);
+ final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
+ summaryId + 2, originalGroupName, false);
+ mService.addNotification(r2);
+ final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
+ summaryId, originalGroupName, true);
+ mService.addNotification(summary);
+ final String originalGroupKey = summary.getGroupKey();
+ assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
+
+ // Cancel all notifications: children + summary
+ mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
+ r1.getSbn().getPackageName(), r1.getSbn().getTag(),
+ r1.getSbn().getId(), r1.getSbn().getUserId());
+ waitForIdle();
+
+ mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
+ r2.getSbn().getPackageName(), r2.getSbn().getTag(),
+ r2.getSbn().getId(), r2.getSbn().getUserId());
+ waitForIdle();
+
+ mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(),
+ summary.getSbn().getPackageName(), summary.getSbn().getTag(),
+ summary.getSbn().getId(), summary.getSbn().getUserId());
+ waitForIdle();
+
+ mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
+ waitForIdle();
+
+ // Check that onGroupedNotificationRemovedWithDelay was never called: summary was canceled
+ verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any());
+ verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any());
+ verify(mGroupHelper, times(1)).onNotificationRemoved(eq(summary), any());
+ verify(mGroupHelper, never()).onGroupedNotificationRemovedWithDelay(any(), any(), any());
+ }
+
+ @Test
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
when(mAmi.applyForegroundServiceNotification(
any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
@@ -4296,8 +4383,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
- mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_onTv", 0,
- generateNotificationRecord(null, tv).getNotification(), mUserId);
+ mBinderService.enqueueNotificationWithTag(
+ mPkg,
+ mPkg,
+ "testTvExtenderChannelOverride_onTv",
+ 0,
+ generateNotificationRecord(null, tv).getNotification(),
+ mUserId);
verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean());
}
@@ -4311,8 +4403,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel);
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
- mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_notOnTv",
- 0, generateNotificationRecord(null, tv).getNotification(), mUserId);
+ mBinderService.enqueueNotificationWithTag(
+ mPkg,
+ mPkg,
+ "testTvExtenderChannelOverride_notOnTv",
+ 0,
+ generateNotificationRecord(null, tv).getNotification(),
+ mUserId);
verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null),
anyBoolean(), anyBoolean());
@@ -7522,6 +7619,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
// Set up notifications that will be adjusted
final NotificationRecord r1 = spy(generateNotificationRecord(
@@ -7745,9 +7843,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setStyle(new Notification.MessagingStyle("").addMessage(message2));
- NotificationRecord recordB = new NotificationRecord(mContext, new StatusBarNotification(mPkg,
- mPkg, 0, "tag", mUid, 0, nbB.build(), UserHandle.getUserHandleForUid(mUid), null, 0),
- c);
+ NotificationRecord recordB =
+ new NotificationRecord(
+ mContext,
+ new StatusBarNotification(
+ mPkg,
+ mPkg,
+ 0,
+ "tag",
+ mUid,
+ 0,
+ nbB.build(),
+ UserHandle.getUserHandleForUid(mUid),
+ null,
+ 0),
+ c);
// Update means we drop access to first
reset(mUgmInternal);
@@ -13174,6 +13284,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void getPackagesBypassingDnd_blocked()
+ throws RemoteException, PackageManager.NameNotFoundException {
+
+ NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+ NotificationManager.IMPORTANCE_MAX);
+ NotificationChannel channel2 = new NotificationChannel("id3", "name3",
+ NotificationManager.IMPORTANCE_MAX);
+ NotificationChannel channel3 = new NotificationChannel("id4", "name3",
+ NotificationManager.IMPORTANCE_MAX);
+ channel1.setBypassDnd(true);
+ channel2.setBypassDnd(true);
+ channel3.setBypassDnd(false);
+ // has DND access, so can set bypassDnd attribute
+ mService.mPreferencesHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
+ /*has DND access*/ true, UID_N_MR1, false);
+ mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel2, true, true,
+ UID_P, false);
+ mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true,
+ UID_P, false);
+
+ when(mPackageManager.getPackageUid(eq(PKG_P), anyLong(), anyInt())).thenReturn(UID_P);
+ when(mPackageManager.getPackageUid(eq(PKG_N_MR1), anyLong(), anyInt()))
+ .thenReturn(UID_N_MR1);
+ when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false);
+ when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true);
+
+ assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList())
+ .containsExactly(new ZenBypassingApp(PKG_P, false));
+ }
+
+ @Test
public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
mService.setPreferencesHelper(mPreferencesHelper);
@@ -13187,125 +13328,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testGetPackagesBypassingDnd_empty() throws RemoteException {
mService.setPreferencesHelper(mPreferencesHelper);
- List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true);
+ List<String> result = mBinderService.getPackagesBypassingDnd(mUserId).getList();
assertThat(result).isEmpty();
}
@Test
- public void testGetPackagesBypassingDnd_excludeConversationChannels() throws RemoteException {
- mService.setPreferencesHelper(mPreferencesHelper);
-
- // Set packages
- PackageInfo pkg0 = new PackageInfo();
- pkg0.packageName = "pkg0";
- pkg0.applicationInfo = new ApplicationInfo();
- pkg0.applicationInfo.uid = mUid;
- PackageInfo pkg1 = new PackageInfo();
- pkg1.packageName = "pkg1";
- pkg1.applicationInfo = new ApplicationInfo();
- pkg1.applicationInfo.uid = mUid;
- PackageInfo pkg2 = new PackageInfo();
- pkg2.packageName = "pkg2";
- pkg2.applicationInfo = new ApplicationInfo();
- pkg2.applicationInfo.uid = mUid;
-
- when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId))
- .thenReturn(List.of(pkg0, pkg1, pkg2));
-
- // Conversation channels
- NotificationChannel nc0 = new NotificationChannel("id0", "id0",
- NotificationManager.IMPORTANCE_HIGH);
- nc0.setConversationId("parentChannel", "conversationId");
-
- // Demoted conversation channel
- NotificationChannel nc1 = new NotificationChannel("id1", "id1",
- NotificationManager.IMPORTANCE_HIGH);
- nc1.setConversationId("parentChannel", "conversationId");
- nc1.setDemoted(true);
-
- // Non-conversation channels
- NotificationChannel nc2 = new NotificationChannel("id2", "id2",
- NotificationManager.IMPORTANCE_HIGH);
- NotificationChannel nc3 = new NotificationChannel("id3", "id3",
- NotificationManager.IMPORTANCE_HIGH);
-
- ParceledListSlice<NotificationChannel> pls0 =
- new ParceledListSlice(ImmutableList.of(nc0));
- ParceledListSlice<NotificationChannel> pls1 =
- new ParceledListSlice(ImmutableList.of(nc1));
- ParceledListSlice<NotificationChannel> pls2 =
- new ParceledListSlice(ImmutableList.of(nc2, nc3));
-
- when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid))
- .thenReturn(pls0);
- when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid))
- .thenReturn(pls1);
- when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid))
- .thenReturn(pls2);
-
- List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, false);
-
- assertThat(result).containsExactly("pkg1", "pkg2");
- }
-
- @Test
- public void testGetPackagesBypassingDnd_includeConversationChannels() throws RemoteException {
- mService.setPreferencesHelper(mPreferencesHelper);
-
- // Set packages
- PackageInfo pkg0 = new PackageInfo();
- pkg0.packageName = "pkg0";
- pkg0.applicationInfo = new ApplicationInfo();
- pkg0.applicationInfo.uid = mUid;
- PackageInfo pkg1 = new PackageInfo();
- pkg1.packageName = "pkg1";
- pkg1.applicationInfo = new ApplicationInfo();
- pkg1.applicationInfo.uid = mUid;
- PackageInfo pkg2 = new PackageInfo();
- pkg2.packageName = "pkg2";
- pkg2.applicationInfo = new ApplicationInfo();
- pkg2.applicationInfo.uid = mUid;
-
- when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId))
- .thenReturn(List.of(pkg0, pkg1, pkg2));
-
- // Conversation channels
- NotificationChannel nc0 = new NotificationChannel("id0", "id0",
- NotificationManager.IMPORTANCE_HIGH);
- nc0.setConversationId("parentChannel", "conversationId");
-
- // Demoted conversation channel
- NotificationChannel nc1 = new NotificationChannel("id1", "id1",
- NotificationManager.IMPORTANCE_HIGH);
- nc1.setConversationId("parentChannel", "conversationId");
- nc1.setDemoted(true);
-
- // Non-conversation channels
- NotificationChannel nc2 = new NotificationChannel("id2", "id2",
- NotificationManager.IMPORTANCE_HIGH);
- NotificationChannel nc3 = new NotificationChannel("id3", "id3",
- NotificationManager.IMPORTANCE_HIGH);
-
- ParceledListSlice<NotificationChannel> pls0 =
- new ParceledListSlice(ImmutableList.of(nc0));
- ParceledListSlice<NotificationChannel> pls1 =
- new ParceledListSlice(ImmutableList.of(nc1));
- ParceledListSlice<NotificationChannel> pls2 =
- new ParceledListSlice(ImmutableList.of(nc2, nc3));
-
- when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid))
- .thenReturn(pls0);
- when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid))
- .thenReturn(pls1);
- when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid))
- .thenReturn(pls2);
-
- List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true);
-
- assertThat(result).containsExactly("pkg0", "pkg1", "pkg2");
- }
-
- @Test
public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception {
// set the testable NMS to not system uid/appid
mService.isSystemUid = false;
@@ -15482,8 +15509,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
i, null, false).getSbn();
- mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCannotPostNonUijWhenOverLimit",
- sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ mBinderService.enqueueNotificationWithTag(
+ mPkg,
+ mPkg,
+ "testCannotPostNonUijWhenOverLimit",
+ sbn.getId(),
+ sbn.getNotification(),
+ sbn.getUserId());
waitForIdle();
}
@@ -16213,6 +16245,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+
+ mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
// No exception!
}
@@ -17194,6 +17228,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationManagerService.WorkerHandler.class);
mService.setHandler(handler);
when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
Bundle signals = new Bundle();
signals.putInt(KEY_TYPE, TYPE_NEWS);
@@ -17228,10 +17263,44 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
+ android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
+ public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception {
+ final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(r);
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mService.setHandler(handler);
+ when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+
+ Bundle signals = new Bundle();
+ signals.putInt(KEY_TYPE, TYPE_NEWS);
+ Adjustment adjustment = new Adjustment(
+ r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+
+ waitForIdle();
+
+ r.applyAdjustments();
+
+ assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
+
+ // When we block adjustments for this package
+ when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false);
+
+ signals.putInt(KEY_TYPE, TYPE_PROMOTION);
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+ waitForIdle();
+ r.applyAdjustments();
+ // Then the adjustment is not applied.
+ assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
+ }
+
+ @Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_granted() throws Exception {
- mContext.getTestablePermissions().setPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
// qualifying posted notification
Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
.setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -17306,8 +17375,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception {
- mContext.getTestablePermissions().setPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
// qualifying posted notification
Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
.setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -17337,8 +17404,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_revoked() throws Exception {
- mContext.getTestablePermissions().setPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
// start from true state
mBinderService.setCanBePromoted(mPkg, mUid, true, true);
@@ -17402,8 +17467,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception {
- mContext.getTestablePermissions().setPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
// start from true state
mBinderService.setCanBePromoted(mPkg, mUid, true, true);
@@ -17439,8 +17502,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testPostPromotableNotification() throws Exception {
mBinderService.setCanBePromoted(mPkg, mUid, true, true);
assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isTrue();
- mContext.getTestablePermissions().setPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
.setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -17467,8 +17528,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testPostPromotableNotification_noPermission() throws Exception {
- mContext.getTestablePermissions().setPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
+ mBinderService.setCanBePromoted(mPkg, mUid, false, true);
+ assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isFalse();
+
Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
@@ -17496,8 +17558,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testPostPromotableNotification_unimportantNotification() throws Exception {
mBinderService.setCanBePromoted(mPkg, mUid, true, true);
- mContext.getTestablePermissions().setPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
Notification n = new Notification.Builder(mContext, mMinChannel.getId())
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index e1b478cd1a1b..80e86a15156a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -108,6 +108,7 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.app.ZenBypassingApp;
import android.content.AttributionSource;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -255,6 +256,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
return FlagsParameterization.allCombinationsOf(
+ android.app.Flags.FLAG_API_RICH_ONGOING,
FLAG_NOTIFICATION_CLASSIFICATION, FLAG_MODES_UI);
}
@@ -2620,6 +2622,72 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ public void getPackagesBypassingDnd_noChannelsBypassing() throws Exception {
+ assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty();
+ }
+
+ @Test
+ public void getPackagesBypassingDnd_oneChannelBypassing_deleted() {
+ NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+ NotificationManager.IMPORTANCE_MAX);
+ channel1.setBypassDnd(true);
+ channel1.setDeleted(true);
+ // has DND access, so can set bypassDnd attribute
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
+ /*has DND access*/ true, UID_N_MR1, false);
+
+ assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty();
+ }
+
+ @Test
+ public void getPackagesBypassingDnd_oneChannelBypassing_groupBlocked() {
+ int uid = UID_N_MR1;
+ NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+ NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+ NotificationManager.IMPORTANCE_MAX);
+ channel1.setBypassDnd(true);
+ channel1.setGroup(ncg.getId());
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ true,
+ uid, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true,
+ uid, false);
+ ncg.setBlocked(true);
+
+ assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(uid))).isEmpty();
+ }
+
+ @Test
+ public void getPackagesBypassingDnd_multipleApps() {
+ List<ZenBypassingApp> expected = ImmutableList.of(
+ new ZenBypassingApp(PKG_O, true), new ZenBypassingApp(PKG_P, false));
+
+ NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+ NotificationManager.IMPORTANCE_MAX);
+ NotificationChannel channel2 = new NotificationChannel("id2", "name2",
+ NotificationManager.IMPORTANCE_MAX);
+ NotificationChannel channel3 = new NotificationChannel("id3", "name3",
+ NotificationManager.IMPORTANCE_MAX);
+ NotificationChannel channel4 = new NotificationChannel("id4", "name3",
+ NotificationManager.IMPORTANCE_MAX);
+ channel1.setBypassDnd(false);
+ channel2.setBypassDnd(true);
+ channel3.setBypassDnd(true);
+ channel4.setBypassDnd(false);
+ // has DND access, so can set bypassDnd attribute
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
+ /*has DND access*/ true, UID_N_MR1, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, true,
+ UID_O, false);
+ mHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true,
+ UID_P, false);
+ mHelper.createNotificationChannel(PKG_P, UID_P, channel4, true, true,
+ UID_P, false);
+
+ assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_O)))
+ .containsExactlyElementsIn(expected);
+ }
+
+ @Test
public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
@@ -6444,12 +6512,21 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
+ @DisableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
public void testNoAppHasPermissionToPromoteByDefault() {
mHelper.setShowBadge(PKG_P, UID_P, true);
assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isFalse();
}
@Test
+ @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING,
+ android.app.Flags.FLAG_UI_RICH_ONGOING})
+ public void testAllAppsHavePermissionToPromoteByDefault() {
+ mHelper.setShowBadge(PKG_P, UID_P, true);
+ assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isTrue();
+ }
+
+ @Test
@EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted() {
mHelper.setCanBePromoted(PKG_P, UID_P, true, true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java
index 4d82c3ccf4a1..949c5e2e1b0a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java
@@ -69,6 +69,8 @@ public class SystemZenRulesTest extends UiServiceTestCase {
R.string.zen_mode_trigger_summary_range_symbol_combination, "%1$s-%2$s");
mContext.getOrCreateTestableResources().addOverride(
R.string.zen_mode_trigger_summary_divider_text, ",");
+ mContext.getOrCreateTestableResources().addOverride(
+ R.string.zen_mode_trigger_summary_combined, "%1$s,%2$s");
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 4b94e103b9f4..09da0156eb82 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -49,6 +49,8 @@ import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
import static android.app.NotificationManager.Policy.STATE_PRIORITY_CHANNELS_BLOCKED;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
+import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
@@ -70,6 +72,7 @@ import static android.service.notification.ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI
import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_ACTIVATE;
import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_DEACTIVATE;
import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_NONE;
+import static android.service.notification.ZenModeConfig.implicitRuleId;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_NONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
@@ -84,8 +87,6 @@ import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED;
import static com.android.os.dnd.DNDProtoEnums.ROOT_CONFIG;
import static com.android.os.dnd.DNDProtoEnums.STATE_ALLOW;
import static com.android.os.dnd.DNDProtoEnums.STATE_DISALLOW;
-import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
-import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES;
import static com.android.server.notification.ZenModeEventLogger.ACTIVE_RULE_TYPE_MANUAL;
import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
@@ -102,6 +103,7 @@ import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -5348,6 +5350,22 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mTestableLooper.processAllMessages();
verify(mDeviceEffectsApplier).apply(eq(effects), eq(ORIGIN_APP));
+ assertTrue(mZenModeHelper.hasDeviceEffectsApplier());
+ }
+
+ @Test
+ public void testHasDeviceEffectsApplier_returnsFalseIfNotSet() {
+ assertFalse(mZenModeHelper.hasDeviceEffectsApplier());
+ }
+
+ @Test
+ @EnableFlags(FLAG_MODES_API)
+ public void testSettingDeviceEffects_throwsExceptionIfAlreadySet() {
+ mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
+
+ assertThrows(
+ IllegalStateException.class,
+ () -> mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier));
}
@Test
@@ -7050,6 +7068,50 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
+ @Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void setAutomaticZenRuleState_implicitRuleManualActivation_doesNotUseOverride() {
+ mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
+ PERMISSION_GRANTED); // So that canManageAZR succeeds.
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME,
+ CUSTOM_PKG_UID, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME,
+ CUSTOM_PKG_UID, ZEN_MODE_OFF);
+ ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+ assertThat(implicitRule.isActive()).isFalse();
+
+ mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id,
+ new Condition(implicitRule.conditionId, "on!", STATE_TRUE, SOURCE_USER_ACTION),
+ ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
+
+ implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+ assertThat(mZenModeHelper.getAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id))
+ .isEqualTo(STATE_TRUE);
+ assertThat(implicitRule.isActive()).isTrue();
+ assertThat(implicitRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void setAutomaticZenRuleState_implicitRuleManualDeactivation_doesNotUseOverride() {
+ mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
+ PERMISSION_GRANTED); // So that canManageAZR succeeds.
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME,
+ CUSTOM_PKG_UID, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+ assertThat(implicitRule.isActive()).isTrue();
+
+ mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id,
+ new Condition(implicitRule.conditionId, "off!", STATE_FALSE, SOURCE_USER_ACTION),
+ ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
+
+ implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+ assertThat(mZenModeHelper.getAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id))
+ .isEqualTo(STATE_FALSE);
+ assertThat(implicitRule.isActive()).isFalse();
+ assertThat(implicitRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
+ }
+
private ZenRule getZenRule(String ruleId) {
return checkNotNull(mZenModeHelper.mConfig.automaticRules.get(ruleId),
"Didn't find rule with id %s", ruleId);
@@ -7301,6 +7363,20 @@ public class ZenModeHelperTest extends UiServiceTestCase {
verify(callback, never()).onZenModeChanged();
}
+ @Test
+ @EnableFlags(FLAG_MODES_MULTIUSER)
+ public void getNotificationPolicy_fromUserWithoutZenConfig_returnsDefaultPolicy() {
+ // Set a custom policy for the current user to double check we return a default one below.
+ mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, new Policy(0, 0, 0), ORIGIN_SYSTEM,
+ SYSTEM_UID);
+
+ Policy ghostPolicy = mZenModeHelper.getNotificationPolicy(UserHandle.of(5552368));
+
+ assertThat(ghostPolicy).isNotNull();
+ assertThat(ZenAdapters.notificationPolicyToZenPolicy(ghostPolicy))
+ .isEqualTo(mZenModeHelper.getDefaultZenPolicy());
+ }
+
private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
@Nullable ZenPolicy zenPolicy) {
ZenRule rule = new ZenRule();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
index 88ed61588153..d5548a4f375e 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
@@ -16,6 +16,16 @@
package com.android.server.vibrator;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_QUICK_FALL;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_QUICK_RISE;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_SLOW_RISE;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_SPIN;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_THUD;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
@@ -29,6 +39,7 @@ import android.os.Handler;
import android.os.PersistableBundle;
import android.os.VibrationEffect;
import android.os.test.TestLooper;
+import android.os.vibrator.BasicPwleSegment;
import android.os.vibrator.Flags;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
@@ -38,7 +49,7 @@ import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationConfig;
import android.os.vibrator.VibrationEffectSegment;
import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.SparseArray;
@@ -60,6 +71,7 @@ public class DeviceAdapterTest {
private static final int PWLE_VIBRATOR_ID = 2;
private static final int PWLE_WITHOUT_FREQUENCIES_VIBRATOR_ID = 3;
private static final int PWLE_V2_VIBRATOR_ID = 4;
+ private static final int BASIC_VIBRATOR_ID = 5;
private static final float TEST_MIN_FREQUENCY = 50;
private static final float TEST_RESONANT_FREQUENCY = 150;
private static final float TEST_FREQUENCY_RESOLUTION = 25;
@@ -69,10 +81,16 @@ public class DeviceAdapterTest {
private static final int TEST_MIN_ENVELOPE_EFFECT_CONTROL_POINT_DURATION_MILLIS = 20;
private static final float[] TEST_FREQUENCIES_HZ = new float[]{30f, 50f, 100f, 120f, 150f};
private static final float[] TEST_OUTPUT_ACCELERATIONS_GS =
- new float[]{0.3f, 0.5f, 1.0f, 0.8f, 0.6f};
+ new float[]{0.0f, 3.0f, 4.0f, 2.0f, 1.0f};
+
+ private static final float[] TEST_BASIC_FREQUENCIES_HZ = new float[]{50f, 200f, 400f, 500f};
+ private static final float[] TEST_BASIC_OUTPUT_ACCELERATIONS_GS =
+ new float[]{0.05f, 0.5f, 2.0f, 1.0f};
+
private static final float PWLE_V2_MIN_FREQUENCY = TEST_FREQUENCIES_HZ[0];
private static final float PWLE_V2_MAX_FREQUENCY =
TEST_FREQUENCIES_HZ[TEST_FREQUENCIES_HZ.length - 1];
+ private static final int TEST_PRIMITIVE_DURATION = 20;
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -104,6 +122,7 @@ public class DeviceAdapterTest {
vibrators.put(PWLE_WITHOUT_FREQUENCIES_VIBRATOR_ID,
createPwleWithoutFrequenciesVibratorController(
PWLE_WITHOUT_FREQUENCIES_VIBRATOR_ID));
+ vibrators.put(BASIC_VIBRATOR_ID, createBasicVibratorController(BASIC_VIBRATOR_ID));
mAdapter = new DeviceAdapter(mVibrationSettings, vibrators);
}
@@ -118,12 +137,12 @@ public class DeviceAdapterTest {
new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.5f, 100)),
/* repeatIndex= */ -1);
- assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isEqualTo(effect);
+ assertThat(mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect)).isEqualTo(effect);
assertThat(mAdapter.adaptToVibrator(PWLE_VIBRATOR_ID, effect)).isEqualTo(effect);
}
@Test
- @RequiresFlagsEnabled(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+ @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
public void testVendorEffect_returnsOriginalSegment() {
PersistableBundle vendorData = new PersistableBundle();
vendorData.putInt("key", 1);
@@ -236,10 +255,10 @@ public class DeviceAdapterTest {
VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
new PrebakedSegment(
VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_LIGHT),
- new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10),
+ new StepSegment(1, 0, 10),
new PrebakedSegment(
VibrationEffect.EFFECT_THUD, true, VibrationEffect.EFFECT_STRENGTH_STRONG),
- new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.5f, 100)),
+ new StepSegment(1, 0, 10)),
/* repeatIndex= */ -1);
CombinedVibration expected = CombinedVibration.createParallel(effect);
@@ -262,6 +281,11 @@ public class DeviceAdapterTest {
new StepSegment(1, 175, 10),
new StepSegment(1, 0, 50)),
/* repeatIndex= */ 1))
+ .addVibrator(BASIC_VIBRATOR_ID, new VibrationEffect.Composed(Arrays.asList(
+ // Step(amplitude, frequencyHz, duration)
+ new StepSegment(1, 175, 10),
+ new StepSegment(1, 0, 50)),
+ /* repeatIndex= */ 1))
.addVibrator(PWLE_VIBRATOR_ID, new VibrationEffect.Composed(Arrays.asList(
// Ramp(startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration)
new RampSegment(0.72f, 0.72f, 175, 175, 10),
@@ -308,7 +332,7 @@ public class DeviceAdapterTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void testPwleSegment_withoutPwleV2Capability_returnsNull() {
VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.5f, 100),
@@ -318,12 +342,12 @@ public class DeviceAdapterTest {
/* repeatIndex= */ 1);
VibrationEffect.Composed adaptedEffect =
- (VibrationEffect.Composed) mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect);
+ (VibrationEffect.Composed) mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect);
assertThat(adaptedEffect).isNull();
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void testPwleSegment_withPwleV2Capability_returnsAdaptedSegments() {
VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
new PwleSegment(1, 0.2f, 30, 60, 20),
@@ -345,7 +369,7 @@ public class DeviceAdapterTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void testPwleSegment_withFrequenciesBelowSupportedRange_returnsNull() {
float frequencyBelowSupportedRange = PWLE_V2_MIN_FREQUENCY - 1f;
VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
@@ -362,7 +386,7 @@ public class DeviceAdapterTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void testPwleSegment_withFrequenciesAboveSupportedRange_returnsNull() {
float frequencyAboveSupportedRange = PWLE_V2_MAX_FREQUENCY + 1f;
VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
@@ -378,22 +402,119 @@ public class DeviceAdapterTest {
assertThat(adapter.adaptToVibrator(PWLE_V2_VIBRATOR_ID, effect)).isNull();
}
+ @Test
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void testBasicPwleSegment_withoutPwleV2Capability_returnsNull() {
+ VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+ new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.5f, 100),
+ new BasicPwleSegment(0.2f, 0.8f, 0.2f, 0.4f, 20),
+ new BasicPwleSegment(0.8f, 0.2f, 0.4f, 0.5f, 100),
+ new BasicPwleSegment(0.2f, 0.65f, 0.5f, 0.5f, 50)),
+ /* repeatIndex= */ 1);
+
+ VibrationEffect.Composed adaptedEffect =
+ (VibrationEffect.Composed) mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect);
+ assertThat(adaptedEffect).isNull();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void testBasicPwleSegment_withPwleV2Capability_returnsAdaptedSegments() {
+ VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+ new BasicPwleSegment(0.0f, 0.5f, 0.0f, 0.5f, 20),
+ new BasicPwleSegment(0.5f, 1.0f, 0.5f, 1.0f, 100),
+ new BasicPwleSegment(1.0f, 0.0f, 1.0f, 0.5f, 100)),
+ /* repeatIndex= */ 1);
+
+
+ VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList(
+ new PwleSegment(0.0f, 0.16522837f, 63.52442f, 281.7622f, 20),
+ new PwleSegment(0.16522837f, 1.0f, 281.7622f, 500f, 100),
+ new PwleSegment(1.0f, 0.0f, 500, 281.7622f, 100)),
+ /* repeatIndex= */ 1);
+
+ SparseArray<VibratorController> vibrators = new SparseArray<>();
+ vibrators.put(PWLE_V2_VIBRATOR_ID,
+ createPwleV2VibratorController(PWLE_V2_VIBRATOR_ID, TEST_BASIC_FREQUENCIES_HZ,
+ TEST_BASIC_OUTPUT_ACCELERATIONS_GS));
+ DeviceAdapter adapter = new DeviceAdapter(mVibrationSettings, vibrators);
+
+ assertThat(adapter.adaptToVibrator(PWLE_V2_VIBRATOR_ID, effect)).isEqualTo(expected);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveWithRelativeDelay_withoutFlag_returnsNull() {
+ VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_TICK, 1, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1, 100, DELAY_TYPE_RELATIVE_START_OFFSET)),
+ /* repeatIndex= */ -1);
+
+ assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isNull();
+ assertThat(mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect)).isNull();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testUnsupportedPrimitives_withFlag_returnsNull() {
+ VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_TICK, 1, 10),
+ new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1, 100)),
+ /* repeatIndex= */ -1);
+
+ assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isNull();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveWithRelativeDelay_returnsPrimitiveWithPauseDelays() {
+ int expectedPause = 50;
+ int relativeDelay = 50 + TEST_PRIMITIVE_DURATION - 1;
+ VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+ // Originally requested (overlapping):
+ // tick @ 10ms / tick @ 11ms / click @ 69ms + 20ms pause + click
+ // Actually played:
+ // 10ms pause + tick + 50ms pause + click + 20ms pause + click
+ new PrimitiveSegment(PRIMITIVE_TICK, 1, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 1, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1, relativeDelay,
+ DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.5f, 20, DELAY_TYPE_PAUSE)),
+ /* repeatIndex= */ -1);
+
+ // Delay based on primitive duration
+ VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_TICK, 1, 10, DELAY_TYPE_PAUSE),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1, expectedPause, DELAY_TYPE_PAUSE),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.5f, 20, DELAY_TYPE_PAUSE)),
+ /* repeatIndex= */ -1);
+
+ assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isNull();
+ assertThat(mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect)).isEqualTo(expected);
+ }
+
private VibratorController createEmptyVibratorController(int vibratorId) {
return new FakeVibratorControllerProvider(mTestLooper.getLooper())
.newVibratorController(vibratorId, (id, vibrationId) -> {});
}
+ private VibratorController createBasicVibratorController(int vibratorId) {
+ FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+ IVibrator.CAP_COMPOSE_EFFECTS);
+ return provider.newVibratorController(vibratorId, (id, vibrationId) -> {});
+ }
+
private VibratorController createPwleWithoutFrequenciesVibratorController(int vibratorId) {
- FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
- mTestLooper.getLooper());
- provider.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+ IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
return provider.newVibratorController(vibratorId, (id, vibrationId) -> {});
}
private VibratorController createPwleVibratorController(int vibratorId) {
- FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
- mTestLooper.getLooper());
- provider.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+ IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
provider.setResonantFrequency(TEST_RESONANT_FREQUENCY);
provider.setMinFrequency(TEST_MIN_FREQUENCY);
provider.setFrequencyResolution(TEST_FREQUENCY_RESOLUTION);
@@ -402,16 +523,32 @@ public class DeviceAdapterTest {
}
private VibratorController createPwleV2VibratorController(int vibratorId) {
- FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
- mTestLooper.getLooper());
- provider.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
+ return createPwleV2VibratorController(vibratorId, TEST_FREQUENCIES_HZ,
+ TEST_OUTPUT_ACCELERATIONS_GS);
+ }
+
+ private VibratorController createPwleV2VibratorController(int vibratorId, float[] frequencies,
+ float[] accelerations) {
+ FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+ IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
provider.setResonantFrequency(TEST_RESONANT_FREQUENCY);
- provider.setFrequenciesHz(TEST_FREQUENCIES_HZ);
- provider.setOutputAccelerationsGs(TEST_OUTPUT_ACCELERATIONS_GS);
+ provider.setFrequenciesHz(frequencies);
+ provider.setOutputAccelerationsGs(accelerations);
provider.setMaxEnvelopeEffectSize(TEST_MAX_ENVELOPE_EFFECT_SIZE);
provider.setMinEnvelopeEffectControlPointDurationMillis(
TEST_MIN_ENVELOPE_EFFECT_CONTROL_POINT_DURATION_MILLIS);
return provider.newVibratorController(vibratorId, (id, vibrationId) -> {});
}
+
+ private FakeVibratorControllerProvider createVibratorProviderWithEffects(int... capabilities) {
+ FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
+ mTestLooper.getLooper());
+ provider.setCapabilities(capabilities);
+ provider.setSupportedPrimitives(PRIMITIVE_CLICK, PRIMITIVE_TICK, PRIMITIVE_THUD,
+ PRIMITIVE_SPIN, PRIMITIVE_QUICK_RISE, PRIMITIVE_QUICK_FALL, PRIMITIVE_SLOW_RISE);
+ provider.setSupportedEffects(VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK);
+ provider.setPrimitiveDuration(TEST_PRIMITIVE_DURATION);
+ return provider;
+ }
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/PrimitiveDelayAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/PrimitiveDelayAdapterTest.java
new file mode 100644
index 000000000000..f4a6f82fba47
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/PrimitiveDelayAdapterTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2024 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.vibrator;
+
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.vibrator.IVibrator;
+import android.os.VibrationEffect;
+import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
+import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.RampSegment;
+import android.os.vibrator.StepSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class PrimitiveDelayAdapterTest {
+ private static final VibratorInfo EMPTY_VIBRATOR_INFO = new VibratorInfo.Builder(0).build();
+ private static final VibratorInfo BASIC_VIBRATOR_INFO = createVibratorInfoWithPrimitives(
+ new int[] { PRIMITIVE_CLICK, PRIMITIVE_TICK },
+ new int[] { 20, 10 });
+
+ private PrimitiveDelayAdapter mAdapter;
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Before
+ public void setUp() throws Exception {
+ mAdapter = new PrimitiveDelayAdapter();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveSegments_flagDisabled_keepsListUnchanged() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 100, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10, DELAY_TYPE_PAUSE)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
+ assertEquals(1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, 1));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testNonPrimitiveSegments_keepsListUnchanged() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+ /* startFrequencyHz= */ 100, /* endFrequencyHz= */ 1, /* duration= */ 20),
+ new PrebakedSegment(VibrationEffect.EFFECT_CLICK, false,
+ VibrationEffect.EFFECT_STRENGTH_LIGHT)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
+ assertEquals(1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, 1));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveWithPause_keepsListUnchanged() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 100, DELAY_TYPE_PAUSE),
+ new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10, DELAY_TYPE_PAUSE)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
+ assertEquals(1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, 1));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveWithRelativeDelay_afterPrimitive_usesPrimitiveStartTimeForDelay() {
+ VibratorInfo info = createVibratorInfoWithPrimitives(
+ new int[] { PRIMITIVE_CLICK }, new int[] { 20 });
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.2f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.3f, 0, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.4f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+ List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_PAUSE),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.4f, 0, DELAY_TYPE_PAUSE)));
+
+ // Repeat index is fixed after removals
+ assertEquals(-1, mAdapter.adaptToVibrator(info, segments, -1));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveWithRelativeDelay_afterRepeatIndex_usesPauseAsFirstDelay() {
+ VibratorInfo info = createVibratorInfoWithPrimitives(
+ new int[] { PRIMITIVE_CLICK }, new int[] { 20 });
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.2f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.3f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.4f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+ List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_PAUSE),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 0.3f, 10, DELAY_TYPE_PAUSE)));
+
+ // Relative offset reset after repeat index.
+ assertEquals(1, mAdapter.adaptToVibrator(info, segments, 2));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveWithRelativeDelayAfter_afterStep_usesSegmentStartTimeForDelay() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 1, /* duration= */ 10),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+ List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 1, /* duration= */ 10),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 0, DELAY_TYPE_PAUSE)));
+
+ assertEquals(-1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, -1));
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void testPrimitiveWithRelativeDelayAfter_afterUnknownDuration_usesZeroAsDuration() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new PrebakedSegment(VibrationEffect.EFFECT_POP, false,
+ VibrationEffect.EFFECT_STRENGTH_STRONG),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+ assertEquals(-1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, -1));
+
+ List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+ new PrebakedSegment(VibrationEffect.EFFECT_POP, false,
+ VibrationEffect.EFFECT_STRENGTH_STRONG),
+ new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 10, DELAY_TYPE_PAUSE)));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ private static VibratorInfo createVibratorInfoWithPrimitives(int[] ids, int[] durations) {
+ VibratorInfo.Builder builder = new VibratorInfo.Builder(0)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+
+ for (int i = 0; i < ids.length; i++) {
+ builder.setSupportedPrimitive(ids[i], durations[i]);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index 23ee893e309a..da1c1ae76d2d 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -449,6 +449,18 @@ public class VibrationSettingsTest {
}
}
+ @Test
+ public void shouldIgnoreVibration_withoutAudioManager_allowsAllVibrations() {
+ mVibrationSettings = new VibrationSettings(mContextSpy,
+ new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
+ mVibrationSettings.onSystemReady(mPackageManagerInternalMock,
+ mPowerManagerInternalMock, mActivityManagerMock, mVirtualDeviceManagerInternalMock,
+ /* audioManager= */ null);
+
+ for (int usage : ALL_USAGES) {
+ assertVibrationNotIgnoredForUsage(usage);
+ }
+ }
@Test
public void shouldIgnoreVibration_vibrateOnDisabled_ignoresUsagesNotAccessibility() {
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 093359042a3e..b4345b62c251 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -747,7 +747,8 @@ public class VibrationThreadTest {
}
@Test
- public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() {
+ @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void vibrate_singleVibratorComposedAndNoCapability_triggersHalAndReturnsUnsupported() {
VibrationEffect effect = VibrationEffect.startComposition()
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
.compose();
@@ -762,6 +763,22 @@ public class VibrationThreadTest {
}
@Test
+ @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+ public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() {
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+ .compose();
+ HalVibration vibration = startThreadAndDispatcher(effect);
+ waitForCompletion();
+
+ verify(mManagerHooks, never()).noteVibratorOn(eq(UID), anyLong());
+ verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
+ verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibration.id));
+ verifyCallbacksTriggered(vibration, Status.IGNORED_UNSUPPORTED);
+ assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibration.id).isEmpty());
+ }
+
+ @Test
public void vibrate_singleVibratorLargeComposition_splitsVibratorComposeCalls() {
FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
@@ -887,11 +904,11 @@ public class VibrationThreadTest {
fakeVibrator.setMaxEnvelopeEffectSize(10);
fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);
- VibrationEffect effect = VibrationEffect.startWaveformEnvelope()
- .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30)
+ VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
+ .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 30)
.build();
HalVibration vibration = startThreadAndDispatcher(effect);
waitForCompletion();
@@ -913,6 +930,41 @@ public class VibrationThreadTest {
@Test
@EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void vibrate_singleVibratorBasicPwle_runsComposePwleV2() {
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
+ fakeVibrator.setResonantFrequency(150);
+ fakeVibrator.setFrequenciesHz(new float[]{50f, 100f, 120f, 150f});
+ fakeVibrator.setOutputAccelerationsGs(new float[]{0.05f, 1.0f, 3.0f, 2.0f});
+ fakeVibrator.setMaxEnvelopeEffectSize(10);
+ fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);
+
+ VibrationEffect effect = new VibrationEffect.BasicEnvelopeBuilder()
+ .setInitialSharpness(/*initialSharpness=*/ 1.0f)
+ .addControlPoint(/*intensity=*/ 1.0f, /*sharpness=*/ 1.0f, /*durationMillis=*/ 20)
+ .addControlPoint(/*intensity=*/ 1.0f, /*sharpness=*/ 1.0f, /*durationMillis=*/ 100)
+ .addControlPoint(/*intensity=*/ 0.0f, /*sharpness=*/ 1.0f, /*durationMillis=*/ 100)
+ .build();
+
+ HalVibration vibration = startThreadAndDispatcher(effect);
+ waitForCompletion();
+
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(220L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
+ verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibration.id));
+ verifyCallbacksTriggered(vibration, Status.FINISHED);
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
+ assertEquals(Arrays.asList(
+ expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 150f, /*timeMillis=*/ 0),
+ expectedPwle(/*amplitude=*/ 1.0f, /*frequencyHz=*/ 150f, /*timeMillis=*/ 20),
+ expectedPwle(/*amplitude=*/ 1.0f, /*frequencyHz=*/ 150f, /*timeMillis=*/ 100),
+ expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 150f, /*timeMillis=*/ 100)
+ ), fakeVibrator.getEffectPwlePoints(vibration.id));
+
+ }
+
+ @Test
+ @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
public void vibrate_singleVibratorPwle_withInitialFrequency_runsComposePwleV2() {
FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
@@ -922,12 +974,14 @@ public class VibrationThreadTest {
fakeVibrator.setMaxEnvelopeEffectSize(10);
fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);
- VibrationEffect effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
- .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30)
- .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20)
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30)
+ VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
+ .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*durationMillis=*/ 30)
.build();
+
HalVibration vibration = startThreadAndDispatcher(effect);
waitForCompletion();
@@ -1913,6 +1967,55 @@ public class VibrationThreadTest {
fakeVibrator.getEffectSegments(vibration5.id));
}
+ @Test
+ public void vibrate_multipleVibratorsSequentialInSession_runsInOrderWithoutDelaysAndNoOffs() {
+ mockVibrators(1, 2, 3);
+ mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ mVibratorProviders.get(2).setSupportedPrimitives(
+ VibrationEffect.Composition.PRIMITIVE_CLICK);
+ mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+
+ CombinedVibration effect = CombinedVibration.startSequential()
+ .addNext(3,
+ VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
+ /* delay= */ TEST_TIMEOUT_MILLIS)
+ .addNext(1,
+ VibrationEffect.createWaveform(
+ new long[] {TEST_TIMEOUT_MILLIS, TEST_TIMEOUT_MILLIS},
+ /* repeat= */ -1),
+ /* delay= */ TEST_TIMEOUT_MILLIS)
+ .addNext(2,
+ VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1,
+ /* delay= */ TEST_TIMEOUT_MILLIS)
+ .compose(),
+ /* delay= */ TEST_TIMEOUT_MILLIS)
+ .combine();
+ HalVibration vibration = startThreadAndDispatcher(effect, /* isInSession= */ true);
+
+ // Should not timeout as delays will not affect in session playback time.
+ waitForCompletion();
+
+ // Vibrating state remains ON until session resets it.
+ verifyCallbacksTriggered(vibration, Status.FINISHED);
+ assertTrue(mControllers.get(1).isVibrating());
+ assertTrue(mControllers.get(2).isVibrating());
+ assertTrue(mControllers.get(3).isVibrating());
+
+ assertEquals(0, mVibratorProviders.get(1).getOffCount());
+ assertEquals(0, mVibratorProviders.get(2).getOffCount());
+ assertEquals(0, mVibratorProviders.get(3).getOffCount());
+ assertEquals(Arrays.asList(expectedOneShot(TEST_TIMEOUT_MILLIS)),
+ mVibratorProviders.get(1).getEffectSegments(vibration.id));
+ assertEquals(expectedAmplitudes(255), mVibratorProviders.get(1).getAmplitudes());
+ assertEquals(Arrays.asList(expectedPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_CLICK, 1, TEST_TIMEOUT_MILLIS)),
+ mVibratorProviders.get(2).getEffectSegments(vibration.id));
+ assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
+ mVibratorProviders.get(3).getEffectSegments(vibration.id));
+ }
+
private void mockVibrators(int... vibratorIds) {
for (int vibratorId : vibratorIds) {
mVibratorProviders.put(vibratorId,
@@ -1935,8 +2038,14 @@ public class VibrationThreadTest {
return startThreadAndDispatcher(createVibration(effect));
}
+ private HalVibration startThreadAndDispatcher(CombinedVibration effect, boolean isInSession) {
+ return startThreadAndDispatcher(createVibration(effect), isInSession,
+ /* requestVibrationParamsFuture= */ null);
+ }
+
private HalVibration startThreadAndDispatcher(HalVibration vib) {
- return startThreadAndDispatcher(vib, /* requestVibrationParamsFuture= */ null);
+ return startThreadAndDispatcher(vib, /* isInSession= */ false,
+ /* requestVibrationParamsFuture= */ null);
}
private HalVibration startThreadAndDispatcher(VibrationEffect effect,
@@ -1947,15 +2056,17 @@ public class VibrationThreadTest {
HalVibration vib = new HalVibration(
new CallerInfo(attrs, UID, DEVICE_ID, PACKAGE_NAME, "reason"),
CombinedVibration.createParallel(effect));
- return startThreadAndDispatcher(vib, requestVibrationParamsFuture);
+ return startThreadAndDispatcher(vib, /* isInSession= */ false,
+ requestVibrationParamsFuture);
}
- private HalVibration startThreadAndDispatcher(HalVibration vib,
+ private HalVibration startThreadAndDispatcher(HalVibration vib, boolean isInSession,
CompletableFuture<Void> requestVibrationParamsFuture) {
mControllers = createVibratorControllers();
DeviceAdapter deviceAdapter = new DeviceAdapter(mVibrationSettings, mControllers);
- mVibrationConductor = new VibrationStepConductor(vib, mVibrationSettings, deviceAdapter,
- mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture, mManagerHooks);
+ mVibrationConductor = new VibrationStepConductor(vib, isInSession, mVibrationSettings,
+ deviceAdapter, mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture,
+ mManagerHooks);
assertTrue(mThread.runVibrationOnVibrationThread(mVibrationConductor));
return mVibrationConductor.getVibration();
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 88ba9e3af6df..ec83e990a70d 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -1531,6 +1531,8 @@ public class VibratorManagerServiceTest {
FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ mVibratorProviders.get(2).setSupportedPrimitives(
+ VibrationEffect.Composition.PRIMITIVE_CLICK);
VibratorManagerService service = createSystemReadyService();
CombinedVibration effect = CombinedVibration.startParallel()
@@ -2115,7 +2117,8 @@ public class VibratorManagerServiceTest {
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
mVibratorProviders.get(1).setSupportedPrimitives(
- VibrationEffect.Composition.PRIMITIVE_CLICK);
+ VibrationEffect.Composition.PRIMITIVE_CLICK,
+ VibrationEffect.Composition.PRIMITIVE_TICK);
VibratorManagerService service = createSystemReadyService();
vibrateAndWaitUntilFinished(service,
@@ -2132,9 +2135,10 @@ public class VibratorManagerServiceTest {
assertTrue(segments.size() > 2);
// 0: Supported effect played
assertTrue(segments.get(0) instanceof PrebakedSegment);
- // 1: No segment for unsupported primitive
+ // 1: Supported primitive played
+ assertTrue(segments.get(1) instanceof PrimitiveSegment);
// 2: One or more intermediate step segments as fallback for unsupported effect
- for (int i = 1; i < segments.size() - 1; i++) {
+ for (int i = 2; i < segments.size() - 1; i++) {
assertTrue(segments.get(i) instanceof StepSegment);
}
// 3: Supported primitive played
@@ -2861,7 +2865,7 @@ public class VibratorManagerServiceTest {
mTestLooper.dispatchAll();
assertThat(session.getStatus()).isEqualTo(Status.IGNORED_UNSUPPORTED);
- verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 3}));
+ verify(mNativeWrapperMock, never()).startSession(anyLong(), any(int[].class));
verify(callback, never()).onStarted(any(IVibrationSession.class));
verify(callback, never()).onFinishing();
verify(callback)
@@ -2885,6 +2889,7 @@ public class VibratorManagerServiceTest {
verify(callback).onStarted(captor.capture());
captor.getValue().finishSession();
+ mTestLooper.dispatchAll();
// Session not ended until HAL callback.
assertThat(session.getStatus()).isEqualTo(Status.RUNNING);
@@ -3135,6 +3140,224 @@ public class VibratorManagerServiceTest {
}
@Test
+ @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+ public void vibrateInSession_afterCancel_vibrationIgnored() throws Exception {
+ mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+ mockVibrators(1, 2);
+ FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+ fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+ int sessionFinishDelayMs = 200;
+ IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+ VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+ mTestLooper.dispatchAll();
+
+ verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+ ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+ verify(callback).onStarted(captor.capture());
+
+ IVibrationSession startedSession = captor.getValue();
+ startedSession.cancelSession();
+ startedSession.vibrate(
+ CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)),
+ "reason");
+
+ // VibrationThread will never start this vibration.
+ assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service,
+ TEST_TIMEOUT_MILLIS));
+
+ // Dispatch HAL callbacks.
+ mTestLooper.moveTimeForward(sessionFinishDelayMs);
+ mTestLooper.dispatchAll();
+
+ assertThat(session.getStatus()).isEqualTo(Status.CANCELLED_BY_USER);
+ verify(callback).onFinishing();
+ verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_CANCELED));
+ }
+
+ @Test
+ @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+ public void vibrateInSession_afterFinish_vibrationIgnored() throws Exception {
+ mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+ mockVibrators(1, 2);
+ FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+ fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+ int sessionFinishDelayMs = 200;
+ IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+ VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+ mTestLooper.dispatchAll();
+
+ verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+ ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+ verify(callback).onStarted(captor.capture());
+
+ IVibrationSession startedSession = captor.getValue();
+ startedSession.finishSession();
+ mTestLooper.dispatchAll();
+
+ startedSession.vibrate(
+ CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)),
+ "reason");
+
+ // Session not ended until HAL callback.
+ assertThat(session.getStatus()).isEqualTo(Status.RUNNING);
+
+ // VibrationThread will never start this vibration.
+ assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service,
+ TEST_TIMEOUT_MILLIS));
+
+ // Dispatch HAL callbacks.
+ mTestLooper.moveTimeForward(sessionFinishDelayMs);
+ mTestLooper.dispatchAll();
+
+ assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+ verify(callback).onFinishing();
+ verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+ }
+
+ @Test
+ @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+ public void vibrateInSession_repeatingVibration_vibrationIgnored() throws Exception {
+ mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+ mockVibrators(1, 2);
+ FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+ fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+ int sessionFinishDelayMs = 200;
+ IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+ VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+ mTestLooper.dispatchAll();
+
+ verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+ ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+ verify(callback).onStarted(captor.capture());
+
+ IVibrationSession startedSession = captor.getValue();
+ startedSession.vibrate(
+ CombinedVibration.createParallel(
+ VibrationEffect.createWaveform(new long[]{ 10, 10, 10, 10}, 0)),
+ "reason");
+
+ // VibrationThread will never start this vibration.
+ assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service,
+ TEST_TIMEOUT_MILLIS));
+
+ startedSession.finishSession();
+ mTestLooper.dispatchAll();
+
+ // Dispatch HAL callbacks.
+ mTestLooper.moveTimeForward(sessionFinishDelayMs);
+ mTestLooper.dispatchAll();
+
+ assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+ assertThat(service.isVibrating(1)).isFalse();
+ assertThat(service.isVibrating(2)).isFalse();
+ verify(callback).onFinishing();
+ verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+ }
+
+ @Test
+ @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+ public void vibrateInSession_singleVibration_playsAllVibrateCommands() throws Exception {
+ mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+ mockVibrators(1, 2);
+ FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+ fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ FakeVibratorControllerProvider fakeVibrator2 = mVibratorProviders.get(1);
+ fakeVibrator2.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+ int sessionFinishDelayMs = 200;
+ IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+ VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+ mTestLooper.dispatchAll();
+
+ verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+ ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+ verify(callback).onStarted(captor.capture());
+
+ IVibrationSession startedSession = captor.getValue();
+ startedSession.vibrate(
+ CombinedVibration.createParallel(
+ VibrationEffect.createWaveform(new long[]{ 10, 10, 10, 10}, -1)),
+ "reason");
+
+ // VibrationThread will start this vibration async, so wait until vibration is triggered.
+ // Vibrators will receive 2 requests for the waveform playback
+ assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 2, service,
+ TEST_TIMEOUT_MILLIS));
+ assertTrue(waitUntil(s -> fakeVibrator2.getAmplitudes().size() == 2, service,
+ TEST_TIMEOUT_MILLIS));
+
+ startedSession.finishSession();
+ mTestLooper.dispatchAll();
+
+ // Dispatch HAL callbacks.
+ mTestLooper.moveTimeForward(sessionFinishDelayMs);
+ mTestLooper.dispatchAll();
+
+ assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+ assertThat(service.isVibrating(1)).isFalse();
+ assertThat(service.isVibrating(2)).isFalse();
+ verify(callback).onFinishing();
+ verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+ }
+
+ @Test
+ @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+ public void vibrateInSession_multipleVibrations_playsAllVibrations() throws Exception {
+ mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+ mockVibrators(1, 2);
+ FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+ fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+ int sessionFinishDelayMs = 200;
+ IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+ VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+ mTestLooper.dispatchAll();
+
+ verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+ ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+ verify(callback).onStarted(captor.capture());
+
+ IVibrationSession startedSession = captor.getValue();
+ startedSession.vibrate(
+ CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)),
+ "reason");
+
+ // VibrationThread will start this vibration async, so wait until vibration is completed.
+ assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 1, service,
+ TEST_TIMEOUT_MILLIS));
+ assertTrue(waitUntil(s -> !session.getVibrations().isEmpty(), service,
+ TEST_TIMEOUT_MILLIS));
+
+ startedSession.vibrate(
+ CombinedVibration.createParallel(VibrationEffect.createOneShot(20, 255)),
+ "reason");
+
+ assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 2, service,
+ TEST_TIMEOUT_MILLIS));
+
+ startedSession.finishSession();
+ mTestLooper.dispatchAll();
+
+ // Dispatch HAL callbacks.
+ mTestLooper.moveTimeForward(sessionFinishDelayMs);
+ mTestLooper.dispatchAll();
+
+ assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+ assertThat(service.isVibrating(1)).isFalse();
+ assertThat(service.isVibrating(2)).isFalse();
+ verify(callback).onFinishing();
+ verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+ }
+
+ @Test
public void frameworkStats_externalVibration_reportsAllMetrics() throws Exception {
mockVibrators(1);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
@@ -3277,7 +3500,8 @@ public class VibratorManagerServiceTest {
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
mVibratorProviders.get(1).setSupportedPrimitives(
- VibrationEffect.Composition.PRIMITIVE_TICK);
+ VibrationEffect.Composition.PRIMITIVE_TICK,
+ VibrationEffect.Composition.PRIMITIVE_CLICK);
VibratorManagerService service = createSystemReadyService();
vibrateAndWaitUntilFinished(service,
@@ -3320,10 +3544,12 @@ public class VibratorManagerServiceTest {
assertEquals(3, metrics.halPerformCount); // CLICK, TICK, then CLICK
assertEquals(4, metrics.halCompositionSize); // 2*TICK + 2*CLICK
// No repetitions in reported effect/primitive IDs.
- assertArrayEquals(new int[] {VibrationEffect.Composition.PRIMITIVE_TICK},
+ assertArrayEquals(
+ new int[] {
+ VibrationEffect.Composition.PRIMITIVE_CLICK,
+ VibrationEffect.Composition.PRIMITIVE_TICK,
+ },
metrics.halSupportedCompositionPrimitivesUsed);
- assertArrayEquals(new int[] {VibrationEffect.Composition.PRIMITIVE_CLICK},
- metrics.halUnsupportedCompositionPrimitivesUsed);
assertArrayEquals(new int[] {VibrationEffect.EFFECT_CLICK},
metrics.halSupportedEffectsUsed);
assertArrayEquals(new int[] {VibrationEffect.EFFECT_TICK},
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 4dc59c20c431..3f3476716831 100644
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -236,7 +236,7 @@ public final class FakeVibratorControllerProvider {
infoBuilder.setSupportedEffects(mSupportedEffects);
if (mSupportedPrimitives != null) {
for (int primitive : mSupportedPrimitives) {
- infoBuilder.setSupportedPrimitive(primitive, EFFECT_DURATION);
+ infoBuilder.setSupportedPrimitive(primitive, (int) mPrimitiveDuration);
}
}
infoBuilder.setCompositionSizeMax(mCompositionSizeMax);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index efe1af336ecd..8b861ed553ce 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -79,6 +79,7 @@ public class SoundTriggerMiddlewareLoggingLatencyTest {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG);
Identity identity = new Identity();
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 6e6b70d319ab..5f2f3ed67432 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -17,10 +17,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.wmtests">
- <!-- Uses API introduced in P (28) -->
+ <!-- Uses API introduced in S (31). Using SDK 31+ avoids Google Play Protect popups. -->
<uses-sdk
android:minSdkVersion="1"
- android:targetSdkVersion="28" />
+ android:targetSdkVersion="31" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
diff --git a/services/tests/wmtests/res/xml/bookmarks.xml b/services/tests/wmtests/res/xml/bookmarks.xml
index 197b36623fff..787f4e85c012 100644
--- a/services/tests/wmtests/res/xml/bookmarks.xml
+++ b/services/tests/wmtests/res/xml/bookmarks.xml
@@ -13,60 +13,70 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<bookmarks>
+<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<!-- the key combinations for the following shortcuts must be in sync
with the key combinations sent by the test in ModifierShortcutTests.java -->
<bookmark
role="android.app.role.BROWSER"
- shortcut="b" />
+ androidprv:keycode="KEYCODE_B"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CONTACTS"
- shortcut="c" />
+ androidprv:keycode="KEYCODE_C"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_EMAIL"
- shortcut="e" />
+ androidprv:keycode="KEYCODE_E"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CALENDAR"
- shortcut="k" />
+ androidprv:keycode="KEYCODE_K"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_MAPS"
- shortcut="m" />
+ androidprv:keycode="KEYCODE_M"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_MUSIC"
- shortcut="p" />
+ androidprv:keycode="KEYCODE_P"
+ androidprv:modifierState="META" />
<bookmark
role="android.app.role.SMS"
- shortcut="s" />
+ androidprv:keycode="KEYCODE_S"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CALCULATOR"
- shortcut="u" />
+ androidprv:keycode="KEYCODE_U"
+ androidprv:modifierState="META" />
<bookmark
role="android.app.role.BROWSER"
- shortcut="b"
- shift="true" />
+ androidprv:keycode="KEYCODE_B"
+ androidprv:modifierState="META|SHIFT" />
<bookmark
category="android.intent.category.APP_CONTACTS"
- shortcut="c"
- shift="true" />
+ androidprv:keycode="KEYCODE_C"
+ androidprv:modifierState="META|SHIFT" />
<bookmark
package="com.test"
class="com.test.BookmarkTest"
- shortcut="j"
- shift="true" />
+ androidprv:keycode="KEYCODE_J"
+ androidprv:modifierState="META|SHIFT" />
<!-- The following shortcuts will not be invoked by tests but are here to
provide test coverage of parsing the different types of shortcut. -->
<bookmark
package="com.test"
class="com.test.BookmarkTest"
- shortcut="j" />
+ androidprv:keycode="KEYCODE_J"
+ androidprv:modifierState="META" />
<bookmark
package="com.test2"
class="com.test.BookmarkTest"
- shortcut="d" />
+ androidprv:keycode="KEYCODE_D"
+ androidprv:modifierState="META" />
<!-- It's intended that this package/class will NOT resolve so we test the resolution
@@ -74,6 +84,7 @@
<bookmark
package="com.test3"
class="com.test.BookmarkTest"
- shortcut="f" />
+ androidprv:keycode="KEYCODE_F"
+ androidprv:modifierState="META" />
</bookmarks>
diff --git a/services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java b/services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java
index 6f9c8904ca32..038e1357159b 100644
--- a/services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
*/
@MediumTest
@RunWith(AndroidJUnit4.class)
-@DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER_MULTI_PRESS_GESTURES)
+@DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER_MULTI_KEY_GESTURES)
public class CombinationKeyTests extends ShortcutKeyTestBase {
private static final long A11Y_KEY_HOLD_MILLIS = 3500;
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
index 0575d98b65ec..82a5add407f4 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
@@ -116,6 +116,7 @@ public class ModifierShortcutManagerTests {
mModifierShortcutManager = new ModifierShortcutManager(
mContext, mHandler, UserHandle.SYSTEM);
+ mModifierShortcutManager.onSystemReady();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index a51ce9951ab4..bc03c233b459 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -88,6 +88,7 @@ import android.service.dreams.DreamManagerInternal;
import android.telecom.TelecomManager;
import android.view.Display;
import android.view.InputEvent;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillManagerInternal;
@@ -270,11 +271,15 @@ class TestPhoneWindowManager {
// Return mocked services: LocalServices.getService
mMockitoSession = mockitoSession()
.mockStatic(LocalServices.class, spyStubOnly)
+ .mockStatic(KeyCharacterMap.class)
.strictness(Strictness.LENIENT)
.startMocking();
mPhoneWindowManager = spy(new PhoneWindowManager());
+ KeyCharacterMap virtualKcm = mContext.getSystemService(InputManager.class)
+ .getInputDevice(KeyCharacterMap.VIRTUAL_KEYBOARD).getKeyCharacterMap();
+ doReturn(virtualKcm).when(() -> KeyCharacterMap.load(anyInt()));
doReturn(mWindowManagerInternal).when(
() -> LocalServices.getService(eq(WindowManagerInternal.class)));
doReturn(mActivityManagerInternal).when(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 7f260f85a755..70f57eb40385 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -357,6 +357,25 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
assertEquals(activity1.app, mAtm.mTopApp);
}
+ @Test
+ public void testTopResumedActivity_deferResume() {
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ activity2.setState(ActivityRecord.State.RESUMED, "test");
+ assertEquals(activity2.app, mAtm.mTopApp);
+ reset(activity2);
+
+ // Verify that no top-resumed activity changes to the client while defer-resume enabled.
+ mSupervisor.beginDeferResume();
+ activity1.getTask().moveToFront("test");
+ activity1.setState(ActivityRecord.State.RESUMED, "test");
+ verify(activity2, never()).scheduleTopResumedActivityChanged(eq(false));
+
+ // Verify that the change is scheduled to the client after defer-resumed disabled
+ mSupervisor.endDeferResume();
+ verify(activity2).scheduleTopResumedActivityChanged(eq(false));
+ }
+
/**
* We need to launch home again after user unlocked for those displays that do not have
* encryption aware home app.
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
index b91a5b7afe26..d5ed048032e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
@@ -17,8 +17,8 @@
package com.android.server.wm;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -228,9 +228,8 @@ public class AppCompatCameraOverridesTest extends WindowTestsBase {
}
@Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
- public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+ public void testShouldApplyCameraCompatFreeformTreatment_notEnabledByOverride_returnsFalse() {
runTestScenario((robot) -> {
robot.activity().createActivityWithComponentInNewTask();
@@ -239,19 +238,9 @@ public class AppCompatCameraOverridesTest extends WindowTestsBase {
}
@Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
- public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse() {
- runTestScenario((robot) -> {
- robot.activity().createActivityWithComponentInNewTask();
-
- robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
- });
- }
-
- @Test
- @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
- public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue() {
+ public void testShouldApplyCameraCompatFreeformTreatment_overrideAndFlagEnabled_returnsTrue() {
runTestScenario((robot) -> {
robot.activity().createActivityWithComponentInNewTask();
@@ -261,8 +250,9 @@ public class AppCompatCameraOverridesTest extends WindowTestsBase {
@Test
@EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA,
- OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void testShouldRecomputeConfigurationForCameraCompat() {
+ OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA,
+ OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
+ public void testShouldRecomputeConfigurationForFreeformTreatment() {
runTestScenario((robot) -> {
robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
robot.applyOnActivity((a) -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index d6be9159694b..40da9ea2d718 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -66,6 +66,7 @@ import android.view.WindowManager;
import android.window.BackAnimationAdapter;
import android.window.BackMotionEvent;
import android.window.BackNavigationInfo;
+import android.window.IBackAnimationHandoffHandler;
import android.window.IOnBackInvokedCallback;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedCallbackInfo;
@@ -780,6 +781,10 @@ public class BackNavigationControllerTests extends WindowTestsBase {
@Override
public void setTriggerBack(boolean triggerBack) {
}
+
+ @Override
+ public void setHandoffHandler(IBackAnimationHandoffHandler unused) {
+ }
};
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
index ade591d006f5..da010ae3c96a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
@@ -333,7 +333,8 @@ public class BackgroundActivityStartControllerExemptionTests {
int realCallingPid = REGULAR_PID_2;
// setup state
- mActiveUids.onNonAppSurfaceVisibilityChanged(callingUid, true);
+ mActiveUids.onNonAppSurfaceVisibilityChanged(callingUid,
+ WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY, true);
when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);
// prepare call
@@ -367,7 +368,8 @@ public class BackgroundActivityStartControllerExemptionTests {
int realCallingPid = REGULAR_PID_2;
// setup state
- mActiveUids.onNonAppSurfaceVisibilityChanged(realCallingUid, true);
+ mActiveUids.onNonAppSurfaceVisibilityChanged(realCallingUid,
+ WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY, true);
when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);
// prepare call
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index e447565a55bd..c427583d3001 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -25,7 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
@@ -96,61 +96,55 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
private static final String TEST_PACKAGE_1 = "com.android.frameworks.wmtests";
private static final String TEST_PACKAGE_2 = "com.test.package.two";
private static final String CAMERA_ID_1 = "camera-1";
- private static final String CAMERA_ID_2 = "camera-2";
- private CameraManager mMockCameraManager;
- private Handler mMockHandler;
private AppCompatConfiguration mAppCompatConfiguration;
private CameraManager.AvailabilityCallback mCameraAvailabilityCallback;
private CameraCompatFreeformPolicy mCameraCompatFreeformPolicy;
private ActivityRecord mActivity;
- private Task mTask;
private ActivityRefresher mActivityRefresher;
@Before
public void setUp() throws Exception {
mAppCompatConfiguration = mDisplayContent.mWmService.mAppCompatConfiguration;
spyOn(mAppCompatConfiguration);
- when(mAppCompatConfiguration.isCameraCompatTreatmentEnabled())
- .thenReturn(true);
- when(mAppCompatConfiguration.isCameraCompatRefreshEnabled())
- .thenReturn(true);
+ when(mAppCompatConfiguration.isCameraCompatTreatmentEnabled()).thenReturn(true);
+ when(mAppCompatConfiguration.isCameraCompatRefreshEnabled()).thenReturn(true);
when(mAppCompatConfiguration.isCameraCompatRefreshCycleThroughStopEnabled())
.thenReturn(true);
- mMockCameraManager = mock(CameraManager.class);
+ final CameraManager mockCameraManager = mock(CameraManager.class);
doAnswer(invocation -> {
mCameraAvailabilityCallback = invocation.getArgument(1);
return null;
- }).when(mMockCameraManager).registerAvailabilityCallback(
+ }).when(mockCameraManager).registerAvailabilityCallback(
any(Executor.class), any(CameraManager.AvailabilityCallback.class));
- when(mContext.getSystemService(CameraManager.class)).thenReturn(mMockCameraManager);
+ when(mContext.getSystemService(CameraManager.class)).thenReturn(mockCameraManager);
mDisplayContent.setIgnoreOrientationRequest(true);
- mMockHandler = mock(Handler.class);
+ final Handler mockHandler = mock(Handler.class);
- when(mMockHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
+ when(mockHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
});
- mActivityRefresher = new ActivityRefresher(mDisplayContent.mWmService, mMockHandler);
- CameraStateMonitor cameraStateMonitor =
- new CameraStateMonitor(mDisplayContent, mMockHandler);
- mCameraCompatFreeformPolicy =
- new CameraCompatFreeformPolicy(mDisplayContent, cameraStateMonitor,
- mActivityRefresher);
+ mActivityRefresher = new ActivityRefresher(mDisplayContent.mWmService, mockHandler);
+ final CameraStateMonitor cameraStateMonitor = new CameraStateMonitor(mDisplayContent,
+ mockHandler);
+ mCameraCompatFreeformPolicy = new CameraCompatFreeformPolicy(mDisplayContent,
+ cameraStateMonitor, mActivityRefresher);
setDisplayRotation(Surface.ROTATION_90);
mCameraCompatFreeformPolicy.start();
cameraStateMonitor.startListeningToCameraState();
}
- @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testFullscreen_doesNotActivateCameraCompatMode() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT, WINDOWING_MODE_FULLSCREEN);
doReturn(false).when(mActivity).inFreeformWindowingMode();
@@ -160,23 +154,26 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
assertNotInCameraCompatMode();
}
- @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testOrientationUnspecified_doesNotActivateCameraCompatMode() {
configureActivity(SCREEN_ORIENTATION_UNSPECIFIED);
assertNotInCameraCompatMode();
}
- @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testNoCameraConnection_doesNotActivateCameraCompatMode() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
assertNotInCameraCompatMode();
}
- @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testCameraConnected_deviceInPortrait_portraitCameraCompatMode() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
setDisplayRotation(Surface.ROTATION_0);
@@ -187,6 +184,8 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testCameraConnected_deviceInLandscape_portraitCameraCompatMode() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
setDisplayRotation(Surface.ROTATION_270);
@@ -197,6 +196,8 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testCameraConnected_deviceInPortrait_landscapeCameraCompatMode() throws Exception {
configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
setDisplayRotation(Surface.ROTATION_0);
@@ -207,6 +208,8 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testCameraConnected_deviceInLandscape_landscapeCameraCompatMode() throws Exception {
configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
setDisplayRotation(Surface.ROTATION_270);
@@ -216,8 +219,9 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
assertActivityRefreshRequested(/* refreshRequested */ false);
}
- @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testCameraReconnected_cameraCompatModeAndRefresh() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
setDisplayRotation(Surface.ROTATION_270);
@@ -236,6 +240,8 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testCameraOpenedForDifferentPackage_notInCameraCompatMode() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -246,27 +252,32 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
- public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+ public void testShouldApplyCameraCompatFreeformTreatment_overrideNotEnabled_returnsFalse() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.info
- .isChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT));
- assertFalse(mCameraCompatFreeformPolicy.isCameraCompatForFreeformEnabledForActivity(
- mActivity));
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertFalse(mCameraCompatFreeformPolicy.isTreatmentEnabledForActivity(mActivity,
+ /* checkOrientation */ true));
}
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
- public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue() {
+ @EnableCompatChanges(OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT)
+ public void testShouldApplyCameraCompatFreeformTreatment_enabledByOverride_returnsTrue() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mCameraCompatFreeformPolicy.isCameraCompatForFreeformEnabledForActivity(
- mActivity));
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertTrue(mActivity.info
+ .isChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT));
+ assertTrue(mCameraCompatFreeformPolicy.isTreatmentEnabledForActivity(mActivity,
+ /* checkOrientation */ true));
}
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testShouldRefreshActivity_appBoundsChanged_returnsTrue() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
Configuration oldConfiguration = createConfiguration(/* letterbox= */ false);
@@ -279,6 +290,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testShouldRefreshActivity_displayRotationChanged_returnsTrue() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
@@ -294,6 +306,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testShouldRefreshActivity_appBoundsNorDisplayChanged_returnsFalse() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
@@ -309,6 +322,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testOnActivityConfigurationChanging_refreshDisabledViaFlag_noRefresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -324,6 +338,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testOnActivityConfigurationChanging_cycleThroughStopDisabled() throws Exception {
when(mAppCompatConfiguration.isCameraCompatRefreshCycleThroughStopEnabled())
.thenReturn(false);
@@ -338,6 +353,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -352,6 +368,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testGetCameraCompatAspectRatio_activityNotInCameraCompat_returnsDefaultAspRatio() {
configureActivity(SCREEN_ORIENTATION_FULL_USER);
@@ -365,6 +382,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testGetCameraCompatAspectRatio_activityInCameraCompat_returnsConfigAspectRatio() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
final float configAspectRatio = 1.5f;
@@ -380,6 +398,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
public void testGetCameraCompatAspectRatio_inCameraCompatPerAppOverride_returnDefAspectRatio() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
final float configAspectRatio = 1.5f;
@@ -406,7 +425,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
private void configureActivityAndDisplay(@ScreenOrientation int activityOrientation,
@Orientation int naturalOrientation, @WindowingMode int windowingMode) {
- mTask = new TaskBuilder(mSupervisor)
+ final Task task = new TaskBuilder(mSupervisor)
.setDisplay(mDisplayContent)
.setWindowingMode(windowingMode)
.build();
@@ -416,7 +435,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
.setComponent(ComponentName.createRelative(mContext,
com.android.server.wm.CameraCompatFreeformPolicyTests.class.getName()))
.setScreenOrientation(activityOrientation)
- .setTask(mTask)
+ .setTask(task)
.build();
spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
@@ -429,13 +448,11 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
}
private void assertInCameraCompatMode(@CameraCompatTaskInfo.FreeformCameraCompatMode int mode) {
- assertEquals(mode, mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .getFreeformCameraCompatMode());
+ assertEquals(mode, mCameraCompatFreeformPolicy.getCameraCompatMode(mActivity));
}
private void assertNotInCameraCompatMode() {
- assertEquals(CAMERA_COMPAT_FREEFORM_NONE, mActivity.mAppCompatController
- .getAppCompatCameraOverrides().getFreeformCameraCompatMode());
+ assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_NONE);
}
private void assertActivityRefreshRequested(boolean refreshRequested) throws Exception {
@@ -471,7 +488,8 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
private Configuration createConfiguration(boolean letterbox) {
final Configuration configuration = new Configuration();
- Rect bounds = letterbox ? new Rect(300, 0, 700, 600) : new Rect(0, 0, 1000, 600);
+ Rect bounds = letterbox ? new Rect(/*left*/ 300, /*top*/ 0, /*right*/ 700, /*bottom*/ 600)
+ : new Rect(/*left*/ 0, /*top*/ 0, /*right*/ 1000, /*bottom*/ 600);
configuration.windowConfiguration.setAppBounds(bounds);
return configuration;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index c51261f40ed5..76b994d013f3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -49,6 +49,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.ContentRecordingSession;
@@ -213,7 +214,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
- verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+ verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR);
}
@Test
@@ -225,7 +226,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mContentRecorder.setContentRecordingSession(invalidTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
- verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+ verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR);
}
@Test
@@ -310,8 +311,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mVirtualDisplayContent.getConfiguration().orientation, WINDOWING_MODE_FULLSCREEN);
// No resize is issued, only the initial transformations when we started recording.
- verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(),
- anyFloat());
+ verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat());
verify(mTransaction).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
anyFloat(), anyFloat());
}
@@ -386,19 +386,18 @@ public class ContentRecorderTests extends WindowTestsBase {
// WHEN a configuration change arrives, and the recorded content is a different size.
Configuration configuration = mTask.getConfiguration();
- configuration.windowConfiguration.setBounds(new Rect(0, 0, recordedWidth, recordedHeight));
- configuration.windowConfiguration.setAppBounds(
- new Rect(0, 0, recordedWidth, recordedHeight));
+ Rect newBounds = new Rect(0, 0, recordedWidth, recordedHeight);
+ configuration.windowConfiguration.setBounds(newBounds);
+ configuration.windowConfiguration.setAppBounds(newBounds);
mTask.onConfigurationChanged(configuration);
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// THEN content in the captured DisplayArea is scaled to fit the surface size.
- verify(mTransaction, atLeastOnce()).setMatrix(eq(mRecordedSurface), anyFloat(), eq(0f),
- eq(0f),
- anyFloat());
+ verify(mTransaction, atLeastOnce()).setMatrix(
+ eq(mRecordedSurface), anyFloat(), eq(0f), eq(0f), anyFloat());
// THEN the resize callback is notified.
- verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized(
- recordedWidth, recordedHeight);
+ verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged(
+ mTaskSession.getContentToRecord(), mTaskSession.getTargetUid(), newBounds);
}
@Test
@@ -649,7 +648,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mTask.removeImmediately();
- verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+ verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_TARGET_REMOVED);
}
@Test
@@ -684,8 +683,8 @@ public class ContentRecorderTests extends WindowTestsBase {
int xInset = (mSurfaceSize.x - scaledWidth) / 2;
verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
// THEN the resize callback is notified.
- verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized(
- displayAreaBounds.width(), displayAreaBounds.height());
+ verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged(
+ mDisplaySession.getContentToRecord(), mDisplaySession.getTargetUid(), displayAreaBounds);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java b/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
index c9c31dfe5307..a0f4ae77452c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
@@ -239,6 +239,9 @@ public class DeferredDisplayUpdaterDiffTest {
} else if (type.equals(FrameRateCategoryRate.class)) {
field.set(first, new FrameRateCategoryRate(16666667, 11111111));
field.set(second, new FrameRateCategoryRate(11111111, 8333333));
+ } else if (type.isArray() && type.getComponentType().equals(float.class)) {
+ field.set(first, new float[]{60.0f});
+ field.set(second, new float[]{120.0f});
} else {
throw new IllegalArgumentException("Field " + field
+ " is not supported by this test, please add implementation of setting "
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
index c8fc4822259e..63973345b5fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
@@ -20,16 +20,19 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
@@ -54,6 +57,7 @@ public class DisplayRotationImmersiveAppCompatPolicyTests extends WindowTestsBas
private DisplayRotationImmersiveAppCompatPolicy mPolicy;
+ private DisplayRotation mMockDisplayRotation;
private AppCompatConfiguration mMockAppCompatConfiguration;
private ActivityRecord mMockActivityRecord;
private Task mMockTask;
@@ -98,6 +102,7 @@ public class DisplayRotationImmersiveAppCompatPolicyTests extends WindowTestsBas
when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_90)).thenReturn(true);
when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_180)).thenReturn(false);
when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_270)).thenReturn(true);
+ mMockDisplayRotation = mockDisplayRotation;
return mockDisplayRotation;
}
@@ -196,6 +201,24 @@ public class DisplayRotationImmersiveAppCompatPolicyTests extends WindowTestsBas
}
@Test
+ public void testDeferOrientationUpdate() {
+ assertFalse(mPolicy.deferOrientationUpdate());
+
+ doReturn(SCREEN_ORIENTATION_UNSPECIFIED).when(mMockDisplayRotation).getLastOrientation();
+ final WindowOrientationListener orientationListener = mock(WindowOrientationListener.class);
+ doReturn(Surface.ROTATION_90).when(orientationListener).getProposedRotation();
+ doReturn(orientationListener).when(mMockDisplayRotation).getOrientationListener();
+ spyOn(mDisplayContent.mTransitionController);
+ doReturn(true).when(mDisplayContent.mTransitionController)
+ .hasTransientLaunch(mDisplayContent);
+
+ assertTrue(mPolicy.deferOrientationUpdate());
+ mDisplayContent.mTransitionController.mStateValidators.getFirst().run();
+
+ verify(mWm).updateRotation(false, false);
+ }
+
+ @Test
public void testRotationChoiceEnforcedOnly_nullTopRunningActivity_lockNotEnforced() {
when(mDisplayContent.topRunningActivity()).thenReturn(null);
diff --git a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
index a0c5b54603f9..c016c5ead23c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
@@ -69,7 +69,9 @@ public class FrameRateSelectionPriorityTests extends WindowTestsBase {
private static final FrameRateVote FRAME_RATE_VOTE_60_PREFERRED =
new FrameRateVote(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT,
SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN);
-
+ private static final float HI_REFRESH_RATE = 90;
+ private static final float MID_REFRESH_RATE = 70;
+ private static final float LOW_REFRESH_RATE = 60;
WindowState createWindow(String name) {
WindowState window = createWindow(null, TYPE_APPLICATION, name);
when(window.mWmService.mDisplayManagerInternal.getRefreshRateSwitchingType())
@@ -82,14 +84,16 @@ public class FrameRateSelectionPriorityTests extends WindowTestsBase {
DisplayInfo di = new DisplayInfo(mDisplayInfo);
Mode defaultMode = di.getDefaultMode();
Mode hiMode = new Mode(1,
- defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 90);
+ defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), HI_REFRESH_RATE);
Mode midMode = new Mode(2,
- defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 70);
+ defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), MID_REFRESH_RATE);
Mode lowMode = new Mode(LOW_MODE_ID,
- defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 60);
+ defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), LOW_REFRESH_RATE);
di.supportedModes = new Mode[] { hiMode, midMode };
di.appsSupportedModes = new Mode[] { hiMode, midMode, lowMode };
+ di.supportedRefreshRates = new float[] {HI_REFRESH_RATE, MID_REFRESH_RATE,
+ LOW_REFRESH_RATE};
di.defaultModeId = 1;
mRefreshRatePolicy = new RefreshRatePolicy(mWm, di, mDenylist);
when(mDisplayPolicy.getRefreshRatePolicy()).thenReturn(mRefreshRatePolicy);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index df17cd1d24b7..aa992504f9a5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -434,6 +434,7 @@ public class RecentTasksTest extends WindowTestsBase {
@Test
public void testAddTaskCompatibleWindowingMode_withFreeformAndFullscreen_expectRemove() {
Task task1 = createTaskBuilder(".Task1")
+ .setTaskId(1)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.build();
doReturn(WINDOWING_MODE_FREEFORM).when(task1).getWindowingMode();
@@ -452,6 +453,10 @@ public class RecentTasksTest extends WindowTestsBase {
assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
assertThat(mCallbacksRecorder.mRemoved).hasSize(1);
assertThat(mCallbacksRecorder.mRemoved).contains(task1);
+
+ TaskChangeNotificationController controller =
+ mAtm.getTaskChangeNotificationController();
+ verify(controller, times(1)).notifyRecentTaskRemovedForAddTask(task1.mTaskId);
}
@Test
@@ -496,24 +501,6 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
- public void testAppendOrganizedChildTaskInfo() {
- final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build();
- root.mCreatedByOrganizer = true;
- // Add organized and non-organized child.
- final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build();
- final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build();
- doReturn(true).when(child1).isOrganized();
- doReturn(false).when(child2).isOrganized();
- mRecentTasks.add(root);
-
- // Make sure only organized child will be appended.
- final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
- final List<RecentTaskInfo> childrenTaskInfos = infos.get(0).childrenTaskInfos;
- assertEquals(childrenTaskInfos.size(), 1);
- assertEquals(childrenTaskInfos.get(0).taskId, child1.mTaskId);
- }
-
- @Test
public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
// There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
// FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
@@ -1420,46 +1407,6 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
- public void testLastSnapshotData_snapshotSaved() {
- final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), new Point(80, 80));
- final Task task1 = createTaskBuilder(".Task").build();
- task1.onSnapshotChanged(snapshot);
-
- mRecentTasks.add(task1);
- final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
- final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
- infos.get(0).lastSnapshotData;
- assertTrue(lastSnapshotData.taskSize.equals(100, 100));
- assertTrue(lastSnapshotData.bufferSize.equals(80, 80));
- }
-
- @Test
- public void testLastSnapshotData_noBuffer() {
- final Task task1 = createTaskBuilder(".Task").build();
- final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), null);
- task1.onSnapshotChanged(snapshot);
-
- mRecentTasks.add(task1);
- final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
- final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
- infos.get(0).lastSnapshotData;
- assertTrue(lastSnapshotData.taskSize.equals(100, 100));
- assertNull(lastSnapshotData.bufferSize);
- }
-
- @Test
- public void testLastSnapshotData_notSet() {
- final Task task1 = createTaskBuilder(".Task").build();
-
- mRecentTasks.add(task1);
- final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
- final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
- infos.get(0).lastSnapshotData;
- assertNull(lastSnapshotData.taskSize);
- assertNull(lastSnapshotData.bufferSize);
- }
-
- @Test
public void testCreateRecentTaskInfo_detachedTask() {
final Task task = createTaskBuilder(".Task").build();
final ComponentName componentName = getUniqueComponentName();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index 3d08ca2905f3..73e5f58fa7e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -101,6 +101,8 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), LOW_REFRESH_RATE);
mDisplayInfo.supportedModes = new Mode[] { hiMode, midMode };
mDisplayInfo.appsSupportedModes = new Mode[] { hiMode, midMode, lowMode };
+ mDisplayInfo.supportedRefreshRates = new float[] {HI_REFRESH_RATE, MID_REFRESH_RATE,
+ LOW_REFRESH_RATE};
mDisplayInfo.defaultModeId = HI_MODE_ID;
mPolicy = new RefreshRatePolicy(mWm, mDisplayInfo, mDenylist);
}
@@ -270,6 +272,46 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
}
@Test
+ public void testInsetsAnimationAppOverridePreferredModeId() {
+ final WindowState overrideWindow = createWindow("overrideWindow");
+ overrideWindow.mAttrs.packageName = "com.android.test";
+ overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
+ parcelLayoutParams(overrideWindow);
+ assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_LOW_EXACT, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+
+ overrideWindow.notifyInsetsAnimationRunningStateChanged(true);
+ assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_NONE, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testInsetsAnimationAppOverridePreferredRefreshRate() {
+ final WindowState overrideWindow = createWindow("overrideWindow");
+ overrideWindow.mAttrs.packageName = "com.android.test";
+ overrideWindow.mAttrs.preferredRefreshRate = LOW_REFRESH_RATE;
+ parcelLayoutParams(overrideWindow);
+ assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_LOW_PREFERRED, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+
+ overrideWindow.notifyInsetsAnimationRunningStateChanged(true);
+ assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_NONE, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
public void testAnimatingCamera() {
final WindowState cameraUsingWindow = createWindow("cameraUsingWindow");
cameraUsingWindow.mAttrs.packageName = "com.android.test";
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 791b5b59535a..a92fe3afbd78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -162,6 +162,10 @@ public class SafeActivityOptionsTest {
verifySecureExceptionThrown(activityOptions, taskSupervisor);
activityOptions = ActivityOptions.makeBasic();
+ activityOptions.setTaskAlwaysOnTop(true);
+ verifySecureExceptionThrown(activityOptions, taskSupervisor);
+
+ activityOptions = ActivityOptions.makeBasic();
activityOptions.setLaunchDisplayId(DEFAULT_DISPLAY);
verifySecureExceptionThrown(activityOptions, taskSupervisor);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 41f1e2359c88..4fbe492ea7fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -4863,7 +4863,7 @@ public class SizeCompatTests extends WindowTestsBase {
@Test
@EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
- public void testCameraCompatAspectRatio_defualtAspectRatioAppliedWhenGreater() {
+ public void testCameraCompatAspectRatio_defaultAspectRatioAppliedWhenGreater() {
// Needed to create camera compat policy in DisplayContent.
allowDesktopMode();
// Create display that has all stable insets and does not rotate.
@@ -4928,6 +4928,7 @@ public class SizeCompatTests extends WindowTestsBase {
spyOn(pm);
final PackageManager.Property property = new PackageManager.Property("propertyName",
true /* value */, name.getPackageName(), name.getClassName());
+ // Activity level.
try {
doReturn(property).when(pm).getPropertyAsUser(
WindowManager.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
@@ -4938,6 +4939,19 @@ public class SizeCompatTests extends WindowTestsBase {
final ActivityRecord optOutActivity = new ActivityBuilder(mAtm)
.setComponent(name).setTask(mTask).build();
assertFalse(optOutActivity.isUniversalResizeable());
+
+ // Application level.
+ try {
+ doReturn(property).when(pm).getProperty(
+ WindowManager.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
+ name.getPackageName());
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ final ActivityRecord optOutAppActivity = new ActivityBuilder(mAtm)
+ .setComponent(getUniqueComponentName(mContext.getPackageName()))
+ .setTask(mTask).build();
+ assertFalse(optOutAppActivity.isUniversalResizeable());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 42e31de295d6..410fa2879600 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -84,6 +84,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import android.util.ArrayMap;
import android.util.Rational;
import android.view.Display;
@@ -122,6 +123,8 @@ import java.util.function.BiConsumer;
* Build/Install/Run:
* atest WmTests:WindowOrganizerTests
*/
+
+// TODO revert parts of this set to set the flag to test the behavior
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
@@ -541,6 +544,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Test
+ @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
public void testSetActivityWindowingMode() {
final ActivityRecord record = makePipableActivity();
final Task rootTask = record.getRootTask();
@@ -1299,6 +1303,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Test
+ @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
public void testEnterPipParams() {
final StubOrganizer o = new StubOrganizer();
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
@@ -1314,6 +1319,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Test
+ @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
public void testChangePipParams() {
class ChangeSavingOrganizer extends StubOrganizer {
RunningTaskInfo mChangedInfo;
@@ -1885,6 +1891,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@SuppressWarnings("GuardedBy")
@Test
+ @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
public void testResumeTopsWhenLeavingPinned() {
final ActivityRecord home = new ActivityBuilder(mAtm).setTask(
mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask()).build();
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 1750a14e0561..50e0e181cd68 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -71,6 +71,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -84,12 +85,14 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
+import android.content.ContentResolver;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Build;
import android.os.IBinder;
import android.os.InputConfig;
import android.os.RemoteException;
@@ -97,6 +100,7 @@ import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.MergedConfiguration;
import android.view.Gravity;
@@ -353,6 +357,29 @@ public class WindowStateTests extends WindowTestsBase {
}
@Test
+ public void testDestroySurface() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+ win.mHasSurface = win.mAnimatingExit = true;
+ win.mWinAnimator.mSurfaceControl = mock(SurfaceControl.class);
+ win.onExitAnimationDone();
+
+ assertFalse("Case 1 destroySurface no-op",
+ win.destroySurface(false /* cleanupOnResume */, false /* appStopped */));
+ assertTrue(win.mHasSurface);
+ assertTrue(win.mDestroying);
+
+ assertFalse("Case 2 destroySurface no-op",
+ win.destroySurface(true /* cleanupOnResume */, false /* appStopped */));
+ assertTrue(win.mHasSurface);
+ assertTrue(win.mDestroying);
+
+ assertTrue("Case 3 destroySurface destroys surface",
+ win.destroySurface(false /* cleanupOnResume */, true /* appStopped */));
+ assertFalse(win.mDestroying);
+ assertFalse(win.mHasSurface);
+ }
+
+ @Test
public void testPrepareWindowToDisplayDuringRelayout() {
// Call prepareWindowToDisplayDuringRelayout for a window without FLAG_TURN_SCREEN_ON before
// calling setCurrentLaunchCanTurnScreenOn for windows with flag in the same activity.
@@ -1534,6 +1561,57 @@ public class WindowStateTests extends WindowTestsBase {
}
@Test
+ public void testIsSecureLocked_flagSecureSet() {
+ WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
+ 1 /* ownerId */);
+ window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+
+ assertTrue(window.isSecureLocked());
+ }
+
+ @Test
+ public void testIsSecureLocked_flagSecureNotSet() {
+ WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
+ 1 /* ownerId */);
+
+ assertFalse(window.isSecureLocked());
+ }
+
+ @Test
+ public void testIsSecureLocked_disableSecureWindows() {
+ assumeTrue(Build.IS_DEBUGGABLE);
+
+ WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
+ 1 /* ownerId */);
+ window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+ ContentResolver cr = useFakeSettingsProvider();
+
+ // isSecureLocked should return false when DISABLE_SECURE_WINDOWS is set to 1
+ Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1");
+ mWm.mSettingsObserver.onChange(false /* selfChange */,
+ Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+ assertFalse(window.isSecureLocked());
+
+ // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is set to 0.
+ Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "0");
+ mWm.mSettingsObserver.onChange(false /* selfChange */,
+ Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+ assertTrue(window.isSecureLocked());
+
+ // Disable secure windows again.
+ Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1");
+ mWm.mSettingsObserver.onChange(false /* selfChange */,
+ Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+ assertFalse(window.isSecureLocked());
+
+ // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is deleted.
+ Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, null);
+ mWm.mSettingsObserver.onChange(false /* selfChange */,
+ Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+ assertTrue(window.isSecureLocked());
+ }
+
+ @Test
@RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
public void testIsSecureLocked_sensitiveContentProtectionManagerEnabled() {
String testPackage = "test";
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 129494517cd6..15c8b135d2c4 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -185,6 +185,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
private static final int MSG_INCREASE_SENDSTRING_COUNT = 21;
private static final int MSG_UPDATE_USB_SPEED = 22;
private static final int MSG_UPDATE_HAL_VERSION = 23;
+ private static final int MSG_USER_UNLOCKED_AFTER_BOOT = 24;
// Delay for debouncing USB disconnects.
// We often get rapid connect/disconnect events when enabling USB functions,
@@ -414,6 +415,17 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
}
};
+ if (Flags.checkUserActionUnlocked()) {
+ BroadcastReceiver userUnlockedAfterBootReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.sendEmptyMessage(MSG_USER_UNLOCKED_AFTER_BOOT);
+ }
+ };
+ mContext.registerReceiver(userUnlockedAfterBootReceiver,
+ new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+ }
+
mContext.registerReceiver(portReceiver,
new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
mContext.registerReceiver(chargingReceiver,
@@ -474,6 +486,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
}
+ // Same as ACTION_LOCKED_BOOT_COMPLETED.
public void bootCompleted() {
if (DEBUG) Slog.d(TAG, "boot completed");
mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
@@ -632,7 +645,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
protected int mUsbSpeed;
protected int mCurrentGadgetHalVersion;
protected boolean mPendingBootAccessoryHandshakeBroadcast;
-
+ protected boolean mUserUnlockedAfterBoot;
/**
* The persistent property which stores whether adb is enabled or not.
* May also contain vendor-specific default functions for testing purposes.
@@ -837,6 +850,12 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
}
+ private void attachAccessory() {
+ mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
+ removeMessages(MSG_ACCESSORY_HANDSHAKE_TIMEOUT);
+ broadcastUsbAccessoryHandshake();
+ }
+
private void updateCurrentAccessory() {
// We are entering accessory mode if we have received a request from the host
// and the request has not timed out yet.
@@ -863,10 +882,13 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
// defer accessoryAttached if system is not ready
- if (mBootCompleted) {
- mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
- removeMessages(MSG_ACCESSORY_HANDSHAKE_TIMEOUT);
- broadcastUsbAccessoryHandshake();
+ if (!Flags.checkUserActionUnlocked() && mBootCompleted) {
+ attachAccessory();
+ }
+ // Defer accessoryAttached till user unlocks after boot.
+ // When no pin pattern is set, ACTION_USER_UNLOCKED would fire anyways
+ if (Flags.checkUserActionUnlocked() && mUserUnlockedAfterBoot) {
+ attachAccessory();
} // else handle in boot completed
} else {
Slog.e(TAG, "nativeGetAccessoryStrings failed");
@@ -887,7 +909,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
if (mCurrentAccessory != null) {
- if (mBootCompleted) {
+ if (!Flags.checkUserActionUnlocked() && mBootCompleted) {
+ mPermissionManager.usbAccessoryRemoved(mCurrentAccessory);
+ }
+ if (Flags.checkUserActionUnlocked() && mUserUnlockedAfterBoot) {
mPermissionManager.usbAccessoryRemoved(mCurrentAccessory);
}
mCurrentAccessory = null;
@@ -1377,6 +1402,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
case MSG_BOOT_COMPLETED:
operationId = sUsbOperationCount.incrementAndGet();
mBootCompleted = true;
+ if (DEBUG) Slog.d(TAG, "MSG_BOOT_COMPLETED");
finishBoot(operationId);
break;
case MSG_USER_SWITCHED: {
@@ -1423,14 +1449,38 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
}
case MSG_INCREASE_SENDSTRING_COUNT: {
mSendStringCount = mSendStringCount + 1;
+ break;
+ }
+ case MSG_USER_UNLOCKED_AFTER_BOOT: {
+ if (DEBUG) Slog.d(TAG, "MSG_USER_UNLOCKED_AFTER_BOOT");
+ if (mUserUnlockedAfterBoot) {
+ break;
+ }
+ mUserUnlockedAfterBoot = true;
+ if (mCurrentUsbFunctionsReceived && mUserUnlockedAfterBoot) {
+ attachAccessoryAfterBoot();
+ }
+ break;
}
}
}
+ private void attachAccessoryAfterBoot() {
+ if (mCurrentAccessory != null) {
+ Slog.i(TAG, "AccessoryAttached");
+ mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
+ broadcastUsbAccessoryHandshake();
+ } else if (mPendingBootAccessoryHandshakeBroadcast) {
+ broadcastUsbAccessoryHandshake();
+ }
+ mPendingBootAccessoryHandshakeBroadcast = false;
+ }
+
public abstract void handlerInitDone(int operationId);
protected void finishBoot(int operationId) {
if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
+ if (DEBUG) Slog.d(TAG, "finishBoot all flags true");
if (mPendingBootBroadcast) {
updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
mPendingBootBroadcast = false;
@@ -1441,14 +1491,12 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
} else {
setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
- if (mCurrentAccessory != null) {
- mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
- broadcastUsbAccessoryHandshake();
- } else if (mPendingBootAccessoryHandshakeBroadcast) {
- broadcastUsbAccessoryHandshake();
+ if (!Flags.checkUserActionUnlocked()) {
+ attachAccessoryAfterBoot();
+ }
+ if (Flags.checkUserActionUnlocked() && mUserUnlockedAfterBoot) {
+ attachAccessoryAfterBoot();
}
-
- mPendingBootAccessoryHandshakeBroadcast = false;
updateUsbNotification(false);
updateAdbNotification(false);
updateUsbFunctions();
diff --git a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
index cd96d76a1c93..a2d0efd1d063 100644
--- a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
+++ b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
@@ -14,3 +14,10 @@ flag {
description: "This flag enables binding to MtpService when in mtp/ptp modes"
bug: "332256525"
}
+
+flag {
+ name: "check_user_action_unlocked"
+ namespace: "usb"
+ description: "This flag checks if phone is unlocked after boot"
+ bug: "73654179"
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6490cbe3e31a..7cfdec664a92 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -9734,6 +9734,35 @@ public class CarrierConfigManager {
"carrier_supported_satellite_services_per_provider_bundle";
/**
+ * A PersistableBundle that contains a list of key-value pairs, where the values are integer
+ * arrays.
+ * <p>
+ * Keys are the IDs of regional satellite configs as strings and values are
+ * integer arrays of earfcns in the corresponding regions.
+ *
+ * An example config for two regions "1" and "2":
+ * <pre>{@code
+ * <carrier_config>
+ * <pbundle_as_map name="regional_satellite_earfcn_bundle">
+ * <int-array name = "1" num = "2">
+ * <item value = "100"/>
+ * <item value = "200"/>
+ * </int-array>
+ * <int-array name = "2" num = "1">
+ * <item value = "200"/>
+ * </int-array>
+ * </pbundle_as_map>
+ * </carrier_config>
+ * }</pre>
+ * <p>
+ * This config is empty by default.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public static final String KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE =
+ "regional_satellite_earfcn_bundle";
+
+ /**
* This config enables modem to scan satellite PLMNs specified as per
* {@link #KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE} and attach to same
* in case cellular networks are not enabled. This will need specific agreement between
@@ -11264,6 +11293,9 @@ public class CarrierConfigManager {
sDefaults.putPersistableBundle(
KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
PersistableBundle.EMPTY);
+ sDefaults.putPersistableBundle(
+ KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE,
+ PersistableBundle.EMPTY);
sDefaults.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false);
sDefaults.putInt(KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT, 180);
sDefaults.putIntArray(KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY,
diff --git a/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl b/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl
new file mode 100644
index 000000000000..1e41d6e2cc31
--- /dev/null
+++ b/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+/** @hide */
+package android.telephony;
+
+parcelable CellularIdentifierDisclosure;
diff --git a/telephony/java/android/telephony/CellularIdentifierDisclosure.java b/telephony/java/android/telephony/CellularIdentifierDisclosure.java
index 7b2db6d59819..0b6a70feac9d 100644
--- a/telephony/java/android/telephony/CellularIdentifierDisclosure.java
+++ b/telephony/java/android/telephony/CellularIdentifierDisclosure.java
@@ -16,11 +16,16 @@
package android.telephony;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.telephony.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -31,16 +36,88 @@ import java.util.Objects;
*
* @hide
*/
+@SystemApi
+@FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
public final class CellularIdentifierDisclosure implements Parcelable {
private static final String TAG = "CellularIdentifierDisclosure";
+ /* Non-access stratum protocol messages */
+ /** Unknown */
+ public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0;
+ /** ATTACH REQUESTS. Sample reference: TS 24.301 8.2.4 Applies to 2g, 3g, and 4g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1;
+ /** IDENTITY RESPONSE. Sample Reference: TS 24.301 8.2.19.
+ * Applies to 2g, 3g, 4g, and 5g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2;
+ /** DETACH_REQUEST. Sample Reference: TS 24.301 8.2.11. Applies to 2g, 3g, and 4g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3;
+ /** TRACKING AREA UPDATE (TAU) REQUEST. Sample Reference: 3GPP TS 24.301 8.2.29.
+ * Note: that per the spec, only temporary IDs should be sent in the TAU Request, but since the
+ * EPS Mobile Identity field supports IMSIs, this is included as an extra safety measure to
+ * combat implementation bugs. Applies to 4g and 5g networks. */
+ public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4;
+ /** LOCATION UPDATE REQUEST. Sample Reference: TS 24.008 4.4.3. Applies to 2g and 3g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5;
+ /** AUTHENTICATION AND CIPHERING RESPONSE. Reference: 3GPP TS 24.008 4.7.7.1.
+ * Applies to 2g and 3g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6;
+ /** REGISTRATION REQUEST. Reference: 3GPP TS 24.501 8.2.6. Applies to 5g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7;
+ /** DEREGISTRATION REQUEST. Reference: 3GPP TS 24.501 8.2.12. Applies to 5g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8;
+ /** CONNECTION MANAGEMENT REESTABLISHMENT REQUEST. Reference: 3GPP TS 24.008 9.2.4.
+ * Applies to 2g and 3g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9;
+ /** CONNECTION MANAGEMENT SERVICE REQUEST. Reference: 3GPP TS 24.008 9.2.9.
+ * Applies to 2g and 3g networks */
+ public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10;
+ /** IMEI DETATCH INDICATION. Reference: 3GPP TS 24.008 9.2.14.
+ * Applies to 2g and 3g networks. Used for circuit-switched detach. */
+ public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"NAS_PROTOCOL_MESSAGE_"}, value = {NAS_PROTOCOL_MESSAGE_UNKNOWN,
+ NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE,
+ NAS_PROTOCOL_MESSAGE_DETACH_REQUEST, NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST,
+ NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST,
+ NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE,
+ NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST, NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST,
+ NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST,
+ NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST, NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION})
+ public @interface NasProtocolMessage {
+ }
+
+ /* Cellular identifiers */
+ /** Unknown */
+ public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0;
+ /** IMSI (International Mobile Subscriber Identity) */
+ public static final int CELLULAR_IDENTIFIER_IMSI = 1;
+ /** IMEI (International Mobile Equipment Identity) */
+ public static final int CELLULAR_IDENTIFIER_IMEI = 2;
+ /** 5G-specific SUCI (Subscription Concealed Identifier) */
+ public static final int CELLULAR_IDENTIFIER_SUCI = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"CELLULAR_IDENTIFIER_"}, value = {CELLULAR_IDENTIFIER_UNKNOWN,
+ CELLULAR_IDENTIFIER_IMSI, CELLULAR_IDENTIFIER_IMEI, CELLULAR_IDENTIFIER_SUCI})
+ public @interface CellularIdentifier {
+ }
+
private @NasProtocolMessage int mNasProtocolMessage;
private @CellularIdentifier int mCellularIdentifier;
private String mPlmn;
private boolean mIsEmergency;
+ /**
+ * Constructor for new CellularIdentifierDisclosure instances.
+ *
+ * @hide
+ */
+ @TestApi
public CellularIdentifierDisclosure(@NasProtocolMessage int nasProtocolMessage,
- @CellularIdentifier int cellularIdentifier, String plmn, boolean isEmergency) {
+ @CellularIdentifier int cellularIdentifier, @NonNull String plmn, boolean isEmergency) {
mNasProtocolMessage = nasProtocolMessage;
mCellularIdentifier = cellularIdentifier;
mPlmn = plmn;
@@ -51,18 +128,30 @@ public final class CellularIdentifierDisclosure implements Parcelable {
readFromParcel(in);
}
+ /**
+ * @return the NAS protocol message associated with the disclosed identifier.
+ */
public @NasProtocolMessage int getNasProtocolMessage() {
return mNasProtocolMessage;
}
+ /**
+ * @return the identifier disclosed.
+ */
public @CellularIdentifier int getCellularIdentifier() {
return mCellularIdentifier;
}
- public String getPlmn() {
+ /**
+ * @return the PLMN associated with the disclosure.
+ */
+ @NonNull public String getPlmn() {
return mPlmn;
}
+ /**
+ * @return if the disclosure is associated with an emergency call.
+ */
public boolean isEmergency() {
return mIsEmergency;
}
@@ -73,14 +162,14 @@ public final class CellularIdentifierDisclosure implements Parcelable {
}
@Override
- public void writeToParcel(Parcel out, int flags) {
+ public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mNasProtocolMessage);
out.writeInt(mCellularIdentifier);
out.writeBoolean(mIsEmergency);
out.writeString8(mPlmn);
}
- public static final Parcelable.Creator<CellularIdentifierDisclosure> CREATOR =
+ public static final @NonNull Parcelable.Creator<CellularIdentifierDisclosure> CREATOR =
new Parcelable.Creator<CellularIdentifierDisclosure>() {
public CellularIdentifierDisclosure createFromParcel(Parcel in) {
return new CellularIdentifierDisclosure(in);
@@ -120,42 +209,4 @@ public final class CellularIdentifierDisclosure implements Parcelable {
mIsEmergency = in.readBoolean();
mPlmn = in.readString8();
}
-
- public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0;
- public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1;
- public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2;
- public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3;
- public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4;
- public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5;
- public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6;
- public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7;
- public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8;
- public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9;
- public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10;
- public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"NAS_PROTOCOL_MESSAGE_"}, value = {NAS_PROTOCOL_MESSAGE_UNKNOWN,
- NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE,
- NAS_PROTOCOL_MESSAGE_DETACH_REQUEST, NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST,
- NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST,
- NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE,
- NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST, NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST,
- NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST,
- NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST, NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION})
- public @interface NasProtocolMessage {
- }
-
- public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0;
- public static final int CELLULAR_IDENTIFIER_IMSI = 1;
- public static final int CELLULAR_IDENTIFIER_IMEI = 2;
- public static final int CELLULAR_IDENTIFIER_SUCI = 3;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"CELLULAR_IDENTIFIER_"}, value = {CELLULAR_IDENTIFIER_UNKNOWN,
- CELLULAR_IDENTIFIER_IMSI, CELLULAR_IDENTIFIER_IMEI, CELLULAR_IDENTIFIER_SUCI})
- public @interface CellularIdentifier {
- }
}
diff --git a/core/java/android/content/pm/verify/pkg/VerificationSession.aidl b/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl
index ac855850a86c..bee30bd43df9 100644
--- a/core/java/android/content/pm/verify/pkg/VerificationSession.aidl
+++ b/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.verify.pkg;
-
/** @hide */
-parcelable VerificationSession;
+package android.telephony;
+
+parcelable SecurityAlgorithmUpdate;
diff --git a/telephony/java/android/telephony/SecurityAlgorithmUpdate.java b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
index 57209eb68de8..d635b555276b 100644
--- a/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
+++ b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
@@ -16,11 +16,16 @@
package android.telephony;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.telephony.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -31,112 +36,42 @@ import java.util.Objects;
*
* @hide
*/
+@SystemApi
+@FlaggedApi(Flags.FLAG_SECURITY_ALGORITHMS_UPDATE_INDICATIONS)
public final class SecurityAlgorithmUpdate implements Parcelable {
private static final String TAG = "SecurityAlgorithmUpdate";
- private @ConnectionEvent int mConnectionEvent;
- private @SecurityAlgorithm int mEncryption;
- private @SecurityAlgorithm int mIntegrity;
- private boolean mIsUnprotectedEmergency;
-
- public SecurityAlgorithmUpdate(@ConnectionEvent int connectionEvent,
- @SecurityAlgorithm int encryption, @SecurityAlgorithm int integrity,
- boolean isUnprotectedEmergency) {
- mConnectionEvent = connectionEvent;
- mEncryption = encryption;
- mIntegrity = integrity;
- mIsUnprotectedEmergency = isUnprotectedEmergency;
- }
-
- private SecurityAlgorithmUpdate(Parcel in) {
- readFromParcel(in);
- }
-
- public @ConnectionEvent int getConnectionEvent() {
- return mConnectionEvent;
- }
-
- public @SecurityAlgorithm int getEncryption() {
- return mEncryption;
- }
-
- public @SecurityAlgorithm int getIntegrity() {
- return mIntegrity;
- }
-
- public boolean isUnprotectedEmergency() {
- return mIsUnprotectedEmergency;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mConnectionEvent);
- out.writeInt(mEncryption);
- out.writeInt(mIntegrity);
- out.writeBoolean(mIsUnprotectedEmergency);
- }
-
- private void readFromParcel(@NonNull Parcel in) {
- mConnectionEvent = in.readInt();
- mEncryption = in.readInt();
- mIntegrity = in.readInt();
- mIsUnprotectedEmergency = in.readBoolean();
- }
-
- public static final Parcelable.Creator<SecurityAlgorithmUpdate> CREATOR =
- new Parcelable.Creator<SecurityAlgorithmUpdate>() {
- public SecurityAlgorithmUpdate createFromParcel(Parcel in) {
- return new SecurityAlgorithmUpdate(in);
- }
-
- public SecurityAlgorithmUpdate[] newArray(int size) {
- return new SecurityAlgorithmUpdate[size];
- }
- };
-
- @Override
- public String toString() {
- return TAG + ":{ mConnectionEvent = " + mConnectionEvent + " mEncryption = " + mEncryption
- + " mIntegrity = " + mIntegrity + " mIsUnprotectedEmergency = "
- + mIsUnprotectedEmergency;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof SecurityAlgorithmUpdate)) return false;
- SecurityAlgorithmUpdate that = (SecurityAlgorithmUpdate) o;
- return mConnectionEvent == that.mConnectionEvent
- && mEncryption == that.mEncryption
- && mIntegrity == that.mIntegrity
- && mIsUnprotectedEmergency == that.mIsUnprotectedEmergency;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mConnectionEvent, mEncryption, mIntegrity, mIsUnprotectedEmergency);
- }
-
+ /** 2G GSM circuit switched */
public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0;
+ /** 2G GPRS packet services */
public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1;
+ /** 3G circuit switched*/
public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2;
+ /** 3G packet switched*/
public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3;
+ /** 4G Non-access stratum */
public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4;
+ /** 4G Access-stratum */
public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5;
+ /** VOLTE SIP */
public static final int CONNECTION_EVENT_VOLTE_SIP = 6;
+ /** VOLTE SIP SOS (emergency) */
public static final int CONNECTION_EVENT_VOLTE_SIP_SOS = 7;
+ /** VOLTE RTP */
public static final int CONNECTION_EVENT_VOLTE_RTP = 8;
+ /** VOLTE RTP SOS (emergency) */
public static final int CONNECTION_EVENT_VOLTE_RTP_SOS = 9;
+ /** 5G Non-access stratum */
public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 10;
+ /** 5G Access stratum */
public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 11;
+ /** VoNR SIP */
public static final int CONNECTION_EVENT_VONR_SIP = 12;
+ /** VoNR SIP SOS (emergency) */
public static final int CONNECTION_EVENT_VONR_SIP_SOS = 13;
+ /** VoNR RTP */
public static final int CONNECTION_EVENT_VONR_RTP = 14;
+ /** VoNR RTP SOS (emergency) */
public static final int CONNECTION_EVENT_VONR_RTP_SOS = 15;
/** @hide */
@@ -153,48 +88,101 @@ public final class SecurityAlgorithmUpdate implements Parcelable {
public @interface ConnectionEvent {
}
+ /* GSM CS services, see 3GPP TS 43.020 for details */
+ /** A5/0 - the null cipher */
public static final int SECURITY_ALGORITHM_A50 = 0;
+ /** A5/1 cipher */
public static final int SECURITY_ALGORITHM_A51 = 1;
+ /** A5/2 cipher */
public static final int SECURITY_ALGORITHM_A52 = 2;
+ /** A5/3 cipher */
public static final int SECURITY_ALGORITHM_A53 = 3;
+ /** A5/4 cipher */
public static final int SECURITY_ALGORITHM_A54 = 4;
+ /* GPRS PS services (3GPP TS 43.020) */
+ /** GEA0 - null cipher */
public static final int SECURITY_ALGORITHM_GEA0 = 14;
+ /** GEA1 cipher */
public static final int SECURITY_ALGORITHM_GEA1 = 15;
+ /** GEA2 cipher */
public static final int SECURITY_ALGORITHM_GEA2 = 16;
+ /** GEA3 cipher */
public static final int SECURITY_ALGORITHM_GEA3 = 17;
+ /** GEA4 cipher */
public static final int SECURITY_ALGORITHM_GEA4 = 18;
+ /** GEA5 cipher */
public static final int SECURITY_ALGORITHM_GEA5 = 19;
+ /* 3G PS/CS services (3GPP TS 33.102) */
+ /** UEA0 - null cipher */
public static final int SECURITY_ALGORITHM_UEA0 = 29;
+ /** UEA1 cipher */
public static final int SECURITY_ALGORITHM_UEA1 = 30;
+ /** UEA2 cipher */
public static final int SECURITY_ALGORITHM_UEA2 = 31;
+ /* 4G PS services & 5G NSA (3GPP TS 33.401) */
+ /** EEA0 - null cipher */
public static final int SECURITY_ALGORITHM_EEA0 = 41;
+ /** EEA1 */
public static final int SECURITY_ALGORITHM_EEA1 = 42;
+ /** EEA2 */
public static final int SECURITY_ALGORITHM_EEA2 = 43;
+ /** EEA3 */
public static final int SECURITY_ALGORITHM_EEA3 = 44;
+ /* 5G PS services (3GPP TS 33.401 for 5G NSA and 3GPP TS 33.501 for 5G SA) */
+ /** NEA0 - the null cipher */
public static final int SECURITY_ALGORITHM_NEA0 = 55;
+ /** NEA1 */
public static final int SECURITY_ALGORITHM_NEA1 = 56;
+ /** NEA2 */
public static final int SECURITY_ALGORITHM_NEA2 = 57;
+ /** NEA3 */
public static final int SECURITY_ALGORITHM_NEA3 = 58;
+ /* IMS and SIP layer security (See 3GPP TS 33.203) */
+ /** No IPsec config */
public static final int SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG = 66;
+ /** No IMS security, recommended to use SIP_NO_IPSEC_CONFIG and SIP_NULL instead */
public static final int SECURITY_ALGORITHM_IMS_NULL = 67;
+ /* IPSEC is present */
+ /** SIP security is not enabled */
public static final int SECURITY_ALGORITHM_SIP_NULL = 68;
+ /** AES GCM mode */
public static final int SECURITY_ALGORITHM_AES_GCM = 69;
+ /** AES GMAC mode */
public static final int SECURITY_ALGORITHM_AES_GMAC = 70;
+ /** AES CBC mode */
public static final int SECURITY_ALGORITHM_AES_CBC = 71;
+ /** DES EDE3 CBC mode */
public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72;
+ /** AES EDE3 CBC mode */
public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73;
+ /** HMAC SHA1 96 */
public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74;
+ /** HMAC MD5 96 */
public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 75;
+ /* RTP and SRTP (see 3GPP TS 33.328) */
+ /** RTP only, SRTP is not being used */
public static final int SECURITY_ALGORITHM_RTP = 85;
+ /* When SRTP is available and used */
+ /** SRTP with null ciphering */
public static final int SECURITY_ALGORITHM_SRTP_NULL = 86;
+ /** SRTP with AES counter mode */
public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87;
+ /** SRTP with AES F8 mode */
public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88;
+ /** SRTP with HMAC SHA1 */
public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89;
+ /* Ciphers for ePDG (3GPP TS 33.402) */
+ /** ePDG encryption - AES GCM mode */
public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99;
+ /** ePDG encryption - AES GCM CBC mode */
public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100;
+ /** ePDG authentication - HMAC SHA1 256 128 */
public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101;
+ /** Unknown */
public static final int SECURITY_ALGORITHM_UNKNOWN = 113;
+ /** Other */
public static final int SECURITY_ALGORITHM_OTHER = 114;
+ /** Proprietary algorithms */
public static final int SECURITY_ALGORITHM_ORYX = 124;
/** @hide */
@@ -220,4 +208,109 @@ public final class SecurityAlgorithmUpdate implements Parcelable {
public @interface SecurityAlgorithm {
}
+ private @ConnectionEvent int mConnectionEvent;
+ private @SecurityAlgorithm int mEncryption;
+ private @SecurityAlgorithm int mIntegrity;
+ private boolean mIsUnprotectedEmergency;
+
+ /**
+ * Constructor for new SecurityAlgorithmUpdate instances.
+ *
+ * @hide
+ */
+ @TestApi
+ public SecurityAlgorithmUpdate(@ConnectionEvent int connectionEvent,
+ @SecurityAlgorithm int encryption, @SecurityAlgorithm int integrity,
+ boolean isUnprotectedEmergency) {
+ mConnectionEvent = connectionEvent;
+ mEncryption = encryption;
+ mIntegrity = integrity;
+ mIsUnprotectedEmergency = isUnprotectedEmergency;
+ }
+
+ private SecurityAlgorithmUpdate(Parcel in) {
+ readFromParcel(in);
+ }
+
+ /**
+ * @return the connection event.
+ */
+ public @ConnectionEvent int getConnectionEvent() {
+ return mConnectionEvent;
+ }
+
+ /**
+ * @return the encryption algorithm.
+ */
+ public @SecurityAlgorithm int getEncryption() {
+ return mEncryption;
+ }
+
+ /**
+ * @return the integrity algorithm.
+ */
+ public @SecurityAlgorithm int getIntegrity() {
+ return mIntegrity;
+ }
+
+ /**
+ * @return if the security algorithm update is associated with an unprotected emergency call.
+ */
+ public boolean isUnprotectedEmergency() {
+ return mIsUnprotectedEmergency;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mConnectionEvent);
+ out.writeInt(mEncryption);
+ out.writeInt(mIntegrity);
+ out.writeBoolean(mIsUnprotectedEmergency);
+ }
+
+ private void readFromParcel(@NonNull Parcel in) {
+ mConnectionEvent = in.readInt();
+ mEncryption = in.readInt();
+ mIntegrity = in.readInt();
+ mIsUnprotectedEmergency = in.readBoolean();
+ }
+
+ public static final @NonNull Parcelable.Creator<SecurityAlgorithmUpdate> CREATOR =
+ new Parcelable.Creator<SecurityAlgorithmUpdate>() {
+ public SecurityAlgorithmUpdate createFromParcel(Parcel in) {
+ return new SecurityAlgorithmUpdate(in);
+ }
+
+ public SecurityAlgorithmUpdate[] newArray(int size) {
+ return new SecurityAlgorithmUpdate[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return TAG + ":{ mConnectionEvent = " + mConnectionEvent + " mEncryption = " + mEncryption
+ + " mIntegrity = " + mIntegrity + " mIsUnprotectedEmergency = "
+ + mIsUnprotectedEmergency;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SecurityAlgorithmUpdate)) return false;
+ SecurityAlgorithmUpdate that = (SecurityAlgorithmUpdate) o;
+ return mConnectionEvent == that.mConnectionEvent
+ && mEncryption == that.mEncryption
+ && mIntegrity == that.mIntegrity
+ && mIsUnprotectedEmergency == that.mIsUnprotectedEmergency;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mConnectionEvent, mEncryption, mIntegrity, mIsUnprotectedEmergency);
+ }
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6f2c8623fd71..ad5d42ad5a68 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8825,9 +8825,6 @@ public class TelephonyManager {
* {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION} or doesn't support given
* authType.
*/
- // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not
- // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
- // it's not public API.
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public String getIccAuthentication(int appType, @AuthType int authType, String data) {
return getIccAuthentication(getSubId(), appType, authType, data);
@@ -12239,9 +12236,10 @@ public class TelephonyManager {
* @param subId Subscription ID
* @return true if IMS status is registered, false if the IMS status is not registered or a
* RemoteException occurred.
- * Use {@link ImsMmTelManager.RegistrationCallback} instead.
* @hide
+ * @deprecated Use {@link ImsMmTelManager#getRegistrationState(Executor, Consumer)} instead.
*/
+ @Deprecated
public boolean isImsRegistered(int subId) {
try {
return getITelephony().isImsRegistered(subId);
@@ -12259,8 +12257,10 @@ public class TelephonyManager {
* @return true if IMS status is registered, false if the IMS status is not registered or a
* RemoteException occurred.
* @see SubscriptionManager#getDefaultSubscriptionId()
+ * @deprecated Use {@link ImsMmTelManager#getRegistrationState(Executor, Consumer)} instead.
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public boolean isImsRegistered() {
try {
@@ -12277,9 +12277,10 @@ public class TelephonyManager {
* @return true if Voice over LTE is available or false if it is unavailable or unknown.
* @see SubscriptionManager#getDefaultSubscriptionId()
* <p>
- * Use {@link ImsMmTelManager#isAvailable(int, int)} instead.
+ * @Deprecated Use {@link ImsMmTelManager#isAvailable(int, int)} instead.
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage
public boolean isVolteAvailable() {
try {
@@ -12297,9 +12298,10 @@ public class TelephonyManager {
* used during creation, the default subscription ID will be used. To query the
* underlying technology that VT is available on, use {@link #getImsRegTechnologyForMmTel}.
* @return true if VT is available, or false if it is unavailable or unknown.
- * Use {@link ImsMmTelManager#isAvailable(int, int)} instead.
+ * @Deprecated Use {@link ImsMmTelManager#isAvailable(int, int)} instead.
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage
public boolean isVideoTelephonyAvailable() {
try {
@@ -12313,9 +12315,10 @@ public class TelephonyManager {
* Returns the Status of Wi-Fi calling (Voice over WiFi) for the subscription ID specified.
* @param subId the subscription ID.
* @return true if VoWiFi is available, or false if it is unavailable or unknown.
- * Use {@link ImsMmTelManager#isAvailable(int, int)} instead.
+ * @Deprecated Use {@link ImsMmTelManager#isAvailable(int, int)} instead.
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage
public boolean isWifiCallingAvailable() {
try {
@@ -12336,9 +12339,11 @@ public class TelephonyManager {
* other sim's internet, or
* - {@link ImsRegistrationImplBase#REGISTRATION_TECH_NONE} if we are not registered or the
* result is unavailable.
- * Use {@link ImsMmTelManager.RegistrationCallback} instead.
+ * @Deprecated Use {@link ImsMmTelManager#registerImsRegistrationCallback(Executor, RegistrationCallback)}
+ * or {@link ImsMmTelManager#getRegistrationTransportType(Executor, Consumer)} instead.
* @hide
*/
+ @Deprecated
public @ImsRegistrationImplBase.ImsRegistrationTech int getImsRegTechnologyForMmTel() {
try {
return getITelephony().getImsRegTechnologyForMmTel(getSubId());
@@ -19594,4 +19599,37 @@ public class TelephonyManager {
throw ex.rethrowAsRuntimeException();
}
}
+
+ /**
+ * Returns carrier id maps to the passing CarrierIdentifier.
+ * To recognize a carrier (including MVNO) as a first-class identity,
+ * Android assigns each carrier with a canonical integer a.k.a. carrier id.
+ * The carrier ID is an Android platform-wide identifier for a carrier.
+ * AOSP maintains carrier ID assignments in
+ * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
+ *
+ * @param carrierIdentifier {@link CarrierIdentifier}
+ *
+ * @return Carrier id. Return {@link #UNKNOWN_CARRIER_ID} if the carrier cannot be identified.
+ * @throws UnsupportedOperationException If the device does not have
+ * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ID_FROM_CARRIER_IDENTIFIER)
+ @SystemApi
+ @WorkerThread
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public int getCarrierIdFromCarrierIdentifier(@NonNull CarrierIdentifier carrierIdentifier) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.getCarrierIdFromIdentifier(carrierIdentifier);
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ return UNKNOWN_CARRIER_ID;
+ }
}
diff --git a/telephony/java/android/telephony/satellite/EarfcnRange.java b/telephony/java/android/telephony/satellite/EarfcnRange.java
index 38043b570c2f..207b25d60d90 100644
--- a/telephony/java/android/telephony/satellite/EarfcnRange.java
+++ b/telephony/java/android/telephony/satellite/EarfcnRange.java
@@ -24,6 +24,8 @@ import android.os.Parcelable;
import com.android.internal.telephony.flags.Flags;
+import java.util.Objects;
+
/**
* EARFCN (E-UTRA Absolute Radio Frequency Channel Number): A number that identifies a
* specific frequency channel in LTE/5G NR, used to define the carrier frequency.
@@ -73,10 +75,10 @@ public final class EarfcnRange implements Parcelable {
* @param startEarfcn The starting earfcn value.
* @param endEarfcn The ending earfcn value.
*/
- public EarfcnRange(@IntRange(from = 0, to = 65535) int endEarfcn,
- @IntRange(from = 0, to = 65535) int startEarfcn) {
- mEndEarfcn = endEarfcn;
+ public EarfcnRange(@IntRange(from = 0, to = 65535) int startEarfcn,
+ @IntRange(from = 0, to = 65535) int endEarfcn) {
mStartEarfcn = startEarfcn;
+ mEndEarfcn = endEarfcn;
}
@Override
@@ -85,6 +87,7 @@ public final class EarfcnRange implements Parcelable {
}
@Override
+ @NonNull
public String toString() {
return "startEarfcn: " + mStartEarfcn + ", " + "endEarfcn: " + mEndEarfcn;
}
@@ -121,4 +124,17 @@ public final class EarfcnRange implements Parcelable {
public @IntRange(from = 0, to = 65535) int getEndEarfcn() {
return mEndEarfcn;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EarfcnRange that)) return false;
+
+ return (that.mStartEarfcn == mStartEarfcn) && (that.mEndEarfcn == mEndEarfcn);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mStartEarfcn, mEndEarfcn);
+ }
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteAccessConfiguration.java b/telephony/java/android/telephony/satellite/SatelliteAccessConfiguration.java
index c3ae70b48854..c1a6ae850985 100644
--- a/telephony/java/android/telephony/satellite/SatelliteAccessConfiguration.java
+++ b/telephony/java/android/telephony/satellite/SatelliteAccessConfiguration.java
@@ -24,7 +24,9 @@ import androidx.annotation.NonNull;
import com.android.internal.telephony.flags.Flags;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* SatelliteAccessConfiguration is used to store satellite access configuration
@@ -44,25 +46,25 @@ public final class SatelliteAccessConfiguration implements Parcelable {
* The list of tag IDs associated with the current location
*/
@NonNull
- private int[] mTagIds;
+ private List<Integer> mTagIdList;
/**
* Constructor for {@link SatelliteAccessConfiguration}.
*
* @param satelliteInfos The list of {@link SatelliteInfo} objects representing the satellites
* accessible with this configuration.
- * @param tagIds The list of tag IDs associated with this configuration.
+ * @param tagIdList The list of tag IDs associated with this configuration.
*/
public SatelliteAccessConfiguration(@NonNull List<SatelliteInfo> satelliteInfos,
- @NonNull int[] tagIds) {
+ @NonNull List<Integer> tagIdList) {
mSatelliteInfoList = satelliteInfos;
- mTagIds = tagIds;
+ mTagIdList = tagIdList;
}
public SatelliteAccessConfiguration(Parcel in) {
mSatelliteInfoList = in.createTypedArrayList(SatelliteInfo.CREATOR);
- mTagIds = new int[in.readInt()];
- in.readIntArray(mTagIds);
+ mTagIdList = new ArrayList<>();
+ in.readList(mTagIdList, Integer.class.getClassLoader(), Integer.class);
}
public static final Creator<SatelliteAccessConfiguration> CREATOR =
@@ -91,12 +93,7 @@ public final class SatelliteAccessConfiguration implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedList(mSatelliteInfoList);
- if (mTagIds != null && mTagIds.length > 0) {
- dest.writeInt(mTagIds.length);
- dest.writeIntArray(mTagIds);
- } else {
- dest.writeInt(0);
- }
+ dest.writeList(mTagIdList);
}
/**
@@ -116,7 +113,34 @@ public final class SatelliteAccessConfiguration implements Parcelable {
* @return The list of tag IDs.
*/
@NonNull
- public int[] getTagIds() {
- return mTagIds;
+ public List<Integer> getTagIds() {
+ return mTagIdList;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SatelliteAccessConfiguration that)) return false;
+
+ return mSatelliteInfoList.equals(that.mSatelliteInfoList)
+ && Objects.equals(mTagIdList, that.mTagIdList);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mSatelliteInfoList);
+ result = 31 * result + Objects.hashCode(mTagIdList);
+ return result;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SatelliteAccessConfiguration{");
+ sb.append("mSatelliteInfoList=").append(mSatelliteInfoList);
+ sb.append(", mTagIds=").append(mTagIdList);
+ sb.append('}');
+ return sb.toString();
}
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteInfo.java b/telephony/java/android/telephony/satellite/SatelliteInfo.java
index bca907e49993..7ff231812c8a 100644
--- a/telephony/java/android/telephony/satellite/SatelliteInfo.java
+++ b/telephony/java/android/telephony/satellite/SatelliteInfo.java
@@ -17,6 +17,7 @@
package android.telephony.satellite;
import android.annotation.FlaggedApi;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.Parcelable;
@@ -25,7 +26,9 @@ import androidx.annotation.NonNull;
import com.android.internal.telephony.flags.Flags;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.UUID;
/**
@@ -47,17 +50,18 @@ public class SatelliteInfo implements Parcelable {
* Position information of a satellite.
* This includes the longitude and altitude of the satellite.
*/
+ @Nullable
private SatellitePosition mPosition;
/**
- * The frequency bands to scan. Bands and earfcns won't overlap.
+ * The frequency band list to scan. Bands and earfcns won't overlap.
* Bands will be filled only if the whole band is needed.
* Maximum length of the vector is 8.
*/
- private int[] mBands;
+ private List<Integer> mBandList;
/**
- * EARFCN (E-UTRA Absolute Radio Frequency Channel Number) Ranges
+ * EARFCN (E-UTRA Absolute Radio Frequency Channel Number) range list
* The supported frequency range list.
* Maximum length of the vector is 8.
*/
@@ -71,13 +75,8 @@ public class SatelliteInfo implements Parcelable {
}
mPosition = in.readParcelable(SatellitePosition.class.getClassLoader(),
SatellitePosition.class);
- int numBands = in.readInt();
- mBands = new int[numBands];
- if (numBands > 0) {
- for (int i = 0; i < numBands; i++) {
- mBands[i] = in.readInt();
- }
- }
+ mBandList = new ArrayList<>();
+ in.readList(mBandList, Integer.class.getClassLoader(), Integer.class);
mEarfcnRangeList = in.createTypedArrayList(EarfcnRange.CREATOR);
}
@@ -86,15 +85,15 @@ public class SatelliteInfo implements Parcelable {
*
* @param satelliteId The ID of the satellite.
* @param satellitePosition The {@link SatellitePosition} of the satellite.
- * @param bands The list of frequency bands supported by the satellite.
+ * @param bandList The list of frequency bandList supported by the satellite.
* @param earfcnRanges The list of {@link EarfcnRange} objects representing the EARFCN
* ranges supported by the satellite.
*/
- public SatelliteInfo(@NonNull UUID satelliteId, @NonNull SatellitePosition satellitePosition,
- @NonNull int[] bands, @NonNull List<EarfcnRange> earfcnRanges) {
+ public SatelliteInfo(@NonNull UUID satelliteId, @Nullable SatellitePosition satellitePosition,
+ @NonNull List<Integer> bandList, @NonNull List<EarfcnRange> earfcnRanges) {
mId = satelliteId;
mPosition = satellitePosition;
- mBands = bands;
+ mBandList = bandList;
mEarfcnRangeList = earfcnRanges;
}
@@ -119,12 +118,7 @@ public class SatelliteInfo implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelable(new ParcelUuid(mId), flags);
dest.writeParcelable(mPosition, flags);
- if (mBands != null && mBands.length > 0) {
- dest.writeInt(mBands.length);
- dest.writeIntArray(mBands);
- } else {
- dest.writeInt(0);
- }
+ dest.writeList(mBandList);
dest.writeTypedList(mEarfcnRangeList);
}
@@ -141,8 +135,10 @@ public class SatelliteInfo implements Parcelable {
/**
* Returns the position of the satellite.
*
- * @return The {@link SatellitePosition} of the satellite.
+ * @return The {@link SatellitePosition} of the satellite, or {@code null} if the position is
+ * not available.
*/
+ @Nullable
public SatellitePosition getSatellitePosition() {
return mPosition;
}
@@ -153,8 +149,8 @@ public class SatelliteInfo implements Parcelable {
* @return The list of frequency bands.
*/
@NonNull
- public int[] getBands() {
- return mBands;
+ public List<Integer> getBands() {
+ return mBandList;
}
/**
@@ -166,4 +162,35 @@ public class SatelliteInfo implements Parcelable {
public List<EarfcnRange> getEarfcnRanges() {
return mEarfcnRangeList;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SatelliteInfo that)) return false;
+
+ return mId.equals(that.mId)
+ && Objects.equals(mPosition, that.mPosition)
+ && Objects.equals(mBandList, that.mBandList)
+ && mEarfcnRangeList.equals(that.mEarfcnRangeList);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mId, mPosition, mEarfcnRangeList);
+ result = 31 * result + Objects.hashCode(mBandList);
+ return result;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SatelliteInfo{");
+ sb.append("mId=").append(mId);
+ sb.append(", mPosition=").append(mPosition);
+ sb.append(", mBandList=").append(mBandList);
+ sb.append(", mEarfcnRangeList=").append(mEarfcnRangeList);
+ sb.append('}');
+ return sb.toString();
+ }
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 887b79883710..23203ed65e9a 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -281,6 +281,14 @@ public final class SatelliteManager {
"satellite_access_configuration";
/**
+ * Bundle key to get the response from
+ * {@link #requestSelectedNbIotSatelliteSubscriptionId(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID =
+ "selected_nb_iot_satellite_subscription_id";
+
+ /**
* The request was successfully processed.
* @hide
*/
@@ -531,6 +539,12 @@ public final class SatelliteManager {
@FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_RESULT_ENABLE_IN_PROGRESS = 29;
+ /**
+ * There is no valid satellite subscription selected.
+ * @hide
+ */
+ public static final int SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION = 30;
+
/** @hide */
@IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
SATELLITE_RESULT_SUCCESS,
@@ -562,7 +576,8 @@ public final class SatelliteManager {
SATELLITE_RESULT_LOCATION_NOT_AVAILABLE,
SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS,
SATELLITE_RESULT_DISABLE_IN_PROGRESS,
- SATELLITE_RESULT_ENABLE_IN_PROGRESS
+ SATELLITE_RESULT_ENABLE_IN_PROGRESS,
+ SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION
})
@Retention(RetentionPolicy.SOURCE)
public @interface SatelliteResult {}
@@ -2464,6 +2479,68 @@ public final class SatelliteManager {
}
/**
+ * Request to get the currently selected satellite subscription id as an {@link Integer}.
+ *
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return the time after which the satellite will be visible.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+ * will return a {@link SatelliteException} with the {@link SatelliteResult}.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ public void requestSelectedNbIotSatelliteSubscriptionId(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Integer, SatelliteException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_RESULT_SUCCESS) {
+ if (resultData
+ .containsKey(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID)) {
+ int selectedSatelliteSubscriptionId =
+ resultData
+ .getInt(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(selectedSatelliteSubscriptionId)));
+ } else {
+ loge(
+ "KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID does not exist."
+ );
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(
+ SATELLITE_RESULT_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
+ }
+ };
+ telephony.requestSelectedNbIotSatelliteSubscriptionId(receiver);
+ } else {
+ loge("requestSelectedNbIotSatelliteSubscriptionId() invalid telephony");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ } catch (RemoteException ex) {
+ loge("requestSelectedNbIotSatelliteSubscriptionId() RemoteException: " + ex);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ }
+
+ /**
* Inform whether the device is aligned with the satellite in both real and demo mode.
*
* In demo mode, framework will send datagram to modem only when device is aligned with
diff --git a/telephony/java/android/telephony/satellite/SatellitePosition.java b/telephony/java/android/telephony/satellite/SatellitePosition.java
index 1e8c0180f456..dd463e00ebb5 100644
--- a/telephony/java/android/telephony/satellite/SatellitePosition.java
+++ b/telephony/java/android/telephony/satellite/SatellitePosition.java
@@ -23,6 +23,8 @@ import androidx.annotation.NonNull;
import com.android.internal.telephony.flags.Flags;
+import java.util.Objects;
+
/**
* The position of a satellite in Earth orbit.
*
@@ -111,4 +113,24 @@ public class SatellitePosition implements Parcelable {
public double getAltitudeKm() {
return mAltitudeKm;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SatellitePosition that)) return false;
+
+ return Double.compare(that.mLongitudeDegree, mLongitudeDegree) == 0
+ && Double.compare(that.mAltitudeKm, mAltitudeKm) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLongitudeDegree, mAltitudeKm);
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return "mLongitudeDegree: " + mLongitudeDegree + ", " + "mAltitudeKm: " + mAltitudeKm;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a58427318b55..294c93c8e493 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3018,6 +3018,17 @@ interface ITelephony {
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
void requestTimeForNextSatelliteVisibility(in ResultReceiver receiver);
+
+ /**
+ * Request to get the currently selected satellite subscription id.
+ *
+ * @param receiver Result receiver to get the error code of the request and the currently
+ * selected satellite subscription id.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestSelectedNbIotSatelliteSubscriptionId(in ResultReceiver receiver);
+
/**
* Inform whether the device is aligned with the satellite in both real and demo mode.
*
@@ -3508,4 +3519,15 @@ interface ITelephony {
* @hide
*/
void setNtnSmsSupported(boolean ntnSmsSupported);
+
+ /**
+ * Returns carrier id maps to the passing {@link CarrierIdentifier}.
+ *
+ * @param {@link CarrierIdentifier}.
+ *
+ * @return carrier id from passing {@link CarrierIdentifier} or {@link #UNKNOWN_CARRIER_ID}
+ * if the carrier cannot be identified
+ * @hide
+ */
+ int getCarrierIdFromIdentifier(in CarrierIdentifier carrierIdentifier);
}
diff --git a/test-mock/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index 8f4bcccb0cba..af6ee3d0f71b 100644
--- a/test-mock/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.IContentProvider;
import android.database.ContentObserver;
import android.net.Uri;
+import android.util.Log;
import java.util.Collection;
import java.util.HashMap;
@@ -53,6 +54,7 @@ import java.util.Map;
* </div>
*/
public class MockContentResolver extends ContentResolver {
+ private static final String TAG = "MockContentResolver";
Map<String, ContentProvider> mProviders;
/**
@@ -105,6 +107,7 @@ public class MockContentResolver extends ContentResolver {
if (provider != null) {
return provider.getIContentProvider();
} else {
+ Log.w(TAG, "Provider does not exist: " + name);
return null;
}
}
diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java
index 2cd625eec032..4d495adf727b 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java
@@ -18,7 +18,9 @@ package android.app.jank.tests;
import static org.junit.Assert.assertEquals;
+import android.app.jank.AppJankStats;
import android.app.jank.Flags;
+import android.app.jank.FrameOverrunHistogram;
import android.app.jank.JankDataProcessor;
import android.app.jank.StateTracker;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -39,6 +41,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@@ -154,6 +157,73 @@ public class JankDataProcessorTest {
assertEquals(totalFrames, histogramFrames);
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
+ public void mergeAppJankStats_confirmStatAddedToPendingStats() {
+ HashMap<String, JankDataProcessor.PendingJankStat> pendingStats =
+ mJankDataProcessor.getPendingJankStats();
+
+ assertEquals(pendingStats.size(), 0);
+
+ AppJankStats jankStats = getAppJankStats();
+ mJankDataProcessor.mergeJankStats(jankStats, sActivityName);
+
+ pendingStats = mJankDataProcessor.getPendingJankStats();
+
+ assertEquals(pendingStats.size(), 1);
+ }
+
+ /**
+ * This test confirms matching states are combined into one pending stat. When JankStats are
+ * merged from outside the platform they will contain widget category, widget id and widget
+ * state. If an incoming JankStats matches a pending stat on all those fields the incoming
+ * JankStat will be merged into the existing stat.
+ */
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
+ public void mergeAppJankStats_confirmStatsWithMatchingStatesAreCombinedIntoOnePendingStat() {
+ AppJankStats jankStats = getAppJankStats();
+ mJankDataProcessor.mergeJankStats(jankStats, sActivityName);
+
+ HashMap<String, JankDataProcessor.PendingJankStat> pendingStats =
+ mJankDataProcessor.getPendingJankStats();
+ assertEquals(pendingStats.size(), 1);
+
+ AppJankStats secondJankStat = getAppJankStats();
+ mJankDataProcessor.mergeJankStats(secondJankStat, sActivityName);
+
+ pendingStats = mJankDataProcessor.getPendingJankStats();
+
+ assertEquals(pendingStats.size(), 1);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
+ public void mergeAppJankStats_whenStatsWithMatchingStatesMerge_confirmFrameCountsAdded() {
+ AppJankStats jankStats = getAppJankStats();
+ mJankDataProcessor.mergeJankStats(jankStats, sActivityName);
+ mJankDataProcessor.mergeJankStats(jankStats, sActivityName);
+
+ HashMap<String, JankDataProcessor.PendingJankStat> pendingStats =
+ mJankDataProcessor.getPendingJankStats();
+
+ String statKey = pendingStats.keySet().iterator().next();
+ JankDataProcessor.PendingJankStat pendingStat = pendingStats.get(statKey);
+
+ assertEquals(pendingStats.size(), 1);
+ // The same jankStats objects are merged twice, this should result in the frame counts being
+ // doubled.
+ assertEquals(jankStats.getJankyFrameCount() * 2, pendingStat.getJankyFrames());
+ assertEquals(jankStats.getTotalFrameCount() * 2, pendingStat.getTotalFrames());
+
+ int[] originalHistogramBuckets = jankStats.getFrameOverrunHistogram().getBucketCounters();
+ int[] frameOverrunBuckets = pendingStat.getFrameOverrunBuckets();
+
+ for (int i = 0; i < frameOverrunBuckets.length; i++) {
+ assertEquals(originalHistogramBuckets[i] * 2, frameOverrunBuckets[i]);
+ }
+ }
+
// TODO b/375005277 add tests that cover logging and releasing resources back to pool.
private long getTotalFramesCounted() {
@@ -276,4 +346,26 @@ public class JankDataProcessorTest {
return mockData;
}
+ private AppJankStats getAppJankStats() {
+ AppJankStats jankStats = new AppJankStats(
+ /*App Uid*/APP_ID,
+ /*Widget Id*/"test widget id",
+ /*Widget Category*/AppJankStats.SCROLL,
+ /*Widget State*/AppJankStats.SCROLLING,
+ /*Total Frames*/100,
+ /*Janky Frames*/25,
+ getOverrunHistogram()
+ );
+ return jankStats;
+ }
+
+ private FrameOverrunHistogram getOverrunHistogram() {
+ FrameOverrunHistogram overrunHistogram = new FrameOverrunHistogram();
+ overrunHistogram.addFrameOverrunMillis(-2);
+ overrunHistogram.addFrameOverrunMillis(1);
+ overrunHistogram.addFrameOverrunMillis(5);
+ overrunHistogram.addFrameOverrunMillis(25);
+ return overrunHistogram;
+ }
+
}
diff --git a/tests/CtsSurfaceControlTestsStaging/AndroidManifest.xml b/tests/CtsSurfaceControlTestsStaging/AndroidManifest.xml
index d8eb9ff37e78..da510fcd4d63 100644
--- a/tests/CtsSurfaceControlTestsStaging/AndroidManifest.xml
+++ b/tests/CtsSurfaceControlTestsStaging/AndroidManifest.xml
@@ -18,12 +18,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.view.surfacecontroltests">
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/>
+ <uses-permission android:name="android.permission.OBSERVE_PICTURE_PROFILES"/>
+
<application android:debuggable="true" android:testOnly="true">
<uses-library android:name="android.test.runner"/>
<activity
android:name=".GraphicsActivity"
android:exported="false">
</activity>
+ <activity android:name=".SurfaceControlPictureProfileTestActivity"
+ android:exported="true"
+ android:turnScreenOn="true"
+ android:showWhenLocked="true"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/CtsSurfaceControlTestsStaging/AndroidTest.xml b/tests/CtsSurfaceControlTestsStaging/AndroidTest.xml
index 5c0163fcfa7e..025bf378d82f 100644
--- a/tests/CtsSurfaceControlTestsStaging/AndroidTest.xml
+++ b/tests/CtsSurfaceControlTestsStaging/AndroidTest.xml
@@ -21,6 +21,9 @@
<option name="install-arg" value="-t" />
<option name="test-file-name" value="CtsSurfaceControlTestsStaging.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >
+ <option name="flag-value" value="media_tv/android.media.tv.flags.apply_picture_profiles=true" />
+ </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.view.surfacecontroltests" />
<option name="hidden-api-checks" value="false" />
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTest.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTest.java
new file mode 100644
index 000000000000..135f7102b8a9
--- /dev/null
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTest.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2024 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.view.surfacecontroltests;
+
+import static android.Manifest.permission.OBSERVE_PICTURE_PROFILES;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import static java.util.Arrays.stream;
+
+import android.hardware.HardwareBuffer;
+import android.media.quality.PictureProfileHandle;
+import android.os.Process;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlActivePicture;
+import android.view.SurfaceControlActivePictureListener;
+import android.view.SurfaceView;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.LongStream;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SurfaceControlPictureProfileTest {
+ private static final String TAG = SurfaceControlPictureProfileTest.class.getSimpleName();
+
+ private SurfaceControl[] mSurfaceControls;
+ private SurfaceControl mSurfaceControl;
+
+ @Rule
+ public ActivityTestRule<SurfaceControlPictureProfileTestActivity> mActivityRule =
+ new ActivityTestRule<>(SurfaceControlPictureProfileTestActivity.class);
+
+ @Before
+ public void setup() {
+ SurfaceView[] surfaceViews = mActivityRule.getActivity().getSurfaceViews();
+ mSurfaceControls = new SurfaceControl[surfaceViews.length];
+ // Create a child surface control so we can set a buffer, priority and profile handle all
+ // on one single surface control
+ for (int i = 0; i < mSurfaceControls.length; ++i) {
+ mSurfaceControls[i] = new SurfaceControl.Builder().setName("test").setHidden(false)
+ .setParent(surfaceViews[i].getSurfaceControl()).build();
+ }
+ mSurfaceControl = mSurfaceControls[0];
+ }
+
+ @Test
+ public void whenPictureProfileApplied_noExecptionsThrown() {
+ assumeTrue("Skipping test because feature flag is disabled",
+ com.android.graphics.libgui.flags.Flags.applyPictureProfiles());
+ // TODO(b/337330263): Call MediaQualityManager.getMaxPictureProfiles instead
+ assumeTrue("Skipping test because no picture profile support",
+ SurfaceControl.getMaxPictureProfiles() > 0);
+
+ // TODO(b/337330263): Load the handle from MediaQualityManager instead
+ PictureProfileHandle handle = new PictureProfileHandle(1);
+ HardwareBuffer buffer = getSolidBuffer(100, 100);
+ new SurfaceControl.Transaction()
+ .setBuffer(mSurfaceControl, buffer)
+ .setPictureProfileHandle(mSurfaceControl, handle)
+ .apply();
+ }
+
+ @Test
+ public void whenStartsListening_callsListener() {
+ assumeTrue("Skipping test because feature flag is disabled",
+ com.android.graphics.libgui.flags.Flags.applyPictureProfiles());
+ // TODO(b/337330263): Call MediaQualityManager.getMaxPictureProfiles instead
+ assumeTrue("Skipping test because no picture profile support",
+ SurfaceControl.getMaxPictureProfiles() > 0);
+
+ BlockingQueue<SurfaceControlActivePicture[]> picturesQueue = new LinkedBlockingQueue<>();
+ SurfaceControlActivePicture[] pictures;
+ SurfaceControlActivePictureListener listener = new SurfaceControlActivePictureListener() {
+ @Override
+ public void onActivePicturesChanged(SurfaceControlActivePicture[] pictures) {
+ picturesQueue.add(pictures);
+ }
+ };
+ // TODO(b/337330263): Call MediaQualityManager.addActivePictureListener instead
+ adoptShellPermissionIdentity(OBSERVE_PICTURE_PROFILES);
+ listener.startListening();
+ {
+ HardwareBuffer buffer = getSolidBuffer(100, 100);
+ new SurfaceControl.Transaction().setBuffer(mSurfaceControl, buffer).apply();
+ }
+
+ pictures = pollMs(picturesQueue, 200);
+ assertThat(pictures).isNotNull();
+ assertThat(pictures).isEmpty();
+ }
+
+ @Test
+ public void whenPictureProfileApplied_callsListenerWithUidAndProfileId() {
+ assumeTrue("Skipping test because feature flag is disabled",
+ com.android.graphics.libgui.flags.Flags.applyPictureProfiles());
+ // TODO(b/337330263): Call MediaQualityManager.getMaxPictureProfiles instead
+ assumeTrue("Skipping test because no picture profile support",
+ SurfaceControl.getMaxPictureProfiles() > 0);
+
+ BlockingQueue<SurfaceControlActivePicture[]> picturesQueue = new LinkedBlockingQueue<>();
+ SurfaceControlActivePicture[] pictures;
+ SurfaceControlActivePictureListener listener = new SurfaceControlActivePictureListener() {
+ @Override
+ public void onActivePicturesChanged(SurfaceControlActivePicture[] pictures) {
+ picturesQueue.add(pictures);
+ }
+ };
+ // TODO(b/337330263): Call MediaQualityManager.addActivePictureListener instead
+ adoptShellPermissionIdentity(OBSERVE_PICTURE_PROFILES);
+ listener.startListening();
+ {
+ HardwareBuffer buffer = getSolidBuffer(100, 100);
+ new SurfaceControl.Transaction().setBuffer(mSurfaceControl, buffer).apply();
+ }
+
+ pictures = pollMs(picturesQueue, 200);
+ assertThat(pictures).isNotNull();
+ assertThat(pictures).isEmpty();
+
+ // TODO(b/337330263): Load the handle from MediaQualityManager instead
+ PictureProfileHandle handle = new PictureProfileHandle(1);
+ HardwareBuffer buffer = getSolidBuffer(100, 100);
+ new SurfaceControl.Transaction()
+ .setBuffer(mSurfaceControl, buffer)
+ .setPictureProfileHandle(mSurfaceControl, handle)
+ .apply();
+
+ pictures = pollMs(picturesQueue, 200);
+ assertThat(pictures).isNotNull();
+ assertThat(stream(pictures).map(picture -> picture.getPictureProfileHandle().getId()))
+ .containsExactly(handle.getId());
+ assertThat(stream(pictures).map(picture -> picture.getOwnerUid()))
+ .containsExactly(Process.myUid());
+ }
+
+ @Test
+ public void whenPriorityChanges_callsListenerOnlyForLowerPriorityLayers() {
+ assumeTrue("Skipping test because feature flag is disabled",
+ com.android.graphics.libgui.flags.Flags.applyPictureProfiles());
+ // TODO(b/337330263): Call MediaQualityManager.getMaxPictureProfiles instead
+ int maxPictureProfiles = SurfaceControl.getMaxPictureProfiles();
+ assumeTrue("Skipping test because no picture profile support", maxPictureProfiles > 0);
+
+ BlockingQueue<SurfaceControlActivePicture[]> picturesQueue = new LinkedBlockingQueue<>();
+ SurfaceControlActivePicture[] pictures;
+ SurfaceControlActivePictureListener listener = new SurfaceControlActivePictureListener() {
+ @Override
+ public void onActivePicturesChanged(SurfaceControlActivePicture[] pictures) {
+ picturesQueue.add(pictures);
+ }
+ };
+ // TODO(b/337330263): Call MediaQualityManager.addActivePictureListener instead
+ adoptShellPermissionIdentity(OBSERVE_PICTURE_PROFILES);
+ listener.startListening();
+ {
+ HardwareBuffer buffer = getSolidBuffer(100, 100);
+ new SurfaceControl.Transaction().setBuffer(mSurfaceControl, buffer).apply();
+ }
+
+ pictures = pollMs(picturesQueue, 200);
+ assertThat(pictures).isNotNull();
+ assertThat(pictures).isEmpty();
+
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ // Use one more picture profile than allowed
+ for (int i = 0; i <= maxPictureProfiles; ++i) {
+ // Increase the number of surface views as necessary to support device configuration.
+ assertThat(i).isLessThan(mSurfaceControls.length);
+
+ // TODO(b/337330263): Load the handle from MediaQualityManager instead
+ PictureProfileHandle handle = new PictureProfileHandle(i + 1);
+ HardwareBuffer buffer = getSolidBuffer(100, 100);
+ transaction
+ .setBuffer(mSurfaceControls[i], buffer)
+ .setPictureProfileHandle(mSurfaceControls[i], handle)
+ .setContentPriority(mSurfaceControls[i], 0);
+ }
+ // Make the first layer low priority (high value)
+ transaction.setContentPriority(mSurfaceControls[0], 2);
+ // Make the last layer higher priority (lower value)
+ transaction.setContentPriority(mSurfaceControls[maxPictureProfiles], 1);
+ transaction.apply();
+
+ pictures = pollMs(picturesQueue, 200);
+ assertThat(pictures).isNotNull();
+ assertThat(stream(pictures).map(picture -> picture.getLayerId()))
+ .containsNoDuplicates();
+ // Expect all but the first layer to be listed as an active picture
+ assertThat(stream(pictures).map(picture -> picture.getPictureProfileHandle().getId()))
+ .containsExactlyElementsIn(toIterableRange(2, maxPictureProfiles + 1));
+
+ // Change priority and ensure that the first layer gets access
+ new SurfaceControl.Transaction().setContentPriority(mSurfaceControls[0], 0).apply();
+ pictures = pollMs(picturesQueue, 200);
+ assertThat(pictures).isNotNull();
+ // Expect all but the last layer to be listed as an active picture
+ assertThat(stream(pictures).map(picture -> picture.getPictureProfileHandle().getId()))
+ .containsExactlyElementsIn(toIterableRange(1, maxPictureProfiles));
+ }
+
+ private static SurfaceControlActivePicture[] pollMs(
+ BlockingQueue<SurfaceControlActivePicture[]> picturesQueue, int waitMs) {
+ SurfaceControlActivePicture[] pictures = null;
+ long nowMs = System.currentTimeMillis();
+ long endTimeMs = nowMs + waitMs;
+ while (nowMs < endTimeMs && pictures == null) {
+ try {
+ pictures = picturesQueue.poll(endTimeMs - nowMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // continue polling until timeout when interrupted
+ }
+ nowMs = System.currentTimeMillis();
+ }
+ return pictures;
+ }
+
+ Iterable<Long> toIterableRange(int start, int stop) {
+ return () -> LongStream.rangeClosed(start, stop).iterator();
+ }
+
+ private void adoptShellPermissionIdentity(String permission) {
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(permission);
+ }
+
+ private HardwareBuffer getSolidBuffer(int width, int height) {
+ // We can assume that RGBA_8888 format is supported for every platform.
+ return HardwareBuffer.create(
+ width, height, HardwareBuffer.RGBA_8888, 1, HardwareBuffer.USAGE_CPU_WRITE_OFTEN);
+ }
+}
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTestActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTestActivity.java
new file mode 100644
index 000000000000..42fcb261fa9d
--- /dev/null
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlPictureProfileTestActivity.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.view.surfacecontroltests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.SurfaceView;
+
+public class SurfaceControlPictureProfileTestActivity extends Activity {
+ private SurfaceView[] mSurfaceViews;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.picture_profile_test_layout);
+ mSurfaceViews = new SurfaceView[3];
+ mSurfaceViews[0] = (SurfaceView) findViewById(R.id.surfaceview1);
+ mSurfaceViews[1] = (SurfaceView) findViewById(R.id.surfaceview2);
+ mSurfaceViews[2] = (SurfaceView) findViewById(R.id.surfaceview3);
+ }
+
+ public SurfaceView getSurfaceView() {
+ return mSurfaceViews[0];
+ }
+
+ public SurfaceView[] getSurfaceViews() {
+ return mSurfaceViews;
+ }
+}
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/res/layout/picture_profile_test_layout.xml b/tests/CtsSurfaceControlTestsStaging/src/main/res/layout/picture_profile_test_layout.xml
new file mode 100644
index 000000000000..9aa25785d9f2
--- /dev/null
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/res/layout/picture_profile_test_layout.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <SurfaceView android:id="@+id/surfaceview1"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+ <SurfaceView android:id="@+id/surfaceview2"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+ <SurfaceView android:id="@+id/surfaceview3"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+</LinearLayout>
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
index 01cdbb810379..e59b6bd0617c 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
@@ -35,7 +35,7 @@ import org.junit.runners.Parameterized
/**
* Test the back and forward transition between 2 activities.
*
- * To run this test: `atest FlickerTestsAppLaunch:ActivitiesTransitionTest`
+ * To run this test: `atest FlickerTestsAppLaunch:ActivityTransitionTest`
*
* Actions:
* ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 3d9321c0b830..2bf8cc40d0a0 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -30,7 +30,7 @@ import org.junit.runners.Parameterized
/**
* Test cold launching an app from launcher
*
- * To run this test: `atest FlickerTestsAppLaunch:OpenAppColdFromIcon`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppFromIconColdTest`
*
* Actions:
* ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index 92075303028c..9c6bf9de37ce 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -30,7 +30,7 @@ import org.junit.runners.Parameterized
/**
* Test launching an app after cold opening camera
*
- * To run this test: `atest FlickerTestsAppLaunch:OpenAppAfterCameraTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppFromIntentColdAfterCameraTest`
*
* Notes: Some default assertions are inherited [OpenAppTransition]
*/
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index cbe7c3241df3..1a53a611c8d7 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -35,7 +35,7 @@ import org.junit.runners.Parameterized
/**
* Test cold launching an app from launcher
*
- * To run this test: `atest FlickerTestsAppLaunch:OpenAppColdTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppFromIntentColdTest`
*
* Actions:
* ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index b2941e70a2ed..14b6a18bfe2e 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -34,7 +34,7 @@ import org.junit.runners.Parameterized
/**
* Test warm launching an app from launcher
*
- * To run this test: `atest FlickerTestsAppLaunch:OpenAppWarmTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppFromIntentWarmTest`
*
* Actions:
* ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 4048e0c89619..f30fe96b9d05 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -41,7 +41,7 @@ import org.junit.runners.Parameterized
*
* This test assumes the device doesn't have AOD enabled
*
- * To run this test: `atest FlickerTestsAppLaunch:OpenAppNonResizeableTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppFromLockscreenViaIntentTest`
*
* Actions:
* ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 41423fd9eefe..9c552eb478d4 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -41,7 +41,7 @@ import org.junit.runners.Parameterized
/**
* Test cold launching camera from launcher by double pressing power button
*
- * To run this test: `atest FlickerTestsAppLaunch:OpenCameraOnDoubleClickPowerButton`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenCameraFromHomeOnDoubleClickPowerButtonTest`
*
* Actions:
* ```
@@ -140,14 +140,8 @@ class OpenCameraFromHomeOnDoubleClickPowerButtonTest(flicker: LegacyFlickerTest)
@Postsubmit
@Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- flicker.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry(
- LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
- listOf(CAMERA_BACKGROUND)
- )
- }
- }
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
@Postsubmit
@Test
@@ -170,12 +164,5 @@ class OpenCameraFromHomeOnDoubleClickPowerButtonTest(flicker: LegacyFlickerTest)
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
-
- private val CAMERA_BACKGROUND =
- ComponentNameMatcher(
- "Background for SurfaceView" +
- "[com.google.android.GoogleCamera/" +
- "com.google.android.apps.camera.legacy.app.activity.main.CameraActivity]"
- )
}
}
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
index ea61ad9d4481..e0900a64c52f 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
@@ -16,12 +16,14 @@
package com.android.server.wm.flicker.helpers
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.Context
import android.graphics.Insets
import android.graphics.Rect
import android.graphics.Region
import android.os.SystemClock
import android.platform.uiautomatorhelpers.DeviceHelpers
+import android.tools.PlatformConsts
import android.tools.device.apphelpers.IStandardAppHelper
import android.tools.helpers.SYSTEMUI_PACKAGE
import android.tools.traces.parsers.WindowManagerStateHelper
@@ -74,13 +76,28 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
.waitForAndVerify()
}
+ /** Launch an app and ensure it's moved to Desktop if it has not. */
+ fun enterDesktopMode(
+ wmHelper: WindowManagerStateHelper,
+ device: UiDevice,
+ motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH),
+ ) {
+ innerHelper.launchViaIntent(wmHelper)
+ if (!isInDesktopWindowingMode(wmHelper)) {
+ enterDesktopModeWithDrag(
+ wmHelper = wmHelper,
+ device = device,
+ motionEventHelper = motionEventHelper
+ )
+ }
+ }
+
/** Move an app to Desktop by dragging the app handle at the top. */
- fun enterDesktopWithDrag(
+ private fun enterDesktopModeWithDrag(
wmHelper: WindowManagerStateHelper,
device: UiDevice,
motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH)
) {
- innerHelper.launchViaIntent(wmHelper)
dragToDesktop(
wmHelper = wmHelper,
device = device,
@@ -139,14 +156,38 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
?: error("Unable to find resource $MINIMIZE_BUTTON_VIEW\n")
}
- fun minimizeDesktopApp(wmHelper: WindowManagerStateHelper, device: UiDevice) {
+ fun minimizeDesktopApp(wmHelper: WindowManagerStateHelper, device: UiDevice, isPip: Boolean = false) {
val caption = getCaptionForTheApp(wmHelper, device)
val minimizeButton = getMinimizeButtonForTheApp(caption)
minimizeButton.click()
wmHelper
.StateSyncBuilder()
.withAppTransitionIdle()
- .withWindowSurfaceDisappeared(innerHelper)
+ .apply {
+ if (isPip) withPipShown()
+ else
+ withWindowSurfaceDisappeared(innerHelper)
+ .withActivityState(innerHelper, PlatformConsts.STATE_STOPPED)
+ }
+ .waitForAndVerify()
+ }
+
+ private fun getHeaderEmptyView(caption: UiObject2?): UiObject2 {
+ return caption
+ ?.children
+ ?.find { it.resourceName.endsWith(HEADER_EMPTY_VIEW) }
+ ?: error("Unable to find resource $HEADER_EMPTY_VIEW\n")
+ }
+
+ /** Click on an existing window's header to bring it to the front. */
+ fun bringToFront(wmHelper: WindowManagerStateHelper, device: UiDevice) {
+ val caption = getCaptionForTheApp(wmHelper, device)
+ val openHeaderView = getHeaderEmptyView(caption)
+ openHeaderView.click()
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withTopVisibleApp(innerHelper)
.waitForAndVerify()
}
@@ -347,6 +388,14 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
waitForTransitionToFullscreen(wmHelper)
}
+ /** Maximize an app by dragging the app handle to the top drag zone. */
+ fun maximizeAppWithDragToTopDragZone(
+ wmHelper: WindowManagerStateHelper,
+ device: UiDevice,
+ ) {
+ dragAppWindowToTopDragZone(wmHelper, device)
+ }
+
private fun dragAppWindowToTopDragZone(wmHelper: WindowManagerStateHelper, device: UiDevice) {
val windowRect = wmHelper.getWindowRegion(innerHelper).bounds
val displayRect = getDisplayRect(wmHelper)
@@ -407,6 +456,10 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
return metricInsets.getInsetsIgnoringVisibility(typeMask)
}
+ // Requirement of DesktopWindowingMode is having a minimum of 1 app in WINDOWING_MODE_FREEFORM.
+ private fun isInDesktopWindowingMode(wmHelper: WindowManagerStateHelper) =
+ wmHelper.getWindow(innerHelper)?.windowingMode == WINDOWING_MODE_FREEFORM
+
private companion object {
val TIMEOUT: Duration = Duration.ofSeconds(3)
const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge
@@ -419,6 +472,7 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
const val SNAP_LEFT_BUTTON: String = "maximize_menu_snap_left_button"
const val SNAP_RIGHT_BUTTON: String = "maximize_menu_snap_right_button"
const val MINIMIZE_BUTTON_VIEW: String = "minimize_window"
+ const val HEADER_EMPTY_VIEW: String = "caption_handle"
val caption: BySelector
get() = By.res(SYSTEMUI_PACKAGE, CAPTION)
}
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 931e4f88aa8d..db4838ee6092 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -250,18 +250,13 @@ open class PipAppHelper(instrumentation: Instrumentation) :
wmHelper,
launchedAppComponentMatcherOverride,
action,
- stringExtras,
- waitConditionsBuilder =
- wmHelper
- .StateSyncBuilder()
- .add(ConditionsFactory.isWMStateComplete())
- .withAppTransitionIdle()
- .add(ConditionsFactory.hasPipWindow())
+ stringExtras
)
wmHelper
.StateSyncBuilder()
.withWindowSurfaceAppeared(this)
+ .add(ConditionsFactory.isWMStateComplete())
.withPipShown()
.waitForAndVerify()
}
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
index 69fde0168b14..9e488486e16a 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
@@ -65,10 +65,45 @@ constructor(
.waitForAndVerify()
}
+ fun startSingleAppMediaProjectionWithExtraIntent(
+ wmHelper: WindowManagerStateHelper,
+ targetApp: StandardAppHelper
+ ) {
+ clickStartMediaProjectionWithExtraIntentButton()
+ chooseSingleAppOption()
+ startScreenSharing()
+ selectTargetApp(targetApp.appName)
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
+ }
+
+ fun startSingleAppMediaProjectionFromRecents(
+ wmHelper: WindowManagerStateHelper,
+ targetApp: StandardAppHelper,
+ recentTasksIndex: Int = 0,
+ ) {
+ clickStartMediaProjectionButton()
+ chooseSingleAppOption()
+ startScreenSharing()
+ selectTargetAppRecent(recentTasksIndex)
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .waitForAndVerify()
+ }
+
private fun clickStartMediaProjectionButton() {
findObject(By.res(packageName, START_MEDIA_PROJECTION_BUTTON_ID)).also { it.click() }
}
+ private fun clickStartMediaProjectionWithExtraIntentButton() {
+ findObject(By.res(packageName, START_MEDIA_PROJECTION_NEW_INTENT_BUTTON_ID)).also { it.click() }
+ }
+
private fun chooseEntireScreenOption() {
findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
@@ -92,6 +127,13 @@ constructor(
findObject(By.text(targetAppName)).also { it.click() }
}
+ private fun selectTargetAppRecent(recentTasksIndex: Int) {
+ // Scroll to to find target app to launch then click app icon it to start capture
+ val recentsTasksRecycler =
+ findObject(By.res(SYSTEMUI_PACKAGE, MEDIA_PROJECTION_RECENT_TASKS))
+ recentsTasksRecycler.children[recentTasksIndex].also{ it.click() }
+ }
+
private fun chooseSingleAppOption() {
findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
@@ -116,8 +158,10 @@ constructor(
const val TIMEOUT: Long = 5000L
const val ACCEPT_RESOURCE_ID: String = "android:id/button1"
const val START_MEDIA_PROJECTION_BUTTON_ID: String = "button_start_mp"
+ const val START_MEDIA_PROJECTION_NEW_INTENT_BUTTON_ID: String = "button_start_mp_new_intent"
val SCREEN_SHARE_OPTIONS_PATTERN: Pattern =
Pattern.compile("$SYSTEMUI_PACKAGE:id/screen_share_mode_(options|spinner)")
+ const val MEDIA_PROJECTION_RECENT_TASKS: String = "media_projection_recent_tasks_recycler"
const val ENTIRE_SCREEN_STRING_RES_NAME: String =
"screen_share_permission_dialog_option_entire_screen"
const val SINGLE_APP_STRING_RES_NAME: String =
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
index 46f01e6c9752..c34d2003ef42 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
@@ -16,17 +16,27 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
android:orientation="vertical"
android:background="@android:color/holo_orange_light">
<Button
android:id="@+id/button_start_mp"
- android:layout_width="500dp"
- android:layout_height="500dp"
+ android:layout_margin="16dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="Start Media Projection"
android:textAppearance="?android:attr/textAppearanceLarge"/>
+ <Button
+ android:id="@+id/button_start_mp_new_intent"
+ android:layout_margin="16dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="Start Media Projection with extra intent"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout> \ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
index a24a48269d7c..b29b87450197 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
@@ -19,7 +19,8 @@ package com.android.server.wm.flicker.testapp;
import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.EXTRA_MESSENGER;
import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_SERVICE_DESTROYED;
import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_START_FOREGROUND_DONE;
-import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE_NORMAL;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE_EXTRA_INTENT;
import android.app.Activity;
import android.content.ComponentName;
@@ -71,13 +72,17 @@ public class StartMediaProjectionActivity extends Activity {
setContentView(R.layout.activity_start_media_projection);
Button startMediaProjectionButton = findViewById(R.id.button_start_mp);
+ Button startMediaProjectionButton2 = findViewById(R.id.button_start_mp_new_intent);
startMediaProjectionButton.setOnClickListener(v ->
- startActivityForResult(mService.createScreenCaptureIntent(), REQUEST_CODE));
+ startActivityForResult(mService.createScreenCaptureIntent(), REQUEST_CODE_NORMAL));
+ startMediaProjectionButton2.setOnClickListener(v ->
+ startActivityForResult(mService.createScreenCaptureIntent(),
+ REQUEST_CODE_EXTRA_INTENT));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode != REQUEST_CODE) {
+ if (requestCode != REQUEST_CODE_NORMAL && requestCode != REQUEST_CODE_EXTRA_INTENT) {
throw new IllegalStateException("Unknown request code: " + requestCode);
}
if (resultCode != RESULT_OK) {
@@ -85,6 +90,11 @@ public class StartMediaProjectionActivity extends Activity {
}
Log.d(TAG, "onActivityResult");
startMediaProjectionService(resultCode, data);
+ if (requestCode == REQUEST_CODE_EXTRA_INTENT) {
+ Intent startMain = new Intent(Intent.ACTION_MAIN);
+ startMain.addCategory(Intent.CATEGORY_HOME);
+ startActivity(startMain);
+ }
}
private void startMediaProjectionService(int resultCode, Intent resultData) {
@@ -122,7 +132,7 @@ public class StartMediaProjectionActivity extends Activity {
displayBounds.width(), displayBounds.height(), PixelFormat.RGBA_8888, 1);
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
- "DanielDisplay",
+ "TestDisplay",
displayBounds.width(),
displayBounds.height(),
DisplayMetrics.DENSITY_HIGH,
diff --git a/tests/Input/res/xml/bookmarks.xml b/tests/Input/res/xml/bookmarks.xml
index ba3f1871cdec..a4c898d8159a 100644
--- a/tests/Input/res/xml/bookmarks.xml
+++ b/tests/Input/res/xml/bookmarks.xml
@@ -14,47 +14,55 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<bookmarks>
+<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<!-- the key combinations for the following shortcuts must be in sync
with the key combinations sent by the test in KeyGestureControllerTests.java -->
<bookmark
role="android.app.role.BROWSER"
- shortcut="b" />
+ androidprv:keycode="KEYCODE_B"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CONTACTS"
- shortcut="c" />
+ androidprv:keycode="KEYCODE_C"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_EMAIL"
- shortcut="e" />
+ androidprv:keycode="KEYCODE_E"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CALENDAR"
- shortcut="k" />
+ androidprv:keycode="KEYCODE_K"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_MAPS"
- shortcut="m" />
+ androidprv:keycode="KEYCODE_M"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_MUSIC"
- shortcut="p" />
+ androidprv:keycode="KEYCODE_P"
+ androidprv:modifierState="META" />
<bookmark
role="android.app.role.SMS"
- shortcut="s" />
+ androidprv:keycode="KEYCODE_S"
+ androidprv:modifierState="META" />
<bookmark
category="android.intent.category.APP_CALCULATOR"
- shortcut="u" />
+ androidprv:keycode="KEYCODE_U"
+ androidprv:modifierState="META" />
<bookmark
role="android.app.role.BROWSER"
- shortcut="b"
- shift="true" />
+ androidprv:keycode="KEYCODE_B"
+ androidprv:modifierState="META|SHIFT" />
<bookmark
category="android.intent.category.APP_CONTACTS"
- shortcut="c"
+ androidprv:keycode="KEYCODE_C"
shift="true" />
<bookmark
package="com.test"
class="com.test.BookmarkTest"
- shortcut="j"
+ androidprv:keycode="KEYCODE_J"
shift="true" />
</bookmarks> \ No newline at end of file
diff --git a/tests/Input/res/xml/bookmarks_legacy.xml b/tests/Input/res/xml/bookmarks_legacy.xml
new file mode 100644
index 000000000000..8bacf490ad9e
--- /dev/null
+++ b/tests/Input/res/xml/bookmarks_legacy.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2024 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.
+ -->
+<bookmarks>
+ <!-- The key combinations for the following shortcuts are legacy way defining bookmarks and we
+ should prefer new way of defining bookmarks as shown in {@link bookmarks.xml} -->
+ <bookmark
+ role="android.app.role.BROWSER"
+ shortcut="b" />
+ <bookmark
+ category="android.intent.category.APP_CONTACTS"
+ shortcut="c" />
+ <bookmark
+ category="android.intent.category.APP_EMAIL"
+ shortcut="e" />
+ <bookmark
+ category="android.intent.category.APP_CALENDAR"
+ shortcut="k" />
+ <bookmark
+ category="android.intent.category.APP_MAPS"
+ shortcut="m" />
+ <bookmark
+ category="android.intent.category.APP_MUSIC"
+ shortcut="p" />
+ <bookmark
+ role="android.app.role.SMS"
+ shortcut="s" />
+ <bookmark
+ category="android.intent.category.APP_CALCULATOR"
+ shortcut="u" />
+
+ <bookmark
+ role="android.app.role.BROWSER"
+ shortcut="b"
+ shift="true" />
+
+ <bookmark
+ category="android.intent.category.APP_CONTACTS"
+ shortcut="c"
+ shift="true" />
+
+ <bookmark
+ package="com.test"
+ class="com.test.BookmarkTest"
+ shortcut="j"
+ shift="true" />
+</bookmarks> \ No newline at end of file
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 09a686ca2c3f..36a89f95aa6f 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -115,13 +115,11 @@ class KeyGestureControllerTests {
private lateinit var iInputManager: IInputManager
@Mock
- private lateinit var resources: Resources
-
- @Mock
private lateinit var packageManager: PackageManager
private var currentPid = 0
private lateinit var context: Context
+ private lateinit var resources: Resources
private lateinit var keyGestureController: KeyGestureController
private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
private lateinit var testLooper: TestLooper
@@ -130,6 +128,7 @@ class KeyGestureControllerTests {
@Before
fun setup() {
context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+ resources = Mockito.spy(context.resources)
setupInputDevices()
setupBehaviors()
testLooper = TestLooper()
@@ -146,10 +145,6 @@ class KeyGestureControllerTests {
private fun setupBehaviors() {
Mockito.`when`(SystemProperties.get("ro.debuggable")).thenReturn("1")
Mockito.`when`(resources.getBoolean(R.bool.config_enableScreenshotChord)).thenReturn(true)
- val testBookmarks: XmlResourceParser = context.resources.getXml(
- com.android.test.input.R.xml.bookmarks
- )
- Mockito.`when`(resources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks)
Mockito.`when`(context.resources).thenReturn(resources)
Mockito.`when`(packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH))
.thenReturn(true)
@@ -158,6 +153,11 @@ class KeyGestureControllerTests {
Mockito.`when`(context.packageManager).thenReturn(packageManager)
}
+ private fun setupBookmarks(bookmarkRes: Int) {
+ val testBookmarks: XmlResourceParser = context.resources.getXml(bookmarkRes)
+ Mockito.`when`(resources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks)
+ }
+
private fun setupInputDevices() {
val correctIm = context.getSystemService(InputManager::class.java)!!
val virtualDevice = correctIm.getInputDevice(KeyCharacterMap.VIRTUAL_KEYBOARD)!!
@@ -604,45 +604,6 @@ class KeyGestureControllerTests {
AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALCULATOR)
),
TestData(
- "META + SHIFT + B -> Launch Default Browser",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_SHIFT_LEFT,
- KeyEvent.KEYCODE_B
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
- intArrayOf(KeyEvent.KEYCODE_B),
- KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
- AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER)
- ),
- TestData(
- "META + SHIFT + C -> Launch Default Contacts",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_SHIFT_LEFT,
- KeyEvent.KEYCODE_C
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
- intArrayOf(KeyEvent.KEYCODE_C),
- KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
- AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS)
- ),
- TestData(
- "META + SHIFT + J -> Launch Target Activity",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_SHIFT_LEFT,
- KeyEvent.KEYCODE_J
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
- intArrayOf(KeyEvent.KEYCODE_J),
- KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
- AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest")
- ),
- TestData(
"META + CTRL + DEL -> Trigger Bug Report",
intArrayOf(
KeyEvent.KEYCODE_META_LEFT,
@@ -715,47 +676,47 @@ class KeyGestureControllerTests {
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "ALT + [ -> Resizes a task to fit the left half of the screen",
+ "META + [ -> Resizes a task to fit the left half of the screen",
intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_META_LEFT,
KeyEvent.KEYCODE_LEFT_BRACKET
),
KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET),
- KeyEvent.META_ALT_ON,
+ KeyEvent.META_META_ON,
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "ALT + ] -> Resizes a task to fit the right half of the screen",
+ "META + ] -> Resizes a task to fit the right half of the screen",
intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_META_LEFT,
KeyEvent.KEYCODE_RIGHT_BRACKET
),
KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET),
- KeyEvent.META_ALT_ON,
+ KeyEvent.META_META_ON,
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "ALT + '=' -> Maximizes a task to fit the screen",
+ "META + '=' -> Toggles maximization of a task to maximized and restore its bounds",
intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_META_LEFT,
KeyEvent.KEYCODE_EQUALS
),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
intArrayOf(KeyEvent.KEYCODE_EQUALS),
- KeyEvent.META_ALT_ON,
+ KeyEvent.META_META_ON,
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "ALT + '-' -> Restores a task size to its previous bounds",
+ "META + '-' -> Minimizes a freeform task",
intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_META_LEFT,
KeyEvent.KEYCODE_MINUS
),
- KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
intArrayOf(KeyEvent.KEYCODE_MINUS),
- KeyEvent.META_ALT_ON,
+ KeyEvent.META_META_ON,
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
@@ -866,6 +827,139 @@ class KeyGestureControllerTests {
}
@Keep
+ private fun bookmarkArguments(): Array<TestData> {
+ return arrayOf(
+ TestData(
+ "META + B -> Launch Default Browser",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_B),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_B),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER)
+ ),
+ TestData(
+ "META + C -> Launch Default Contacts",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_C),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_C),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS)
+ ),
+ TestData(
+ "META + E -> Launch Default Email",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_E),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_E),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_EMAIL)
+ ),
+ TestData(
+ "META + K -> Launch Default Calendar",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_K),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_K),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALENDAR)
+ ),
+ TestData(
+ "META + M -> Launch Default Maps",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_M),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_M),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MAPS)
+ ),
+ TestData(
+ "META + P -> Launch Default Music",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_P),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_P),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MUSIC)
+ ),
+ TestData(
+ "META + S -> Launch Default SMS",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_S),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_S),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_SMS)
+ ),
+ TestData(
+ "META + U -> Launch Default Calculator",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_U),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_U),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALCULATOR)
+ ),
+ TestData(
+ "META + SHIFT + B -> Launch Default Browser",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_SHIFT_LEFT,
+ KeyEvent.KEYCODE_B
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_B),
+ KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER)
+ ),
+ TestData(
+ "META + SHIFT + C -> Launch Default Contacts",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_SHIFT_LEFT,
+ KeyEvent.KEYCODE_C
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_C),
+ KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS)
+ ),
+ TestData(
+ "META + SHIFT + J -> Launch Target Activity",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_SHIFT_LEFT,
+ KeyEvent.KEYCODE_J
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_J),
+ KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+ AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest")
+ )
+ )
+ }
+
+ @Test
+ @Parameters(method = "bookmarkArguments")
+ fun testBookmarks(test: TestData) {
+ setupBookmarks(com.android.test.input.R.xml.bookmarks)
+ setupKeyGestureController()
+ testKeyGestureInternal(test)
+ }
+
+ @Test
+ @Parameters(method = "bookmarkArguments")
+ fun testBookmarksLegacy(test: TestData) {
+ setupBookmarks(com.android.test.input.R.xml.bookmarks_legacy)
+ setupKeyGestureController()
+ testKeyGestureInternal(test)
+ }
+
+ @Keep
private fun systemKeysTestArguments(): Array<TestData> {
return arrayOf(
TestData(
@@ -1267,7 +1361,7 @@ class KeyGestureControllerTests {
@Parameters(method = "systemGesturesTestArguments_forKeyCombinations")
@EnableFlags(
com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
- com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER_MULTI_PRESS_GESTURES
+ com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER_MULTI_KEY_GESTURES
)
fun testKeyCombinationGestures(test: TestData) {
setupKeyGestureController()
diff --git a/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
index 58fb4e1ed103..938e2f8a3611 100644
--- a/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
@@ -19,6 +19,7 @@ package com.android.server.input
import android.animation.ValueAnimator
import android.content.Context
import android.content.ContextWrapper
+import android.content.res.Resources
import android.graphics.Color
import android.hardware.input.IKeyboardBacklightListener
import android.hardware.input.IKeyboardBacklightState
@@ -28,11 +29,12 @@ import android.os.UEventObserver
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
import android.view.InputDevice
+import android.util.TypedValue
import androidx.test.annotation.UiThreadTest
import androidx.test.core.app.ApplicationProvider
+import com.android.internal.R
import com.android.server.input.KeyboardBacklightController.DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL
import com.android.server.input.KeyboardBacklightController.MAX_BRIGHTNESS_CHANGE_STEPS
-import com.android.server.input.KeyboardBacklightController.USER_INACTIVITY_THRESHOLD_MILLIS
import com.android.test.input.MockInputManagerRule
import java.io.FileNotFoundException
import java.io.FileOutputStream
@@ -49,6 +51,7 @@ import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.eq
import org.mockito.Mockito.spy
@@ -94,6 +97,7 @@ class KeyboardBacklightControllerTests {
const val LIGHT_ID = 2
const val SECOND_LIGHT_ID = 3
const val MAX_BRIGHTNESS = 255
+ const val USER_INACTIVITY_THRESHOLD_MILLIS = 30000
}
@get:Rule
@@ -105,6 +109,8 @@ class KeyboardBacklightControllerTests {
private lateinit var native: NativeInputManagerService
@Mock
private lateinit var uEventManager: UEventManager
+ @Mock
+ private lateinit var resources: Resources
private lateinit var keyboardBacklightController: KeyboardBacklightController
private lateinit var context: Context
private lateinit var dataStore: PersistentDataStore
@@ -117,6 +123,7 @@ class KeyboardBacklightControllerTests {
@Before
fun setup() {
context = spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+ `when`(context.resources).thenReturn(resources)
dataStore = PersistentDataStore(object : PersistentDataStore.Injector() {
override fun openRead(): InputStream? {
throw FileNotFoundException()
@@ -129,6 +136,7 @@ class KeyboardBacklightControllerTests {
override fun finishWrite(fos: FileOutputStream?, success: Boolean) {}
})
testLooper = TestLooper()
+ setupConfig()
keyboardBacklightController = KeyboardBacklightController(context, native, dataStore,
testLooper.looper, FakeAnimatorFactory(), uEventManager)
val inputManager = InputManager(context)
@@ -147,7 +155,31 @@ class KeyboardBacklightControllerTests {
sysfsNodeChanges++
}
}
-
+ private fun setupConfig() {
+ val brightnessValues = intArrayOf(100, 200, 0)
+ val decreaseThresholds = intArrayOf(-1, 900, 1900)
+ val increaseThresholds = intArrayOf(1000, 2000, -1)
+ `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightBrightnessValues))
+ .thenReturn(brightnessValues)
+ `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightDecreaseLuxThreshold))
+ .thenReturn(decreaseThresholds)
+ `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightIncreaseLuxThreshold))
+ .thenReturn(increaseThresholds)
+ `when`(resources.getInteger(R.integer.config_keyboardBacklightTimeoutMs))
+ .thenReturn(USER_INACTIVITY_THRESHOLD_MILLIS)
+ `when`(
+ resources.getValue(
+ eq(R.dimen.config_autoKeyboardBrightnessSmoothingConstant),
+ any(TypedValue::class.java),
+ anyBoolean()
+ )
+ ).then {
+ val args = it.arguments
+ val outValue = args[1] as TypedValue
+ outValue.data = java.lang.Float.floatToRawIntBits(1.0f)
+ Unit
+ }
+ }
@Test
fun testKeyboardBacklightIncrementDecrement() {
KeyboardBacklightFlags(
@@ -365,7 +397,7 @@ class KeyboardBacklightControllerTests {
lightColorMap[LIGHT_ID]
)
- testLooper.moveTimeForward(USER_INACTIVITY_THRESHOLD_MILLIS + 1000)
+ testLooper.moveTimeForward((USER_INACTIVITY_THRESHOLD_MILLIS + 1000).toLong())
testLooper.dispatchNext()
assertEquals(
"Keyboard backlight level should be turned off after inactivity",
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index 91483eb41387..8be74eaccd20 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -37,7 +37,7 @@ android_test {
"truth",
] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
"true": [
- "service-crashrecovery.impl",
+ "service-crashrecovery-pre-jarjar",
"framework-crashrecovery.impl",
],
default: [],
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
index 05a0f8f34337..af87bf724a30 100644
--- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -138,7 +138,8 @@ public class CrashRecoveryTest {
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG,
- Manifest.permission.WRITE_DEVICE_CONFIG);
+ Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG);
mTestLooper = new TestLooper();
mSpyContext = spy(InstrumentationRegistry.getContext());
when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
@@ -1013,7 +1014,7 @@ public class CrashRecoveryTest {
triggerFailureCount = 1;
}
for (int i = 0; i < triggerFailureCount; i++) {
- watchdog.onPackageFailure(packages, failureReason);
+ watchdog.notifyPackageFailure(packages, failureReason);
}
mTestLooper.dispatchAll();
if (Flags.recoverabilityDetection()) {
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index a540a8d567a1..5a8a6bedf9eb 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -152,7 +152,8 @@ public class PackageWatchdogTest {
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG,
- Manifest.permission.WRITE_DEVICE_CONFIG);
+ Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG);
mTestLooper = new TestLooper();
mSpyContext = spy(InstrumentationRegistry.getContext());
when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
@@ -391,7 +392,7 @@ public class PackageWatchdogTest {
// Then fail APP_A below the threshold
for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) {
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
}
@@ -1024,14 +1025,14 @@ public class PackageWatchdogTest {
watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
// Fail APP_A below the threshold which should not trigger package failures
for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) {
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
}
mTestLooper.dispatchAll();
assertThat(observer.mHealthCheckFailedPackages).isEmpty();
// One more to trigger the package failure
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
mTestLooper.dispatchAll();
assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
@@ -1050,10 +1051,10 @@ public class PackageWatchdogTest {
TestObserver observer = new TestObserver(OBSERVER_NAME_1);
watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE);
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1);
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
mTestLooper.dispatchAll();
@@ -1061,10 +1062,10 @@ public class PackageWatchdogTest {
// DEFAULT_TRIGGER_FAILURE_DURATION_MS.
assertThat(observer.mHealthCheckFailedPackages).isEmpty();
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS - 1);
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
mTestLooper.dispatchAll();
@@ -1128,17 +1129,17 @@ public class PackageWatchdogTest {
watchdog.startObservingHealth(observer, Arrays.asList(APP_A), Long.MAX_VALUE);
// Raise 2 failures at t=0 and t=900 respectively
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
moveTimeForwardAndDispatch(900);
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
// Raise 2 failures at t=1100
moveTimeForwardAndDispatch(200);
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
mTestLooper.dispatchAll();
@@ -1432,13 +1433,13 @@ public class PackageWatchdogTest {
TestObserver observer = new TestObserver(OBSERVER_NAME_1);
watchdog.startObservingHealth(observer, List.of(APP_A), SHORT_DURATION);
for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) {
- watchdog.onPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
}
mTestLooper.dispatchAll();
assertThat(observer.mMitigatedPackages).isEmpty();
watchdog.startObservingHealth(observer, List.of(APP_A), LONG_DURATION);
- watchdog.onPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
+ watchdog.notifyPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
mTestLooper.dispatchAll();
assertThat(observer.mMitigatedPackages).isEqualTo(List.of(APP_A));
@@ -1736,7 +1737,7 @@ public class PackageWatchdogTest {
triggerFailureCount = 1;
}
for (int i = 0; i < triggerFailureCount; i++) {
- watchdog.onPackageFailure(packages, failureReason);
+ watchdog.notifyPackageFailure(packages, failureReason);
}
mTestLooper.dispatchAll();
if (Flags.recoverabilityDetection()) {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
index 314e95229d29..a6aa877c9097 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
@@ -82,7 +82,8 @@ public class NetworkStagedRollbackTest {
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.FORCE_STOP_PACKAGES,
- Manifest.permission.WRITE_DEVICE_CONFIG);
+ Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG);
}
/**
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 4cddcfeb91dc..32deb2e8fdfc 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -70,7 +70,8 @@ public class StagedRollbackTest {
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.FORCE_STOP_PACKAGES,
- Manifest.permission.WRITE_DEVICE_CONFIG);
+ Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG);
}
/**
diff --git a/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
index 8913e8c1996e..05308464cb9b 100644
--- a/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
@@ -89,7 +89,7 @@ public class LegacyProtoLogImplTest {
//noinspection ResultOfMethodCallIgnored
mFile.delete();
mProtoLog = new LegacyProtoLogImpl(mFile, mViewerConfigFilename,
- 1024 * 1024, mReader, 1024, () -> {});
+ 1024 * 1024, mReader, 1024, (instance) -> {});
}
@After
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
index 2692e12c57ed..ed256e72b415 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -40,6 +41,7 @@ import android.tools.traces.io.ResultWriter;
import android.tools.traces.monitors.PerfettoTraceMonitor;
import android.tools.traces.protolog.ProtoLogTrace;
import android.tracing.perfetto.DataSource;
+import android.tracing.perfetto.DataSourceParams;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -57,6 +59,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
import perfetto.protos.Protolog;
import perfetto.protos.ProtologCommon;
@@ -93,14 +96,14 @@ public class ProcessedPerfettoProtoLogImplTest {
);
private static ProtoLogConfigurationService sProtoLogConfigurationService;
+ private static ProtoLogDataSource sTestDataSource;
private static PerfettoProtoLogImpl sProtoLog;
private static Protolog.ProtoLogViewerConfig.Builder sViewerConfigBuilder;
- private static Runnable sCacheUpdater;
+ private static ProtoLogCacheUpdater sCacheUpdater;
private static ProtoLogViewerConfigReader sReader;
- public ProcessedPerfettoProtoLogImplTest() throws IOException {
- }
+ public ProcessedPerfettoProtoLogImplTest() throws IOException { }
@BeforeClass
public static void setUp() throws Exception {
@@ -153,12 +156,18 @@ public class ProcessedPerfettoProtoLogImplTest {
.thenAnswer(it -> new AutoClosableProtoInputStream(
sViewerConfigBuilder.build().toByteArray()));
- sCacheUpdater = () -> {};
+ sCacheUpdater = (instance) -> {};
sReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
+ sTestDataSource = new ProtoLogDataSource(TEST_PROTOLOG_DATASOURCE_NAME);
+ DataSourceParams params =
+ new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(
+ DataSourceParams
+ .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
+ .build();
+ sTestDataSource.register(params);
+ busyWaitForDataSourceRegistration(TEST_PROTOLOG_DATASOURCE_NAME);
- final ProtoLogDataSourceBuilder dataSourceBuilder =
- (onStart, onFlush, onStop) -> new ProtoLogDataSource(
- onStart, onFlush, onStop, TEST_PROTOLOG_DATASOURCE_NAME);
final ViewerConfigFileTracer tracer = (dataSource, viewerConfigFilePath) -> {
Utils.dumpViewerConfig(dataSource, () -> {
if (!viewerConfigFilePath.equals(MOCK_VIEWER_CONFIG_FILE)) {
@@ -169,14 +178,13 @@ public class ProcessedPerfettoProtoLogImplTest {
});
};
sProtoLogConfigurationService =
- new ProtoLogConfigurationServiceImpl(dataSourceBuilder, tracer);
+ new ProtoLogConfigurationServiceImpl(sTestDataSource, tracer);
- sProtoLog = new ProcessedPerfettoProtoLogImpl(
+ sProtoLog = new ProcessedPerfettoProtoLogImpl(sTestDataSource,
MOCK_VIEWER_CONFIG_FILE, viewerConfigInputStreamProvider, sReader,
- () -> sCacheUpdater.run(), TestProtoLogGroup.values(), dataSourceBuilder,
+ (instance) -> sCacheUpdater.update(instance), TestProtoLogGroup.values(),
sProtoLogConfigurationService);
-
- busyWaitForDataSourceRegistration(TEST_PROTOLOG_DATASOURCE_NAME);
+ sProtoLog.enable();
}
@Before
@@ -604,7 +612,7 @@ public class ProcessedPerfettoProtoLogImplTest {
@Test
public void cacheIsUpdatedWhenTracesStartAndStop() {
final AtomicInteger cacheUpdateCallCount = new AtomicInteger(0);
- sCacheUpdater = cacheUpdateCallCount::incrementAndGet;
+ sCacheUpdater = (instance) -> cacheUpdateCallCount.incrementAndGet();
PerfettoTraceMonitor traceMonitor1 = PerfettoTraceMonitor.newBuilder()
.enableProtoLog(true,
@@ -858,6 +866,39 @@ public class ProcessedPerfettoProtoLogImplTest {
.isEqualTo("This message should also be logged 567");
}
+ @Test
+ public void enablesLogGroupAfterLoadingConfig() {
+ sProtoLog.stopLoggingToLogcat(
+ new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+ Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+
+ doAnswer((Answer<Void>) invocation -> {
+ // logToLogcat is still false before we laod the viewer config
+ Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+ return null;
+ }).when(sReader).unloadViewerConfig(any(), any());
+
+ sProtoLog.startLoggingToLogcat(
+ new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+ Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isTrue();
+ }
+
+ @Test
+ public void disablesLogGroupBeforeUnloadingConfig() {
+ sProtoLog.startLoggingToLogcat(
+ new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+ Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isTrue();
+
+ doAnswer((Answer<Void>) invocation -> {
+ // Already set logToLogcat to false by the time we unload the config
+ Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+ return null;
+ }).when(sReader).unloadViewerConfig(any(), any());
+ sProtoLog.stopLoggingToLogcat(
+ new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+ Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+ }
+
private enum TestProtoLogGroup implements IProtoLogGroup {
TEST_GROUP(true, true, false, "TEST_TAG");
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
index ce519b7a1576..49249333b72b 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
@@ -67,9 +67,6 @@ public class ProtologDataSourceTest {
@Test
public void allEnabledTraceMode() {
- final ProtoLogDataSource ds =
- new ProtoLogDataSource((idx, c) -> {}, () -> {}, (idx, c) -> {});
-
final ProtoLogDataSource.TlsState tlsState = createTlsState(
DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
ProtologConfig.ProtoLogConfig.newBuilder()
@@ -154,8 +151,7 @@ public class ProtologDataSourceTest {
private ProtoLogDataSource.TlsState createTlsState(
DataSourceConfigOuterClass.DataSourceConfig config) {
- final ProtoLogDataSource ds =
- Mockito.spy(new ProtoLogDataSource((idx, c) -> {}, () -> {}, (idx, c) -> {}));
+ final ProtoLogDataSource ds = Mockito.spy(new ProtoLogDataSource());
ProtoInputStream configStream = new ProtoInputStream(config.toByteArray());
final ProtoLogDataSource.Instance dsInstance = Mockito.spy(
diff --git a/tests/broadcasts/OWNERS b/tests/broadcasts/OWNERS
deleted file mode 100644
index d2e1f815e8dc..000000000000
--- a/tests/broadcasts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 316181
-include platform/frameworks/base:/BROADCASTS_OWNERS
diff --git a/tests/broadcasts/unit/Android.bp b/tests/broadcasts/unit/Android.bp
deleted file mode 100644
index 47166a713580..000000000000
--- a/tests/broadcasts/unit/Android.bp
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Copyright (C) 2024 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 {
- // 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"],
- default_team: "trendy_team_framework_backstage_power",
-}
-
-android_test {
- name: "BroadcastUnitTests",
- srcs: ["src/**/*.java"],
- defaults: [
- "modules-utils-extended-mockito-rule-defaults",
- ],
- static_libs: [
- "androidx.test.runner",
- "androidx.test.rules",
- "androidx.test.ext.junit",
- "mockito-target-extended-minus-junit4",
- "truth",
- "flag-junit",
- "android.app.flags-aconfig-java",
- ],
- certificate: "platform",
- platform_apis: true,
- test_suites: ["device-tests"],
-}
diff --git a/tests/broadcasts/unit/AndroidManifest.xml b/tests/broadcasts/unit/AndroidManifest.xml
deleted file mode 100644
index e9c5248e4d98..000000000000
--- a/tests/broadcasts/unit/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2024 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.broadcasts.unit" >
-
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.broadcasts.unit"
- android:label="Broadcasts Unit Tests"/>
-</manifest> \ No newline at end of file
diff --git a/tests/broadcasts/unit/AndroidTest.xml b/tests/broadcasts/unit/AndroidTest.xml
deleted file mode 100644
index b91e4783b69e..000000000000
--- a/tests/broadcasts/unit/AndroidTest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!-- Copyright (C) 2024 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.
--->
-<configuration description="Runs Broadcasts tests">
- <option name="test-suite-tag" value="apct" />
- <option name="test-tag" value="BroadcastUnitTests" />
-
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="BroadcastUnitTests.apk" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.broadcasts.unit" />
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="hidden-api-checks" value="false"/>
- </test>
-</configuration> \ No newline at end of file
diff --git a/tests/broadcasts/unit/TEST_MAPPING b/tests/broadcasts/unit/TEST_MAPPING
deleted file mode 100644
index 8919fdcd7a3f..000000000000
--- a/tests/broadcasts/unit/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "presubmit": [
- {
- "name": "BroadcastUnitTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
- ]
-}
diff --git a/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java
deleted file mode 100644
index b7c412dea999..000000000000
--- a/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app;
-
-import static android.content.Intent.ACTION_BATTERY_CHANGED;
-import static android.content.Intent.ACTION_DEVICE_STORAGE_LOW;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.Bundle;
-import android.os.SystemProperties;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
-import android.util.ArrayMap;
-
-import androidx.annotation.GuardedBy;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.modules.utils.testing.ExtendedMockitoRule;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-@EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class BroadcastStickyCacheTest {
- @ClassRule
- public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
- @Rule
- public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
-
- @Rule
- public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
- .mockStatic(SystemProperties.class)
- .build();
-
- private static final String PROP_KEY_BATTERY_CHANGED = BroadcastStickyCache.getKey(
- ACTION_BATTERY_CHANGED);
-
- private final TestSystemProps mTestSystemProps = new TestSystemProps();
-
- @Before
- public void setUp() {
- doAnswer(invocation -> {
- final String name = invocation.getArgument(0);
- final long value = Long.parseLong(invocation.getArgument(1));
- mTestSystemProps.add(name, value);
- return null;
- }).when(() -> SystemProperties.set(anyString(), anyString()));
- doAnswer(invocation -> {
- final String name = invocation.getArgument(0);
- final TestSystemProps.Handle testHandle = mTestSystemProps.query(name);
- if (testHandle == null) {
- return null;
- }
- final SystemProperties.Handle handle = Mockito.mock(SystemProperties.Handle.class);
- doAnswer(handleInvocation -> testHandle.getLong(-1)).when(handle).getLong(anyLong());
- return handle;
- }).when(() -> SystemProperties.find(anyString()));
- }
-
- @After
- public void tearDown() {
- mTestSystemProps.clear();
- BroadcastStickyCache.clearForTest();
- }
-
- @Test
- public void testUseCache_nullFilter() {
- assertThat(BroadcastStickyCache.useCache(null)).isEqualTo(false);
- }
-
- @Test
- public void testUseCache_noActions() {
- final IntentFilter filter = new IntentFilter();
- assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
- }
-
- @Test
- public void testUseCache_multipleActions() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_DEVICE_STORAGE_LOW);
- filter.addAction(ACTION_BATTERY_CHANGED);
- assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
- }
-
- @Test
- public void testUseCache_valueNotSet() {
- final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
- assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
- }
-
- @Test
- public void testUseCache() {
- final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
- final Intent intent = new Intent(ACTION_BATTERY_CHANGED)
- .putExtra(BatteryManager.EXTRA_LEVEL, 90);
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
- BroadcastStickyCache.add(filter, intent);
- assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(true);
- }
-
- @Test
- public void testUseCache_versionMismatch() {
- final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
- final Intent intent = new Intent(ACTION_BATTERY_CHANGED)
- .putExtra(BatteryManager.EXTRA_LEVEL, 90);
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
- BroadcastStickyCache.add(filter, intent);
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-
- assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
- }
-
- @Test
- public void testAdd() {
- final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
- Intent intent = new Intent(ACTION_BATTERY_CHANGED)
- .putExtra(BatteryManager.EXTRA_LEVEL, 90);
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
- BroadcastStickyCache.add(filter, intent);
- assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(true);
- Intent actualIntent = BroadcastStickyCache.getIntentUnchecked(filter);
- assertThat(actualIntent).isNotNull();
- assertEquals(actualIntent, intent);
-
- intent = new Intent(ACTION_BATTERY_CHANGED)
- .putExtra(BatteryManager.EXTRA_LEVEL, 99);
- BroadcastStickyCache.add(filter, intent);
- actualIntent = BroadcastStickyCache.getIntentUnchecked(filter);
- assertThat(actualIntent).isNotNull();
- assertEquals(actualIntent, intent);
- }
-
- @Test
- public void testIncrementVersion_propExists() {
- SystemProperties.set(PROP_KEY_BATTERY_CHANGED, String.valueOf(100));
-
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(101);
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(102);
- }
-
- @Test
- public void testIncrementVersion_propNotExists() {
- // Verify that the property doesn't exist
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
-
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(1);
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(2);
- }
-
- @Test
- public void testIncrementVersionIfExists_propExists() {
- BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-
- BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(2);
- BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(3);
- }
-
- @Test
- public void testIncrementVersionIfExists_propNotExists() {
- // Verify that the property doesn't exist
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
-
- BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
- // Verify that property is not added as part of the querying.
- BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
- assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
- }
-
- private void assertEquals(Intent actualIntent, Intent expectedIntent) {
- assertThat(actualIntent.getAction()).isEqualTo(expectedIntent.getAction());
- assertEquals(actualIntent.getExtras(), expectedIntent.getExtras());
- }
-
- private void assertEquals(Bundle actualExtras, Bundle expectedExtras) {
- assertWithMessage("Extras expected=%s, actual=%s", expectedExtras, actualExtras)
- .that(actualExtras.kindofEquals(expectedExtras)).isTrue();
- }
-
- private static final class TestSystemProps {
- @GuardedBy("mSysProps")
- private final ArrayMap<String, Long> mSysProps = new ArrayMap<>();
-
- public void add(String name, long value) {
- synchronized (mSysProps) {
- mSysProps.put(name, value);
- }
- }
-
- public long get(String name, long defaultValue) {
- synchronized (mSysProps) {
- final int idx = mSysProps.indexOfKey(name);
- return idx >= 0 ? mSysProps.valueAt(idx) : defaultValue;
- }
- }
-
- public Handle query(String name) {
- synchronized (mSysProps) {
- return mSysProps.containsKey(name) ? new Handle(name) : null;
- }
- }
-
- public void clear() {
- synchronized (mSysProps) {
- mSysProps.clear();
- }
- }
-
- public class Handle {
- private final String mName;
-
- Handle(String name) {
- mName = name;
- }
-
- public long getLong(long defaultValue) {
- return get(mName, defaultValue);
- }
- }
- }
-}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 3828a71d7b28..4ab8e6abbbef 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -70,7 +70,6 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.Uri;
-import android.net.vcn.Flags;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
@@ -293,8 +292,6 @@ public class VcnManagementServiceTest {
doReturn(Collections.singleton(TRANSPORT_WIFI))
.when(mMockDeps)
.getRestrictedTransports(any(), any(), any());
-
- mSetFlagsRule.enableFlags(Flags.FLAG_FIX_CONFIG_GARBAGE_COLLECTION);
}
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 1bef5f8b17f6..1d4adc4a57d8 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -207,14 +207,13 @@ static ResourceTable::CollisionResult MergeConfigValue(
Value* dst_value = dst_config_value->value.get();
Value* src_value = src_config_value->value.get();
- CollisionResult collision_result;
- if (overlay) {
- collision_result =
- ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool);
- } else {
- collision_result =
- ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus());
- if (collision_result == CollisionResult::kConflict) {
+ CollisionResult collision_result =
+ ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus());
+ if (collision_result == CollisionResult::kConflict) {
+ if (overlay) {
+ collision_result =
+ ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool);
+ } else {
collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value);
}
}
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 40ff5b633d97..03da460affb5 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -111,8 +111,8 @@ const char* GetToolName();
// Retrieves the build fingerprint of aapt2.
std::string GetToolFingerprint();
-template <typename T>
-typename std::enable_if<std::is_arithmetic<T>::value, int>::type compare(const T& a, const T& b) {
+template <std::integral T>
+int compare(T a, T b) {
if (a < b) {
return -1;
} else if (a > b) {
@@ -123,10 +123,7 @@ typename std::enable_if<std::is_arithmetic<T>::value, int>::type compare(const T
// Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
// This will be present in C++14 and can be removed then.
-template <typename T, class... Args>
-std::unique_ptr<T> make_unique(Args&&... args) {
- return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
-}
+using std::make_unique;
// Writes a set of items to the std::ostream, joining the times with the provided separator.
template <typename Container>
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 108942ee754a..9222ff4bf52c 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -16,6 +16,7 @@
package com.android.protolog.tool
+import com.android.internal.protolog.common.IProtoLog
import com.android.internal.protolog.common.LogLevel
import com.android.internal.protolog.common.ProtoLogToolInjected
import com.android.protolog.tool.CommandOptions.Companion.USAGE
@@ -319,6 +320,7 @@ object ProtoLogTool {
MethodCallExpr()
.setName("isEnabled")
.setArguments(NodeList(
+ NameExpr("protoLogInstance"),
FieldAccessExpr()
.setScope(NameExpr(protoLogGroupsClassName))
.setName(group.value.name),
@@ -332,6 +334,7 @@ object ProtoLogTool {
}
cacheClass.addMethod("update").setPrivate(true).setStatic(true)
+ .addParameter(IProtoLog::class.java, "protoLogInstance")
.setBody(updateBlockStmt)
classDeclaration.addMember(cacheClass)
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index f68ae2c7e249..74a907f8ae22 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -309,7 +309,7 @@ public class SharedConnectivityManager {
*/
@TestApi
@NonNull
- @FlaggedApi("com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api")
+ @SuppressLint("UnflaggedApi") // Exempt: Test API for already shipped feature
public BroadcastReceiver getBroadcastReceiver() {
return mBroadcastReceiver;
}